An atproto PDS written in Go
at v0.7.2 2.9 kB view raw
1package server 2 3import ( 4 "context" 5 "strings" 6 "time" 7 8 "github.com/Azure/go-autorest/autorest/to" 9 "github.com/bluesky-social/indigo/api/atproto" 10 "github.com/bluesky-social/indigo/atproto/atcrypto" 11 "github.com/bluesky-social/indigo/events" 12 "github.com/bluesky-social/indigo/util" 13 "github.com/haileyok/cocoon/identity" 14 "github.com/haileyok/cocoon/internal/helpers" 15 "github.com/haileyok/cocoon/models" 16 "github.com/haileyok/cocoon/plc" 17 "github.com/labstack/echo/v4" 18) 19 20type ComAtprotoIdentityUpdateHandleRequest struct { 21 Handle string `json:"handle" validate:"atproto-handle"` 22} 23 24func (s *Server) handleIdentityUpdateHandle(e echo.Context) error { 25 logger := s.logger.With("name", "handleIdentityUpdateHandle") 26 27 repo := e.Get("repo").(*models.RepoActor) 28 29 var req ComAtprotoIdentityUpdateHandleRequest 30 if err := e.Bind(&req); err != nil { 31 logger.Error("error binding", "error", err) 32 return helpers.ServerError(e, nil) 33 } 34 35 req.Handle = strings.ToLower(req.Handle) 36 37 if err := e.Validate(req); err != nil { 38 return helpers.InputError(e, nil) 39 } 40 41 ctx := context.WithValue(e.Request().Context(), "skip-cache", true) 42 43 if strings.HasPrefix(repo.Repo.Did, "did:plc:") { 44 log, err := identity.FetchDidAuditLog(ctx, nil, repo.Repo.Did) 45 if err != nil { 46 logger.Error("error fetching doc", "error", err) 47 return helpers.ServerError(e, nil) 48 } 49 50 latest := log[len(log)-1] 51 52 var newAka []string 53 for _, aka := range latest.Operation.AlsoKnownAs { 54 if aka == "at://"+repo.Handle { 55 continue 56 } 57 newAka = append(newAka, aka) 58 } 59 60 newAka = append(newAka, "at://"+req.Handle) 61 62 op := plc.Operation{ 63 Type: "plc_operation", 64 VerificationMethods: latest.Operation.VerificationMethods, 65 RotationKeys: latest.Operation.RotationKeys, 66 AlsoKnownAs: newAka, 67 Services: latest.Operation.Services, 68 Prev: &latest.Cid, 69 } 70 71 k, err := atcrypto.ParsePrivateBytesK256(repo.SigningKey) 72 if err != nil { 73 logger.Error("error parsing signing key", "error", err) 74 return helpers.ServerError(e, nil) 75 } 76 77 if err := s.plcClient.SignOp(k, &op); err != nil { 78 return err 79 } 80 81 if err := s.plcClient.SendOperation(e.Request().Context(), repo.Repo.Did, &op); err != nil { 82 return err 83 } 84 } 85 86 if err := s.passport.BustDoc(context.TODO(), repo.Repo.Did); err != nil { 87 logger.Warn("error busting did doc", "error", err) 88 } 89 90 s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{ 91 RepoIdentity: &atproto.SyncSubscribeRepos_Identity{ 92 Did: repo.Repo.Did, 93 Handle: to.StringPtr(req.Handle), 94 Seq: time.Now().UnixMicro(), // TODO: no 95 Time: time.Now().Format(util.ISO8601), 96 }, 97 }) 98 99 if err := s.db.Exec(ctx, "UPDATE actors SET handle = ? WHERE did = ?", nil, req.Handle, repo.Repo.Did).Error; err != nil { 100 logger.Error("error updating handle in db", "error", err) 101 return helpers.ServerError(e, nil) 102 } 103 104 return nil 105}