forked from
hailey.at/cocoon
Vow, uncensorable PDS written in Go
1package server
2
3import (
4 "context"
5 "net/http"
6 "strings"
7
8 "github.com/bluesky-social/indigo/atproto/atcrypto"
9 "pkg.rbrt.fr/vow/identity"
10 "pkg.rbrt.fr/vow/internal/helpers"
11 "pkg.rbrt.fr/vow/models"
12)
13
14func (s *Server) handleGetRecommendedDidCredentials(w http.ResponseWriter, r *http.Request) {
15 logger := s.logger.With("name", "handleIdentityGetRecommendedDidCredentials")
16
17 repo, _ := getContextValue[*models.RepoActor](r, contextKeyRepo)
18
19 if len(repo.PublicKey) == 0 {
20 helpers.InputError(w, new("no signing key registered for this account"))
21 return
22 }
23
24 pubKey, err := atcrypto.ParsePublicBytesP256(repo.PublicKey)
25 if err != nil {
26 logger.Error("error parsing stored public key", "error", err)
27 helpers.ServerError(w, nil)
28 return
29 }
30
31 // Start with the PDS-generated credentials (verification methods, services,
32 // alsoKnownAs). These are always correct regardless of rotation key state.
33 // CreateDidCredentialsFromPublicKey sets:
34 // - verificationMethods["atproto"] to the passkey's did:key (commit signing)
35 // - verificationMethods["atproto_service"] to the PDS server key (service-auth)
36 creds, err := s.plcClient.CreateDidCredentialsFromPublicKey(pubKey, "", repo.Handle)
37 if err != nil {
38 logger.Error("error creating did credentials", "error", err)
39 helpers.ServerError(w, nil)
40 return
41 }
42
43 // If this is a did:plc identity, fetch the actual rotation keys from the
44 // current PLC document. After supplySigningKey transfers the rotation key
45 // to the user's passkey, the PDS key is no longer authoritative and we
46 // must reflect the real state.
47 if strings.HasPrefix(repo.Repo.Did, "did:plc:") {
48 ctx := context.WithValue(r.Context(), identity.SkipCacheKey, true)
49 auditLog, err := identity.FetchDidAuditLog(ctx, nil, repo.Repo.Did)
50 if err != nil {
51 logger.Warn("error fetching DID audit log for recommended credentials, falling back to PDS defaults", "error", err)
52 // Fall through — the PDS-generated rotation keys are a reasonable
53 // fallback if we can't reach plc.directory.
54 } else {
55 latest := auditLog[len(auditLog)-1]
56 creds.RotationKeys = latest.Operation.RotationKeys
57 }
58 }
59
60 s.writeJSON(w, 200, creds)
61}