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.

feat: atomic account creation

+76 -68
+4
internal/db/db.go
··· 52 52 func (db *DB) Client() *gorm.DB { 53 53 return db.cli 54 54 } 55 + 56 + func (db *DB) Transaction(fc func(tx *gorm.DB) error) error { 57 + return db.cli.Transaction(fc) 58 + }
+26 -27
server/handle_account_signup.go
··· 159 159 return 160 160 } 161 161 162 - urepo := models.Repo{ 163 - Did: did, 164 - CreatedAt: time.Now(), 165 - Email: email, 166 - EmailVerificationCode: new(fmt.Sprintf("%s-%s", helpers.RandomVarchar(6), helpers.RandomVarchar(6))), 167 - Password: string(hashed), 168 - } 169 - 170 - newActor := &models.Actor{ 171 - Did: did, 172 - Handle: handle, 173 - } 174 - 175 - if err := s.db.Create(ctx, &urepo, nil).Error; err != nil { 176 - logger.Error("error inserting repo", "error", err) 177 - fail("Something went wrong. Please try again.") 178 - return 179 - } 180 - 181 - if err := s.db.Create(ctx, newActor, nil).Error; err != nil { 182 - logger.Error("error inserting actor", "error", err) 183 - fail("Something went wrong. Please try again.") 184 - return 185 - } 186 - 187 162 bs := newBlockstoreForRepo(did, s.ipfsAPI) 188 163 189 164 clk := syntax.NewTIDClock(0) ··· 201 176 return 202 177 } 203 178 204 - if err := s.UpdateRepo(ctx, did, root, rev); err != nil { 205 - logger.Error("error updating repo after genesis commit", "error", err) 179 + urepo := models.Repo{ 180 + Did: did, 181 + CreatedAt: time.Now(), 182 + Email: email, 183 + EmailVerificationCode: new(fmt.Sprintf("%s-%s", helpers.RandomVarchar(6), helpers.RandomVarchar(6))), 184 + Password: string(hashed), 185 + Root: root.Bytes(), 186 + Rev: rev, 187 + } 188 + 189 + newActor := &models.Actor{ 190 + Did: did, 191 + Handle: handle, 192 + } 193 + 194 + err = s.db.Transaction(func(tx *gorm.DB) error { 195 + if err := tx.WithContext(ctx).Create(&urepo).Error; err != nil { 196 + return err 197 + } 198 + if err := tx.WithContext(ctx).Create(newActor).Error; err != nil { 199 + return err 200 + } 201 + return nil 202 + }) 203 + if err != nil { 204 + logger.Error("error inserting repo or actor", "error", err) 206 205 fail("Something went wrong. Please try again.") 207 206 return 208 207 }
+46 -41
server/handle_server_create_account.go
··· 185 185 return 186 186 } 187 187 188 - // SigningKey is intentionally left nil — the PDS never stores a private 189 - // key. PublicKey will be populated later when the user calls 190 - // supplySigningKey via the account page. 191 - urepo := models.Repo{ 192 - Did: signupDid, 193 - CreatedAt: time.Now(), 194 - Email: request.Email, 195 - EmailVerificationCode: new(fmt.Sprintf("%s-%s", helpers.RandomVarchar(6), helpers.RandomVarchar(6))), 196 - Password: string(hashed), 197 - } 198 - 199 - if actor == nil { 200 - actor = &models.Actor{ 201 - Did: signupDid, 202 - Handle: request.Handle, 203 - } 204 - 205 - if err := s.db.Create(ctx, &urepo, nil).Error; err != nil { 206 - logger.Error("error inserting new repo", "error", err) 207 - helpers.ServerError(w, nil) 208 - return 209 - } 210 - 211 - if err := s.db.Create(ctx, &actor, nil).Error; err != nil { 212 - logger.Error("error inserting new actor", "error", err) 213 - helpers.ServerError(w, nil) 214 - return 215 - } 216 - } else { 217 - if err := s.db.Save(ctx, &actor, nil).Error; err != nil { 218 - logger.Error("error inserting new actor", "error", err) 219 - helpers.ServerError(w, nil) 220 - return 221 - } 222 - } 223 - 188 + var rootCid []byte 189 + var rev string 224 190 if request.Did == nil || *request.Did == "" { 225 191 bs := newBlockstoreForRepo(signupDid, s.ipfsAPI) 226 192 ··· 233 199 } 234 200 235 201 // Sign the genesis commit with the PDS rotation key. 236 - root, rev, err := commitRepo(ctx, bs, r, s.plcClient.RotationKeyBytes()) 202 + root, rRev, err := commitRepo(ctx, bs, r, s.plcClient.RotationKeyBytes()) 237 203 if err != nil { 238 204 logger.Error("error committing", "error", err) 239 205 helpers.ServerError(w, nil) 240 206 return 241 207 } 208 + rootCid = root.Bytes() 209 + rev = rRev 210 + } 242 211 243 - if err := s.UpdateRepo(ctx, urepo.Did, root, rev); err != nil { 244 - logger.Error("error updating repo after commit", "error", err) 245 - helpers.ServerError(w, nil) 246 - return 212 + // SigningKey is intentionally left nil — the PDS never stores a private 213 + // key. PublicKey will be populated later when the user calls 214 + // supplySigningKey via the account page. 215 + urepo := models.Repo{ 216 + Did: signupDid, 217 + CreatedAt: time.Now(), 218 + Email: request.Email, 219 + EmailVerificationCode: new(fmt.Sprintf("%s-%s", helpers.RandomVarchar(6), helpers.RandomVarchar(6))), 220 + Password: string(hashed), 221 + Root: rootCid, 222 + Rev: rev, 223 + } 224 + 225 + err = s.db.Transaction(func(tx *gorm.DB) error { 226 + if actor == nil { 227 + actor = &models.Actor{ 228 + Did: signupDid, 229 + Handle: request.Handle, 230 + } 231 + if err := tx.WithContext(ctx).Create(&urepo).Error; err != nil { 232 + return err 233 + } 234 + if err := tx.WithContext(ctx).Create(&actor).Error; err != nil { 235 + return err 236 + } 237 + } else { 238 + if err := tx.WithContext(ctx).Create(&urepo).Error; err != nil { 239 + return err 240 + } 241 + if err := tx.WithContext(ctx).Save(&actor).Error; err != nil { 242 + return err 243 + } 247 244 } 245 + return nil 246 + }) 247 + if err != nil { 248 + logger.Error("error inserting new repo/actor", "error", err) 249 + helpers.ServerError(w, nil) 250 + return 251 + } 248 252 253 + if request.Did == nil || *request.Did == "" { 249 254 if err := s.evtman.AddEvent(ctx, &events.XRPCStreamEvent{ 250 255 RepoIdentity: &atproto.SyncSubscribeRepos_Identity{ 251 256 Did: urepo.Did,