Monorepo for Tangled tangled.org

appview: handle non-unique publicKey records #999

open opened by boltless.me targeting master from sl/sqkrqopzkvoo
  • upsert public key to handle record update event
  • don't delete by pair of name and key. delete by name or rkey instead.

Signed-off-by: Seongmin Lee git@boltless.me

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:xasnlahkri4ewmbuzly2rlc5/sh.tangled.repo.pull/3mcsfwwhtyt22
+108 -47
Diff #1
+17 -7
appview/db/pubkeys.go
··· 5 "time" 6 ) 7 8 - func AddPublicKey(e Execer, did, name, key, rkey string) error { 9 _, err := e.Exec( 10 - `insert or ignore into public_keys (did, name, key, rkey) 11 - values (?, ?, ?, ?)`, 12 - did, name, key, rkey) 13 return err 14 } 15 16 - func DeletePublicKey(e Execer, did, name, key string) error { 17 _, err := e.Exec(` 18 delete from public_keys 19 - where did = ? and name = ? and key = ?`, 20 - did, name, key) 21 return err 22 } 23
··· 5 "time" 6 ) 7 8 + func UpsertPublicKey(e Execer, pubKey models.PublicKey) error { 9 _, err := e.Exec( 10 + `insert into public_keys (did, rkey, name, key, created) 11 + values (?, ?, ?, ?, ?) 12 + on conflict(did, rkey) do update set 13 + name = excluded.name, 14 + key = excluded.key, 15 + created = excluded.created`, 16 + pubKey.Did, 17 + pubKey.Rkey, 18 + pubKey.Name, 19 + pubKey.Key, 20 + pubKey.Created.Format(time.RFC3339), 21 + ) 22 return err 23 } 24 25 + // for public_keys with empty rkey 26 + func DeletePublicKeyLegacy(e Execer, did, name string) error { 27 _, err := e.Exec(` 28 delete from public_keys 29 + where did = ? and name = ? and rkey = ''`, 30 + did, name) 31 return err 32 } 33
+13 -3
appview/ingester.go
··· 131 if err != nil { 132 return fmt.Errorf("failed to %s star record: %w", e.Commit.Operation, err) 133 } 134 135 return nil 136 } ··· 164 if err != nil { 165 return fmt.Errorf("failed to %s follow record: %w", e.Commit.Operation, err) 166 } 167 168 return nil 169 } ··· 185 l.Error("invalid record", "err", err) 186 return err 187 } 188 189 - name := record.Name 190 - key := record.Key 191 - err = db.AddPublicKey(i.Db, did, name, key, e.Commit.RKey) 192 case jmodels.CommitOperationDelete: 193 l.Debug("processing delete of pubkey") 194 err = db.DeletePublicKeyByRkey(i.Db, did, e.Commit.RKey) ··· 197 if err != nil { 198 return fmt.Errorf("failed to %s pubkey record: %w", e.Commit.Operation, err) 199 } 200 201 return nil 202 }
··· 131 if err != nil { 132 return fmt.Errorf("failed to %s star record: %w", e.Commit.Operation, err) 133 } 134 + l.Info("processed star", "operation", e.Commit.Operation, "rkey", e.Commit.RKey) 135 136 return nil 137 } ··· 165 if err != nil { 166 return fmt.Errorf("failed to %s follow record: %w", e.Commit.Operation, err) 167 } 168 + l.Info("processed follow", "operation", e.Commit.Operation, "rkey", e.Commit.RKey) 169 170 return nil 171 } ··· 187 l.Error("invalid record", "err", err) 188 return err 189 } 190 + pubKey, err := models.PublicKeyFromRecord(syntax.DID(did), syntax.RecordKey(e.Commit.RKey), record) 191 + if err != nil { 192 + l.Error("invalid record", "err", err) 193 + return err 194 + } 195 + if err := pubKey.Validate(); err != nil { 196 + l.Error("invalid record", "err", err) 197 + return err 198 + } 199 200 + err = db.UpsertPublicKey(i.Db, pubKey) 201 case jmodels.CommitOperationDelete: 202 l.Debug("processing delete of pubkey") 203 err = db.DeletePublicKeyByRkey(i.Db, did, e.Commit.RKey) ··· 206 if err != nil { 207 return fmt.Errorf("failed to %s pubkey record: %w", e.Commit.Operation, err) 208 } 209 + l.Info("processed pubkey", "operation", e.Commit.Operation, "rkey", e.Commit.RKey) 210 211 return nil 212 }
+38
appview/models/pubkey.go
··· 2 3 import ( 4 "encoding/json" 5 "time" 6 ) 7 8 type PublicKey struct { ··· 23 Alias: (*Alias)(&p), 24 }) 25 }
··· 2 3 import ( 4 "encoding/json" 5 + "fmt" 6 "time" 7 + 8 + "github.com/bluesky-social/indigo/atproto/syntax" 9 + "github.com/gliderlabs/ssh" 10 + "tangled.org/core/api/tangled" 11 ) 12 13 type PublicKey struct { ··· 28 Alias: (*Alias)(&p), 29 }) 30 } 31 + 32 + func (p *PublicKey) AsRecord() tangled.PublicKey { 33 + return tangled.PublicKey{ 34 + Name: p.Name, 35 + Key: p.Key, 36 + CreatedAt: p.Created.Format(time.RFC3339), 37 + } 38 + } 39 + 40 + var _ Validator = new(PublicKey) 41 + 42 + func (p *PublicKey) Validate() error { 43 + if _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(p.Key)); err != nil { 44 + return fmt.Errorf("invalid ssh key format: %w", err) 45 + } 46 + 47 + return nil 48 + } 49 + 50 + func PublicKeyFromRecord(did syntax.DID, rkey syntax.RecordKey, record tangled.PublicKey) (PublicKey, error) { 51 + created, err := time.Parse(time.RFC3339, record.CreatedAt) 52 + if err != nil { 53 + return PublicKey{}, fmt.Errorf("invalid time format '%s'", record.CreatedAt) 54 + } 55 + 56 + return PublicKey{ 57 + Did: did.String(), 58 + Rkey: rkey.String(), 59 + Name: record.Name, 60 + Key: record.Key, 61 + Created: &created, 62 + }, nil 63 + }
+1 -1
appview/pages/templates/user/settings/fragments/keyListing.html
··· 19 <button 20 class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group" 21 title="Delete key" 22 - hx-delete="/settings/keys?name={{urlquery $key.Name}}&rkey={{urlquery $key.Rkey}}&key={{urlquery $key.Key}}" 23 hx-swap="none" 24 hx-confirm="Are you sure you want to delete the key {{ $key.Name }}?" 25 >
··· 19 <button 20 class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group" 21 title="Delete key" 22 + hx-delete="/settings/keys?name={{urlquery $key.Name}}&rkey={{urlquery $key.Rkey}}" 23 hx-swap="none" 24 hx-confirm="Are you sure you want to delete the key {{ $key.Name }}?" 25 >
+39 -36
appview/settings/settings.go
··· 24 comatproto "github.com/bluesky-social/indigo/api/atproto" 25 "github.com/bluesky-social/indigo/atproto/syntax" 26 lexutil "github.com/bluesky-social/indigo/lex/util" 27 - "github.com/gliderlabs/ssh" 28 "github.com/google/uuid" 29 ) 30 ··· 419 log.Println("unimplemented") 420 return 421 case http.MethodPut: 422 - did := s.OAuth.GetDid(r) 423 - key := r.FormValue("key") 424 - key = strings.TrimSpace(key) 425 - name := r.FormValue("name") 426 - client, err := s.OAuth.AuthorizedClient(r) 427 - if err != nil { 428 - s.Pages.Notice(w, "settings-keys", "Failed to authorize. Try again later.") 429 - return 430 } 431 432 - _, _, _, _, err = ssh.ParseAuthorizedKey([]byte(key)) 433 - if err != nil { 434 log.Printf("parsing public key: %s", err) 435 s.Pages.Notice(w, "settings-keys", "That doesn't look like a valid public key. Make sure it's a <strong>public</strong> key.") 436 return 437 } 438 439 - rkey := tid.TID() 440 - 441 tx, err := s.Db.Begin() 442 if err != nil { 443 log.Printf("failed to start tx; adding public key: %s", err) ··· 446 } 447 defer tx.Rollback() 448 449 - if err := db.AddPublicKey(tx, did, name, key, rkey); err != nil { 450 log.Printf("adding public key: %s", err) 451 s.Pages.Notice(w, "settings-keys", "Failed to add public key.") 452 return 453 } 454 455 // store in pds too 456 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 457 Collection: tangled.PublicKeyNSID, 458 - Repo: did, 459 - Rkey: rkey, 460 Record: &lexutil.LexiconTypeDecoder{ 461 - Val: &tangled.PublicKey{ 462 - CreatedAt: time.Now().Format(time.RFC3339), 463 - Key: key, 464 - Name: name, 465 - }}, 466 }) 467 // invalid record 468 if err != nil { ··· 489 490 name := q.Get("name") 491 rkey := q.Get("rkey") 492 - key := q.Get("key") 493 494 log.Println(name) 495 log.Println(rkey) 496 - log.Println(key) 497 498 - client, err := s.OAuth.AuthorizedClient(r) 499 - if err != nil { 500 - log.Printf("failed to authorize client: %s", err) 501 - s.Pages.Notice(w, "settings-keys", "Failed to authorize client.") 502 - return 503 - } 504 505 - if err := db.DeletePublicKey(s.Db, did, name, key); err != nil { 506 - log.Printf("removing public key: %s", err) 507 - s.Pages.Notice(w, "settings-keys", "Failed to remove public key.") 508 - return 509 - } 510 511 - if rkey != "" { 512 // remove from pds too 513 - _, err := comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{ 514 Collection: tangled.PublicKeyNSID, 515 Repo: did, 516 Rkey: rkey,
··· 24 comatproto "github.com/bluesky-social/indigo/api/atproto" 25 "github.com/bluesky-social/indigo/atproto/syntax" 26 lexutil "github.com/bluesky-social/indigo/lex/util" 27 "github.com/google/uuid" 28 ) 29 ··· 418 log.Println("unimplemented") 419 return 420 case http.MethodPut: 421 + created := time.Now() 422 + pubKey := models.PublicKey{ 423 + Did: s.OAuth.GetDid(r), 424 + Rkey: tid.TID(), 425 + Name: r.FormValue("name"), 426 + Key: strings.TrimSpace(r.FormValue("key")), 427 + Created: &created, 428 } 429 430 + if err := pubKey.Validate(); err != nil { 431 log.Printf("parsing public key: %s", err) 432 s.Pages.Notice(w, "settings-keys", "That doesn't look like a valid public key. Make sure it's a <strong>public</strong> key.") 433 return 434 } 435 436 tx, err := s.Db.Begin() 437 if err != nil { 438 log.Printf("failed to start tx; adding public key: %s", err) ··· 441 } 442 defer tx.Rollback() 443 444 + if err = db.UpsertPublicKey(s.Db, pubKey); err != nil { 445 log.Printf("adding public key: %s", err) 446 s.Pages.Notice(w, "settings-keys", "Failed to add public key.") 447 return 448 } 449 450 + client, err := s.OAuth.AuthorizedClient(r) 451 + if err != nil { 452 + s.Pages.Notice(w, "settings-keys", "Failed to authorize. Try again later.") 453 + return 454 + } 455 + 456 // store in pds too 457 + record := pubKey.AsRecord() 458 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 459 Collection: tangled.PublicKeyNSID, 460 + Repo: pubKey.Did, 461 + Rkey: pubKey.Rkey, 462 Record: &lexutil.LexiconTypeDecoder{ 463 + Val: &record, 464 + }, 465 }) 466 // invalid record 467 if err != nil { ··· 488 489 name := q.Get("name") 490 rkey := q.Get("rkey") 491 492 log.Println(name) 493 log.Println(rkey) 494 495 + if rkey == "" { 496 + if err := db.DeletePublicKeyLegacy(s.Db, did, name); err != nil { 497 + log.Printf("removing public key: %s", err) 498 + s.Pages.Notice(w, "settings-keys", "Failed to remove public key.") 499 + return 500 + } 501 + } else { 502 + if err := db.DeletePublicKeyByRkey(s.Db, did, rkey); err != nil { 503 + log.Printf("removing public key: %s", err) 504 + s.Pages.Notice(w, "settings-keys", "Failed to remove public key.") 505 + return 506 + } 507 508 + client, err := s.OAuth.AuthorizedClient(r) 509 + if err != nil { 510 + log.Printf("failed to authorize client: %s", err) 511 + s.Pages.Notice(w, "settings-keys", "Failed to authorize client.") 512 + return 513 + } 514 515 // remove from pds too 516 + _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{ 517 Collection: tangled.PublicKeyNSID, 518 Repo: did, 519 Rkey: rkey,

History

2 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
appview: handle non-unique publicKey records
1/3 failed, 2/3 success
expand
no conflicts, ready to merge
expand 0 comments
1 commit
expand
appview: handle non-unique publicKey records
3/3 success
expand
expand 0 comments