An atproto PDS written in Go
103
fork

Configure Feed

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

at 11920453a6fb7d1e1fe614ce3331916638c5af96 89 lines 2.5 kB view raw
1package server 2 3import ( 4 "context" 5 "slices" 6 "strings" 7 "time" 8 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/internal/helpers" 14 "github.com/haileyok/cocoon/models" 15 "github.com/haileyok/cocoon/plc" 16 "github.com/labstack/echo/v4" 17) 18 19type ComAtprotoSubmitPlcOperationRequest struct { 20 Operation plc.Operation `json:"operation"` 21} 22 23func (s *Server) handleSubmitPlcOperation(e echo.Context) error { 24 logger := s.logger.With("name", "handleIdentitySubmitPlcOperation") 25 26 repo := e.Get("repo").(*models.RepoActor) 27 28 var req ComAtprotoSubmitPlcOperationRequest 29 if err := e.Bind(&req); err != nil { 30 logger.Error("error binding", "error", err) 31 return helpers.ServerError(e, nil) 32 } 33 34 if err := e.Validate(req); err != nil { 35 return helpers.InputError(e, nil) 36 } 37 if !strings.HasPrefix(repo.Repo.Did, "did:plc:") { 38 return helpers.InputError(e, nil) 39 } 40 41 op := req.Operation 42 43 k, err := atcrypto.ParsePrivateBytesK256(repo.SigningKey) 44 if err != nil { 45 logger.Error("error parsing key", "error", err) 46 return helpers.ServerError(e, nil) 47 } 48 required, err := s.plcClient.CreateDidCredentials(k, "", repo.Actor.Handle) 49 if err != nil { 50 logger.Error("error crating did credentials", "error", err) 51 return helpers.ServerError(e, nil) 52 } 53 54 for _, expectedKey := range required.RotationKeys { 55 if !slices.Contains(op.RotationKeys, expectedKey) { 56 return helpers.InputError(e, nil) 57 } 58 } 59 if op.Services["atproto_pds"].Type != "AtprotoPersonalDataServer" { 60 return helpers.InputError(e, nil) 61 } 62 if op.Services["atproto_pds"].Endpoint != required.Services["atproto_pds"].Endpoint { 63 return helpers.InputError(e, nil) 64 } 65 if op.VerificationMethods["atproto"] != required.VerificationMethods["atproto"] { 66 return helpers.InputError(e, nil) 67 } 68 if op.AlsoKnownAs[0] != required.AlsoKnownAs[0] { 69 return helpers.InputError(e, nil) 70 } 71 72 if err := s.plcClient.SendOperation(e.Request().Context(), repo.Repo.Did, &op); err != nil { 73 return err 74 } 75 76 if err := s.passport.BustDoc(context.TODO(), repo.Repo.Did); err != nil { 77 logger.Warn("error busting did doc", "error", err) 78 } 79 80 s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{ 81 RepoIdentity: &atproto.SyncSubscribeRepos_Identity{ 82 Did: repo.Repo.Did, 83 Seq: time.Now().UnixMicro(), // TODO: no 84 Time: time.Now().Format(util.ISO8601), 85 }, 86 }) 87 88 return nil 89}