Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
Download tar.gz
Critical fixes:
- C1: Remove crypto error detail from client response (opaques security oracle)
Changed: 'invalid signed genesis op: {e}' → 'signed genesis op is invalid'
Server-side logging still captures full error detail
Important fixes:
- I1: Replace unwrap_or_default() on service_endpoint with proper error handling
Prevents silent DID document with empty serviceEndpoint
Returns 500 if service endpoint is missing in verified op
- I2: Handle UNIQUE constraint violation on INSERT accounts as 409 not 500
Added is_unique_violation() helper to detect constraint violations
Returns 409 DID_ALREADY_EXISTS instead of 500 INTERNAL_ERROR
- I3: Check rows_affected() on UPDATE pending_accounts SET pending_did
Detects if pending_accounts row vanished during pre-store phase
Returns error if zero rows affected (race condition detection)
- I4: Add explicit emptiness checks for rotation_keys and also_known_as arrays
Checks array is non-empty BEFORE calling first()
Returns specific error for empty arrays vs. element mismatch
Test coverage:
- G2: Add test for retry with mismatched pending_did (tampered retry)
Verifies that DID mismatch returns 500 INTERNAL_ERROR
- G3: Add device row deletion assertion to happy_path test
Verifies devices table cleanup during account promotion
- G4: Add test for malformed rotationKeyPublic format
Verifies format validation (must start with 'did:key:z')
Returns 400 INVALID_CLAIM with valid session token
Note: G5 (expired session coverage) already exists in auth.rs
(pending_session_expired_session_returns_401 test at line 321)
All tests pass: 274 total tests
No clippy warnings, cargo fmt clean
Critical:
- [C2] Validate prev=null and op_type="plc_operation" in verify_genesis_op
immediately after parsing, rejecting rotation ops and non-genesis types.
Prevents clients from submitting rotation ops that bypass plc.directory
validation, which would leave accounts stuck.
Important:
- [I5] Document rotation_key caller obligation in verify_genesis_op docstring:
"The caller is responsible for verifying that the provided key appears in
the op's rotationKeys array; this function only checks that the signature
was made by that key."
Type Design:
- [T1] Apply #[non_exhaustive] to VerifiedGenesisOp to prevent struct-literal
construction outside plc.rs module. Ensures construction only via
verify_genesis_op.
- [T2] Apply #[non_exhaustive] to PlcGenesisOp to prevent struct-literal
construction outside plc.rs module. Ensures construction only via
build_did_plc_genesis_op.
- [T3] Promote P256_MULTICODEC_PREFIX to pub(crate) in keys.rs and import
in plc.rs. Eliminates silent divergence risk between two copies of the
same constant.
- [T4] Improve rotation_key parameter docstring in verify_genesis_op to
clarify its purpose: "The key that must have signed the unsigned operation
— the caller determines which of the op's rotation keys to verify against."
Tests:
- [G1] Add verify_rotation_op_with_non_null_prev_returns_error test
covering prev != null rejection.
- [G1] Add verify_non_genesis_op_type_returns_error test covering non-
"plc_operation" type rejection.
- [G1] Add verify_rotation_key_can_verify_own_op test for canonical usage
pattern where the same keypair both signs and appears at rotationKeys[0].
This was missing coverage — prior tests verified with signing_key only.
Add verify_genesis_op and VerifiedGenesisOp to crypto CLAUDE.md
contracts. Update root CLAUDE.md crypto description to mention
verification.
- Fixed alignment of trailing comments in function call arguments
- Normalized spacing after commas (removed excessive space for alignment)
- Reformatted multi-line assert! macro calls for consistency
- Improved line wrapping for method chains and struct literals
All formatting violations (approx. 18) in the test module have been resolved.
Replaces entire #[cfg(test)] mod tests block in crates/relay/src/routes/create_did.rs.
Changes:
- Remove TEST_MASTER_KEY constant (not needed for device-signed ceremony)
- Remove relay_signing_key insertion from insert_test_data
- Add make_signed_op() helper using crypto::build_did_plc_genesis_op
- Simplify TestSetup struct (remove signing_key_id, rotation_key_id)
- Simplify test_state_for_did (no signing_key_master_key manipulation)
- Update create_did_request to use new MM-90 request shape (rotationKeyPublic, signedCreationOp)
Replaces 7 MM-89 test functions with 9 MM-90 test functions:
✓ happy_path_promotes_account_and_returns_did (AC2.1/2.2/2.3/2.4/2.5/4.1/4.2/4.3)
✓ retry_with_pending_did_skips_plc_directory (AC2.6)
✓ invalid_signature_returns_400 (AC3.1)
✓ wrong_handle_in_op_returns_400 (AC3.2)
✓ wrong_service_endpoint_returns_400 (AC3.3)
✓ wrong_rotation_key_in_op_returns_400 (AC3.4)
✓ already_promoted_account_returns_409 (AC3.5)
✓ missing_auth_returns_401 (AC3.6)
✓ plc_directory_error_returns_502 (AC3.7)
All 185 relay tests pass. All workspace tests pass. Clippy: 0 warnings.