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.

refactor: simplify pds signing handling

+21 -54
-11
plc/client.go
··· 139 139 return &creds, nil 140 140 } 141 141 142 - // RotationDIDKey returns the PDS rotation key as a did:key string. This is 143 - // used to check whether the PDS still has authority over a DID by comparing 144 - // against the rotationKeys list in the current PLC document. 145 - func (c *Client) RotationDIDKey() string { 146 - pub, err := c.rotationKey.PublicKey() 147 - if err != nil { 148 - return "" 149 - } 150 - return pub.DIDKey() 151 - } 152 - 153 142 // RotationKeyBytes returns the raw bytes of the PDS rotation key. This allows 154 143 // callers to use the rotation key to sign genesis commits instead of 155 144 // generating a throwaway ephemeral key.
+4 -12
server/handle_identity_update_handle.go
··· 5 5 "encoding/base64" 6 6 "encoding/json" 7 7 "net/http" 8 - "slices" 9 8 "strings" 10 9 "time" 11 10 ··· 73 72 Prev: &latest.Cid, 74 73 } 75 74 76 - // Determine whether the PDS rotation key still has authority over 77 - // this DID. After supplySigningKey transfers the rotation key to the 78 - // user's passkey, the PDS key is no longer in the rotation key list 79 - // and cannot sign PLC operations. 80 - pdsRotationDIDKey := s.plcClient.RotationDIDKey() 81 - pdsCanSign := slices.Contains(latest.Operation.RotationKeys, pdsRotationDIDKey) 82 - 83 - if pdsCanSign { 75 + // If no passkey is registered yet, PDS signs. Otherwise, the user's 76 + // passkey signs (it is the rotation key in Vow's model). 77 + if len(repo.PublicKey) == 0 { 84 78 // PDS still holds authority — sign directly. 85 79 if err := s.plcClient.SignOp(&op); err != nil { 86 80 logger.Error("error signing PLC operation with rotation key", "error", err) ··· 88 82 return 89 83 } 90 84 } else { 91 - // Rotation key belongs to the user's passkey. Delegate the 92 - // signing to the signer over WebSocket, same as 93 - // handleSignPlcOperation does for other PLC operations. 85 + // User has registered a passkey. Request signature via SignerHub. 94 86 opCBOR, err := op.MarshalCBOR() 95 87 if err != nil { 96 88 logger.Error("error marshalling PLC op to CBOR", "error", err)
+17 -31
server/handle_server_supply_signing_key.go
··· 6 6 "encoding/json" 7 7 "maps" 8 8 "net/http" 9 - "slices" 10 9 "strings" 11 10 "time" 12 11 ··· 30 29 // AttestationObject is the base64url-encoded attestationObject CBOR from 31 30 // the AuthenticatorAttestationResponse. 32 31 AttestationObject string `json:"attestationObject" validate:"required"` 33 - // RotationKeys, if provided, sets the rotation keys for the PLC operation. 34 - // When recreating a passkey, the client must include the current rotation 35 - // keys from the signed PLC operation returned by signPlcOperation. 36 - RotationKeys []string `json:"rotationKeys"` 37 32 } 38 33 39 34 type SupplySigningKeyResponse struct { 40 - Did string `json:"did"` 41 - PublicKey string `json:"publicKey"` // did:key for atproto (commit signing, passkey) 42 - ServiceKey string `json:"serviceKey"` // did:key for atproto_service (service-auth, PDS server key) 43 - CredentialID string `json:"credentialId"` // base64url credential ID 44 - RotationKeys []string `json:"rotationKeys"` // new rotation keys after the operation 35 + Did string `json:"did"` 36 + PublicKey string `json:"publicKey"` // did:key for atproto (commit signing, passkey) 37 + ServiceKey string `json:"serviceKey"` // did:key for atproto_service (service-auth, PDS server key) 38 + CredentialID string `json:"credentialId"` // base64url credential ID 39 + RotationKeys []string `json:"rotationKeys"` // new rotation keys after the operation 45 40 SignedOperation *plc.Operation `json:"signedOperation,omitempty"` // signed PLC operation (when passkey signs) 46 41 } 47 42 ··· 141 136 // signed by this key; others fall back to #atproto (known limitation). 142 137 newVerificationMethods["atproto_service"] = pdsDIDKey 143 138 144 - // Determine whether the PDS rotation key still has authority over 145 - // this DID. After the first passkey registration, the rotation key 146 - // belongs to the user's passkey and the PDS can no longer sign. 147 - pdsRotationDIDKey := s.plcClient.RotationDIDKey() 148 - pdsCanSign := slices.Contains(latest.Operation.RotationKeys, pdsRotationDIDKey) 149 - 150 - // Use client-provided rotation keys when recreating passkey (PDS can't sign), 151 - // otherwise replace the PDS rotation key with the passkey's did:key. 152 - if !pdsCanSign && len(req.RotationKeys) > 0 { 153 - newRotationKeys = req.RotationKeys 154 - } else { 155 - newRotationKeys = []string{pubDIDKey} 156 - } 139 + // The passkey becomes the rotation key. In Vow's model, the signing key 140 + // and rotation key are the same - the user's passkey controls both. 141 + newRotationKeys = []string{pubDIDKey} 157 142 158 143 op := plc.Operation{ 159 144 Type: "plc_operation", ··· 164 149 Prev: &latest.Cid, 165 150 } 166 151 167 - if pdsCanSign { 152 + // If no passkey is registered yet, PDS signs (initial registration). 153 + // Otherwise, the existing passkey signs (passkey rotation). 154 + if len(repo.PublicKey) == 0 { 168 155 // PDS still holds authority — sign directly. This is the last 169 156 // PLC operation the PDS will ever be able to sign on behalf of the 170 157 // user. It is voluntarily handing over control to the passkey. ··· 174 161 return 175 162 } 176 163 } else { 177 - // Rotation key belongs to the user's existing passkey. Request 178 - // signature via SignerHub, same as handleIdentityUpdateHandle. 164 + // Passkey already registered. Request signature via SignerHub. 179 165 opCBOR, err := op.MarshalCBOR() 180 166 if err != nil { 181 167 logger.Error("error marshalling PLC op to CBOR", "error", err) ··· 246 232 247 233 s.writeJSON(w, 200, SupplySigningKeyResponse{ 248 234 Did: repo.Repo.Did, 249 - PublicKey: pubDIDKey, 250 - ServiceKey: pdsDIDKey, 251 - CredentialID: base64.RawURLEncoding.EncodeToString(credentialID), 252 - RotationKeys: newRotationKeys, 253 - SignedOperation: signedOp, 235 + PublicKey: pubDIDKey, 236 + ServiceKey: pdsDIDKey, 237 + CredentialID: base64.RawURLEncoding.EncodeToString(credentialID), 238 + RotationKeys: newRotationKeys, 239 + SignedOperation: signedOp, 254 240 }) 255 241 }