tangled
alpha
login
or
join now
willdot.net
/
tangled-fork
forked from
tangled.org/core
0
fork
atom
Monorepo for Tangled
0
fork
atom
overview
issues
pulls
pipelines
POC: create repos
oppi.li
1 year ago
18ab0d69
92fc5459
+130
-38
7 changed files
expand all
collapse all
unified
split
appview
db
db.go
pubkeys.go
pages
login.html
new-repo.html
pages.go
timeline.html
state
state.go
-2
appview/db/db.go
···
177
177
return "", err
178
178
}
179
179
180
180
-
log.Println("domain, secret: ", domain, secret)
181
181
-
182
180
return secret, nil
183
181
}
184
182
+20
-6
appview/db/pubkeys.go
···
1
1
package db
2
2
3
3
-
import "time"
3
3
+
import (
4
4
+
"encoding/json"
5
5
+
"time"
6
6
+
)
4
7
5
8
func (d *DB) AddPublicKey(did, name, key string) error {
6
9
query := `insert into public_keys (did, name, key) values (?, ?, ?)`
···
15
18
}
16
19
17
20
type PublicKey struct {
18
18
-
Key string
19
19
-
Name string
20
20
-
DID string
21
21
+
Did string `json:"did"`
22
22
+
Key string `json:"key"`
23
23
+
Name string `json:"name"`
21
24
Created time.Time
22
25
}
23
26
27
27
+
func (p PublicKey) MarshalJSON() ([]byte, error) {
28
28
+
type Alias PublicKey
29
29
+
return json.Marshal(&struct {
30
30
+
Created int64 `json:"created"`
31
31
+
*Alias
32
32
+
}{
33
33
+
Created: p.Created.Unix(),
34
34
+
Alias: (*Alias)(&p),
35
35
+
})
36
36
+
}
37
37
+
24
38
func (d *DB) GetAllPublicKeys() ([]PublicKey, error) {
25
39
var keys []PublicKey
26
40
···
33
47
for rows.Next() {
34
48
var publicKey PublicKey
35
49
var createdAt *int64
36
36
-
if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.DID, &createdAt); err != nil {
50
50
+
if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.Did, &createdAt); err != nil {
37
51
return nil, err
38
52
}
39
53
publicKey.Created = time.Unix(*createdAt, 0)
···
59
73
for rows.Next() {
60
74
var publicKey PublicKey
61
75
var createdAt *int64
62
62
-
if err := rows.Scan(&publicKey.DID, &publicKey.Key, &publicKey.Name, &createdAt); err != nil {
76
76
+
if err := rows.Scan(&publicKey.Did, &publicKey.Key, &publicKey.Name, &createdAt); err != nil {
63
77
return nil, err
64
78
}
65
79
publicKey.Created = time.Unix(*createdAt, 0)
+1
-1
appview/pages/login.html
···
1
1
{{define "title"}}login{{end}}
2
2
3
3
{{define "content"}}
4
4
-
<h1>Login</h1>
4
4
+
<h1>login</h1>
5
5
<form method="POST" action="/login">
6
6
<label for="handle">handle</label>
7
7
<input type="text" id="handle" name="handle" required>
+15
appview/pages/new-repo.html
···
1
1
+
{{define "title"}}new repo{{end}}
2
2
+
3
3
+
{{define "content"}}
4
4
+
<h1>new repo</h1>
5
5
+
<form method="POST" action="/repo/new">
6
6
+
<label for="name">repo name</label>
7
7
+
<input type="text" id="name" name="name" required>
8
8
+
9
9
+
<label for="domain">domain</label>
10
10
+
<input type="domain" id="domain" name="domain" required>
11
11
+
12
12
+
<button type="submit">create repo</button>
13
13
+
</form>
14
14
+
{{end}}
15
15
+
+8
appview/pages/pages.go
···
77
77
func Knot(w io.Writer, p KnotParams) error {
78
78
return parse("knot.html").Execute(w, p)
79
79
}
80
80
+
81
81
+
type NewRepoParams struct {
82
82
+
User *auth.User
83
83
+
}
84
84
+
85
85
+
func NewRepo(w io.Writer, p NewRepoParams) error {
86
86
+
return parse("new-repo.html").Execute(w, p)
87
87
+
}
+1
appview/pages/timeline.html
···
7
7
<p>logged in as {{ .User.Handle }}</p>
8
8
<a href="/settings">settings</a>
9
9
<a href="/knots">knots</a>
10
10
+
<a href="/repo/new">add repos</a>
10
11
{{ else }}
11
12
<p>not logged in</p>
12
13
<a href="/login">login</a>
+85
-29
appview/state/state.go
···
1
1
package state
2
2
3
3
import (
4
4
+
"bytes"
4
5
"crypto/hmac"
5
6
"crypto/sha256"
6
7
"encoding/hex"
8
8
+
"encoding/json"
7
9
"fmt"
8
10
"log"
9
11
"net/http"
···
194
196
195
197
// create a signed request and check if a node responds to that
196
198
func (s *State) InitKnotServer(w http.ResponseWriter, r *http.Request) {
199
199
+
user := s.auth.GetUser(r)
200
200
+
197
201
domain := chi.URLParam(r, "domain")
198
202
if domain == "" {
199
203
http.Error(w, "malformed url", http.StatusBadRequest)
200
204
return
201
205
}
206
206
+
log.Println("checking ", domain)
202
207
203
203
-
log.Println("checking ", domain)
208
208
+
url := fmt.Sprintf("http://%s/init", domain)
204
209
205
205
-
secret, err := s.db.GetRegistrationKey(domain)
210
210
+
body, _ := json.Marshal(map[string]interface{}{
211
211
+
"did": user.Did,
212
212
+
"keys": []string{},
213
213
+
})
214
214
+
pingRequest, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
206
215
if err != nil {
207
207
-
log.Printf("no key found for domain %s: %s\n", domain, err)
216
216
+
log.Println("failed to build ping request", err)
208
217
return
209
218
}
210
210
-
log.Println("has secret ", secret)
211
219
212
212
-
// make a request do the knotserver with an empty body and above signature
213
213
-
url := fmt.Sprintf("http://%s/health", domain)
214
214
-
215
215
-
pingRequest, err := http.NewRequest("GET", url, nil)
220
220
+
secret, err := s.db.GetRegistrationKey(domain)
216
221
if err != nil {
217
217
-
log.Println("failed to build ping request", err)
222
222
+
log.Printf("no key found for domain %s: %s\n", domain, err)
218
223
return
219
224
}
220
220
-
221
225
client := SignedClient(secret)
222
226
223
227
resp, err := client.Do(pingRequest)
···
227
231
return
228
232
}
229
233
230
230
-
if resp.StatusCode != http.StatusOK {
234
234
+
if resp.StatusCode == http.StatusConflict {
235
235
+
log.Println("status conflict", resp.StatusCode)
236
236
+
w.Write([]byte("already registered, sorry!"))
237
237
+
return
238
238
+
}
239
239
+
240
240
+
if resp.StatusCode != http.StatusNoContent {
231
241
log.Println("status nok", resp.StatusCode)
232
242
w.Write([]byte("no dice"))
233
243
return
···
384
394
w.Write([]byte(fmt.Sprint("added member: ", memberIdent.Handle.String())))
385
395
}
386
396
387
387
-
// list members of domain, requires auth and requires owner status
388
397
func (s *State) RemoveMember(w http.ResponseWriter, r *http.Request) {
389
398
}
390
399
391
391
-
// func buildPingRequest(url, secret string) (*http.Request, error) {
392
392
-
// pingRequest, err := http.NewRequest("GET", url, nil)
393
393
-
// if err != nil {
394
394
-
// return nil, err
395
395
-
// }
396
396
-
//
397
397
-
// timestamp := time.Now().Format(time.RFC3339)
398
398
-
// mac := hmac.New(sha256.New, []byte(secret))
399
399
-
// message := pingRequest.Method + pingRequest.URL.Path + timestamp
400
400
-
// mac.Write([]byte(message))
401
401
-
// signature := hex.EncodeToString(mac.Sum(nil))
402
402
-
//
403
403
-
// pingRequest.Header.Set("X-Signature", signature)
404
404
-
// pingRequest.Header.Set("X-Timestamp", timestamp)
405
405
-
//
406
406
-
// return pingRequest, nil
407
407
-
// }
400
400
+
func (s *State) AddRepo(w http.ResponseWriter, r *http.Request) {
401
401
+
switch r.Method {
402
402
+
case http.MethodGet:
403
403
+
pages.NewRepo(w, pages.NewRepoParams{
404
404
+
User: s.auth.GetUser(r),
405
405
+
})
406
406
+
case http.MethodPost:
407
407
+
user := s.auth.GetUser(r)
408
408
+
409
409
+
domain := r.FormValue("domain")
410
410
+
if domain == "" {
411
411
+
log.Println("invalid form")
412
412
+
return
413
413
+
}
414
414
+
415
415
+
repoName := r.FormValue("name")
416
416
+
if repoName == "" {
417
417
+
log.Println("invalid form")
418
418
+
return
419
419
+
}
420
420
+
421
421
+
ok, err := s.enforcer.E.Enforce(user.Did, domain, domain, "repo:create")
422
422
+
if err != nil || !ok {
423
423
+
w.Write([]byte("domain inaccessible to you"))
424
424
+
return
425
425
+
}
426
426
+
427
427
+
secret, err := s.db.GetRegistrationKey(domain)
428
428
+
if err != nil {
429
429
+
log.Printf("no key found for domain %s: %s\n", domain, err)
430
430
+
return
431
431
+
}
432
432
+
433
433
+
client := SignedClient(secret)
434
434
+
url := fmt.Sprintf("http://%s/repo/new", domain)
435
435
+
body, _ := json.Marshal(map[string]interface{}{
436
436
+
"did": user.Did,
437
437
+
"name": repoName,
438
438
+
})
439
439
+
createRepoRequest, err := http.NewRequest("PUT", url, bytes.NewReader(body))
440
440
+
441
441
+
resp, err := client.Do(createRepoRequest)
442
442
+
443
443
+
if err != nil {
444
444
+
log.Println("failed to send create repo request", err)
445
445
+
return
446
446
+
}
447
447
+
448
448
+
if resp.StatusCode != http.StatusNoContent {
449
449
+
log.Println("server returned ", resp.StatusCode)
450
450
+
return
451
451
+
}
452
452
+
453
453
+
w.Write([]byte("created!"))
454
454
+
}
455
455
+
}
408
456
409
457
func (s *State) Router() http.Handler {
410
458
r := chi.NewRouter()
···
429
477
r.Delete("/", s.RemoveMember)
430
478
})
431
479
})
480
480
+
})
481
481
+
482
482
+
r.Route("/repo", func(r chi.Router) {
483
483
+
r.Route("/new", func(r chi.Router) {
484
484
+
r.Get("/", s.AddRepo)
485
485
+
r.Post("/", s.AddRepo)
486
486
+
})
487
487
+
// r.Post("/import", s.ImportRepo)
432
488
})
433
489
434
490
r.Group(func(r chi.Router) {