BYOK Personal Data Server (PDS) written in Go
ipfs vow atproto pds go
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: swap operations in buildUnsignedCommit and clean up repo fields

+14 -88
+5 -7
models/models.go
··· 17 17 PasswordResetCodeExpiresAt *time.Time 18 18 PlcOperationCode *string 19 19 PlcOperationCodeExpiresAt *time.Time 20 - AccountDeleteCode *string 21 - AccountDeleteCodeExpiresAt *time.Time 22 20 Password string 23 21 // AuthPublicKey holds the compressed P-256 public key bytes for WebAuthn assertion verification. 24 22 AuthPublicKey []byte ··· 29 27 // allowCredentials list when requesting an assertion from the passkey. 30 28 CredentialID []byte 31 29 // CompatMode enables user-side signing of service-auth JWTs. 32 - CompatMode bool 33 - Rev string 34 - Root []byte 35 - Preferences []byte 36 - Deactivated bool 30 + CompatMode bool 31 + Rev string 32 + Root []byte 33 + Preferences []byte 34 + Deactivated bool 37 35 } 38 36 39 37 func (r *Repo) Status() *string {
+2 -71
server/handle_server_delete_account.go
··· 12 12 "github.com/bluesky-social/indigo/api/atproto" 13 13 "github.com/bluesky-social/indigo/events" 14 14 "github.com/bluesky-social/indigo/util" 15 - "golang.org/x/crypto/bcrypt" 16 15 "pkg.rbrt.fr/vow/internal/helpers" 17 16 "pkg.rbrt.fr/vow/models" 18 17 ) ··· 72 71 } 73 72 74 73 // --------------------------------------------------------------------------- 75 - // com.atproto.server.deleteAccount — legacy XRPC endpoint (did + password + token) 74 + // com.atproto.server.deleteAccount — unsupported 76 75 // --------------------------------------------------------------------------- 77 76 78 - type ComAtprotoServerDeleteAccountRequest struct { 79 - Did string `json:"did" validate:"required"` 80 - Password string `json:"password" validate:"required"` 81 - Token string `json:"token" validate:"required"` 82 - } 83 - 84 77 func (s *Server) handleServerDeleteAccount(w http.ResponseWriter, r *http.Request) { 85 - ctx := r.Context() 86 - logger := s.logger.With("name", "handleServerDeleteAccount") 87 - 88 - var req ComAtprotoServerDeleteAccountRequest 89 - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 90 - logger.Error("error decoding", "error", err) 91 - helpers.ServerError(w, nil) 92 - return 93 - } 94 - 95 - if err := s.validator.Struct(&req); err != nil { 96 - logger.Error("error validating", "error", err) 97 - helpers.ServerError(w, nil) 98 - return 99 - } 100 - 101 - urepo, err := s.getRepoActorByDid(ctx, req.Did) 102 - if err != nil { 103 - logger.Error("error getting repo", "error", err) 104 - s.writeJSON(w, http.StatusBadRequest, map[string]string{"error": "account not found"}) 105 - return 106 - } 107 - 108 - if err := bcrypt.CompareHashAndPassword([]byte(urepo.Password), []byte(req.Password)); err != nil { 109 - logger.Error("password mismatch", "error", err) 110 - s.writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "Invalid did or password"}) 111 - return 112 - } 113 - 114 - if urepo.AccountDeleteCode == nil || urepo.AccountDeleteCodeExpiresAt == nil { 115 - logger.Error("no deletion token found for account") 116 - s.writeJSON(w, http.StatusBadRequest, map[string]any{ 117 - "error": "InvalidToken", 118 - "message": "Token is invalid", 119 - }) 120 - return 121 - } 122 - 123 - if *urepo.AccountDeleteCode != req.Token { 124 - logger.Error("deletion token mismatch") 125 - s.writeJSON(w, http.StatusBadRequest, map[string]any{ 126 - "error": "InvalidToken", 127 - "message": "Token is invalid", 128 - }) 129 - return 130 - } 131 - 132 - if time.Now().UTC().After(*urepo.AccountDeleteCodeExpiresAt) { 133 - logger.Error("deletion token expired") 134 - s.writeJSON(w, http.StatusBadRequest, map[string]any{ 135 - "error": "ExpiredToken", 136 - "message": "Token is expired", 137 - }) 138 - return 139 - } 140 - 141 - if err := s.deleteAccountByDid(ctx, req.Did); err != nil { 142 - logger.Error("error deleting account", "error", err) 143 - helpers.ServerError(w, nil) 144 - return 145 - } 146 - 147 - w.WriteHeader(http.StatusOK) 78 + helpers.InputError(w, new("Account deletion not supported here. Login on Vow and delete the account there.")) 148 79 } 149 80 150 81 // ---------------------------------------------------------------------------
+7 -10
server/repo.go
··· 192 192 // require a signing key. The caller must obtain a signature over uc.cbor and 193 193 // then call finaliseCommit. 194 194 func buildUnsignedCommit(ctx context.Context, bs blockstore.Blockstore, r *atp.Repo) (*unsignedCommit, error) { 195 + // Write diff blocks BEFORE calling r.Commit(), because r.Commit() 196 + // traverses the MST and clears the dirty flags, which would cause 197 + // WriteDiffBlocks to do nothing if called afterwards. 198 + if _, err := r.MST.WriteDiffBlocks(ctx, bs.(legacyblockstore.Blockstore)); err != nil { //nolint:staticcheck 199 + return nil, fmt.Errorf("writing MST blocks: %w", err) 200 + } 201 + 195 202 commit, err := r.Commit() 196 203 if err != nil { 197 204 return nil, fmt.Errorf("creating commit: %w", err) 198 - } 199 - 200 - // Stamp the revision on the blockstore before writing any MST blocks so 201 - // that every block carries the correct Rev. 202 - if rs, ok := bs.(revSetter); ok { 203 - rs.SetRev(commit.Rev) 204 - } 205 - 206 - if _, err := r.MST.WriteDiffBlocks(ctx, bs.(legacyblockstore.Blockstore)); err != nil { //nolint:staticcheck 207 - return nil, fmt.Errorf("writing MST blocks: %w", err) 208 205 } 209 206 210 207 buf := new(bytes.Buffer)