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/crypto"
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/labstack/echo/v4"
17)
18
19type ComAtprotoIdentityUpdateHandleRequest struct {
20 Handle string `json:"handle" validate:"atproto-handle"`
21}
22
23func (s *Server) handleIdentityUpdateHandle(e echo.Context) error {
24 repo := e.Get("repo").(*models.RepoActor)
25
26 var req ComAtprotoIdentityUpdateHandleRequest
27 if err := e.Bind(&req); err != nil {
28 s.logger.Error("error binding", "error", err)
29 return helpers.ServerError(e, nil)
30 }
31
32 req.Handle = strings.ToLower(req.Handle)
33
34 if err := e.Validate(req); err != nil {
35 return helpers.InputError(e, nil)
36 }
37
38 ctx := context.WithValue(e.Request().Context(), "skip-cache", true)
39
40 if strings.HasPrefix(repo.Repo.Did, "did:plc:") {
41 log, err := identity.FetchDidAuditLog(ctx, repo.Repo.Did)
42 if err != nil {
43 s.logger.Error("error fetching doc", "error", err)
44 return helpers.ServerError(e, nil)
45 }
46
47 latest := log[len(log)-1]
48
49 k, err := crypto.ParsePrivateBytesK256(repo.SigningKey)
50 if err != nil {
51 s.logger.Error("error parsing signing key", "error", err)
52 return helpers.ServerError(e, nil)
53 }
54
55 op, err := s.plcClient.FormatAndSignAtprotoOp(k, req.Handle, latest.Operation.RotationKeys, &latest.Cid)
56 if err != nil {
57 return err
58 }
59
60 if err := s.plcClient.SendOperation(context.TODO(), repo.Repo.Did, op); err != nil {
61 return err
62 }
63 }
64
65 s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{
66 RepoHandle: &atproto.SyncSubscribeRepos_Handle{
67 Did: repo.Repo.Did,
68 Handle: req.Handle,
69 Seq: time.Now().UnixMicro(), // TODO: no
70 Time: time.Now().Format(util.ISO8601),
71 },
72 })
73
74 s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{
75 RepoIdentity: &atproto.SyncSubscribeRepos_Identity{
76 Did: repo.Repo.Did,
77 Handle: to.StringPtr(req.Handle),
78 Seq: time.Now().UnixMicro(), // TODO: no
79 Time: time.Now().Format(util.ISO8601),
80 },
81 })
82
83 if err := s.db.Exec("UPDATE actors SET handle = ? WHERE did = ?", req.Handle, repo.Repo.Did).Error; err != nil {
84 s.logger.Error("error updating handle in db", "error", err)
85 return helpers.ServerError(e, nil)
86 }
87
88 return nil
89}