this repo has no description

POC: create repos

Akshay 76bb6d31 338f740e

Changed files
+130 -38
appview
-2
appview/db/db.go
··· 177 177 return "", err 178 178 } 179 179 180 - log.Println("domain, secret: ", domain, secret) 181 - 182 180 return secret, nil 183 181 } 184 182
+20 -6
appview/db/pubkeys.go
··· 1 1 package db 2 2 3 - import "time" 3 + import ( 4 + "encoding/json" 5 + "time" 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 - Key string 19 - Name string 20 - DID string 21 + Did string `json:"did"` 22 + Key string `json:"key"` 23 + Name string `json:"name"` 21 24 Created time.Time 22 25 } 23 26 27 + func (p PublicKey) MarshalJSON() ([]byte, error) { 28 + type Alias PublicKey 29 + return json.Marshal(&struct { 30 + Created int64 `json:"created"` 31 + *Alias 32 + }{ 33 + Created: p.Created.Unix(), 34 + Alias: (*Alias)(&p), 35 + }) 36 + } 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 - if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.DID, &createdAt); err != nil { 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 - if err := rows.Scan(&publicKey.DID, &publicKey.Key, &publicKey.Name, &createdAt); err != nil { 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 - <h1>Login</h1> 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 + {{define "title"}}new repo{{end}} 2 + 3 + {{define "content"}} 4 + <h1>new repo</h1> 5 + <form method="POST" action="/repo/new"> 6 + <label for="name">repo name</label> 7 + <input type="text" id="name" name="name" required> 8 + 9 + <label for="domain">domain</label> 10 + <input type="domain" id="domain" name="domain" required> 11 + 12 + <button type="submit">create repo</button> 13 + </form> 14 + {{end}} 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 + 81 + type NewRepoParams struct { 82 + User *auth.User 83 + } 84 + 85 + func NewRepo(w io.Writer, p NewRepoParams) error { 86 + return parse("new-repo.html").Execute(w, p) 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 + <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 + "bytes" 4 5 "crypto/hmac" 5 6 "crypto/sha256" 6 7 "encoding/hex" 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 + user := s.auth.GetUser(r) 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 + log.Println("checking ", domain) 202 207 203 - log.Println("checking ", domain) 208 + url := fmt.Sprintf("http://%s/init", domain) 204 209 205 - secret, err := s.db.GetRegistrationKey(domain) 210 + body, _ := json.Marshal(map[string]interface{}{ 211 + "did": user.Did, 212 + "keys": []string{}, 213 + }) 214 + pingRequest, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) 206 215 if err != nil { 207 - log.Printf("no key found for domain %s: %s\n", domain, err) 216 + log.Println("failed to build ping request", err) 208 217 return 209 218 } 210 - log.Println("has secret ", secret) 211 219 212 - // make a request do the knotserver with an empty body and above signature 213 - url := fmt.Sprintf("http://%s/health", domain) 214 - 215 - pingRequest, err := http.NewRequest("GET", url, nil) 220 + secret, err := s.db.GetRegistrationKey(domain) 216 221 if err != nil { 217 - log.Println("failed to build ping request", err) 222 + log.Printf("no key found for domain %s: %s\n", domain, err) 218 223 return 219 224 } 220 - 221 225 client := SignedClient(secret) 222 226 223 227 resp, err := client.Do(pingRequest) ··· 227 231 return 228 232 } 229 233 230 - if resp.StatusCode != http.StatusOK { 234 + if resp.StatusCode == http.StatusConflict { 235 + log.Println("status conflict", resp.StatusCode) 236 + w.Write([]byte("already registered, sorry!")) 237 + return 238 + } 239 + 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 - // 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 - // func buildPingRequest(url, secret string) (*http.Request, error) { 392 - // pingRequest, err := http.NewRequest("GET", url, nil) 393 - // if err != nil { 394 - // return nil, err 395 - // } 396 - // 397 - // timestamp := time.Now().Format(time.RFC3339) 398 - // mac := hmac.New(sha256.New, []byte(secret)) 399 - // message := pingRequest.Method + pingRequest.URL.Path + timestamp 400 - // mac.Write([]byte(message)) 401 - // signature := hex.EncodeToString(mac.Sum(nil)) 402 - // 403 - // pingRequest.Header.Set("X-Signature", signature) 404 - // pingRequest.Header.Set("X-Timestamp", timestamp) 405 - // 406 - // return pingRequest, nil 407 - // } 400 + func (s *State) AddRepo(w http.ResponseWriter, r *http.Request) { 401 + switch r.Method { 402 + case http.MethodGet: 403 + pages.NewRepo(w, pages.NewRepoParams{ 404 + User: s.auth.GetUser(r), 405 + }) 406 + case http.MethodPost: 407 + user := s.auth.GetUser(r) 408 + 409 + domain := r.FormValue("domain") 410 + if domain == "" { 411 + log.Println("invalid form") 412 + return 413 + } 414 + 415 + repoName := r.FormValue("name") 416 + if repoName == "" { 417 + log.Println("invalid form") 418 + return 419 + } 420 + 421 + ok, err := s.enforcer.E.Enforce(user.Did, domain, domain, "repo:create") 422 + if err != nil || !ok { 423 + w.Write([]byte("domain inaccessible to you")) 424 + return 425 + } 426 + 427 + secret, err := s.db.GetRegistrationKey(domain) 428 + if err != nil { 429 + log.Printf("no key found for domain %s: %s\n", domain, err) 430 + return 431 + } 432 + 433 + client := SignedClient(secret) 434 + url := fmt.Sprintf("http://%s/repo/new", domain) 435 + body, _ := json.Marshal(map[string]interface{}{ 436 + "did": user.Did, 437 + "name": repoName, 438 + }) 439 + createRepoRequest, err := http.NewRequest("PUT", url, bytes.NewReader(body)) 440 + 441 + resp, err := client.Do(createRepoRequest) 442 + 443 + if err != nil { 444 + log.Println("failed to send create repo request", err) 445 + return 446 + } 447 + 448 + if resp.StatusCode != http.StatusNoContent { 449 + log.Println("server returned ", resp.StatusCode) 450 + return 451 + } 452 + 453 + w.Write([]byte("created!")) 454 + } 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 + }) 481 + 482 + r.Route("/repo", func(r chi.Router) { 483 + r.Route("/new", func(r chi.Router) { 484 + r.Get("/", s.AddRepo) 485 + r.Post("/", s.AddRepo) 486 + }) 487 + // r.Post("/import", s.ImportRepo) 432 488 }) 433 489 434 490 r.Group(func(r chi.Router) {