An easy-to-host PDS on the ATProtocol, MacOS. Grandma-approved.

fix: address code review formatting and dead_code issues (MM-89 Phase 2)

- [Critical] Fix formatting in auth.rs (lines 91-128) and create_did.rs
(multiple locations): run cargo fmt --all to auto-format both files
to comply with CI gate requirements.

- [Minor] Remove unnecessary #[allow(dead_code)] from AppState.http_client
field in app.rs line 81. The field is actively used by create_did_handler
at create_did.rs:161 for plc.directory HTTP calls.

authored by malpercio.dev and committed by

Tangled 132ebc34 10b6e096

+122 -97
-1
crates/relay/src/app.rs
··· 78 78 pub struct AppState { 79 79 pub config: Arc<Config>, 80 80 pub db: sqlx::SqlitePool, 81 - #[allow(dead_code)] 82 81 pub http_client: Client, 83 82 } 84 83
+10 -15
crates/relay/src/routes/auth.rs
··· 8 8 /// Information about an authenticated pending session. 9 9 pub struct PendingSessionInfo { 10 10 pub account_id: String, 11 + #[allow(dead_code)] 11 12 pub device_id: String, 12 13 } 13 14 ··· 90 91 91 92 // Decode base64url → raw bytes, then SHA-256 hash → hex string. 92 93 // Matches the storage format written by POST /v1/accounts/mobile. 93 - let token_bytes = URL_SAFE_NO_PAD.decode(token).map_err(|_| { 94 - ApiError::new( 95 - ErrorCode::Unauthorized, 96 - "invalid session token", 97 - ) 98 - })?; 94 + let token_bytes = URL_SAFE_NO_PAD 95 + .decode(token) 96 + .map_err(|_| ApiError::new(ErrorCode::Unauthorized, "invalid session token"))?; 99 97 let token_hash: String = Sha256::digest(&token_bytes) 100 98 .iter() 101 99 .map(|b| format!("{b:02x}")) ··· 111 109 .await 112 110 .map_err(|e| { 113 111 tracing::error!(error = %e, "failed to query pending session"); 114 - ApiError::new( 115 - ErrorCode::InternalError, 116 - "session lookup failed", 117 - ) 112 + ApiError::new(ErrorCode::InternalError, "session lookup failed") 118 113 })?; 119 114 120 115 let (account_id, device_id) = row.ok_or_else(|| { 121 - ApiError::new( 122 - ErrorCode::Unauthorized, 123 - "invalid or expired session token", 124 - ) 116 + ApiError::new(ErrorCode::Unauthorized, "invalid or expired session token") 125 117 })?; 126 118 127 - Ok(PendingSessionInfo { account_id, device_id }) 119 + Ok(PendingSessionInfo { 120 + account_id, 121 + device_id, 122 + }) 128 123 } 129 124 130 125 #[cfg(test)]
+112 -81
crates/relay/src/routes/create_did.rs
··· 56 56 let session = require_pending_session(&headers, &state.db).await?; 57 57 58 58 // Step 2: Load pending account details. 59 - let (handle, pending_did, email): (String, Option<String>, String) = sqlx::query_as( 60 - "SELECT handle, pending_did, email FROM pending_accounts WHERE id = ?", 61 - ) 62 - .bind(&session.account_id) 63 - .fetch_optional(&state.db) 64 - .await 65 - .map_err(|e| { 66 - tracing::error!(error = %e, "failed to query pending account"); 67 - ApiError::new(ErrorCode::InternalError, "failed to load account") 68 - })? 69 - .ok_or_else(|| ApiError::new(ErrorCode::Unauthorized, "account not found"))?; 59 + let (handle, pending_did, email): (String, Option<String>, String) = 60 + sqlx::query_as("SELECT handle, pending_did, email FROM pending_accounts WHERE id = ?") 61 + .bind(&session.account_id) 62 + .fetch_optional(&state.db) 63 + .await 64 + .map_err(|e| { 65 + tracing::error!(error = %e, "failed to query pending account"); 66 + ApiError::new(ErrorCode::InternalError, "failed to load account") 67 + })? 68 + .ok_or_else(|| ApiError::new(ErrorCode::Unauthorized, "account not found"))?; 70 69 71 70 // Step 3: Look up signing key in relay_signing_keys. 72 - let (private_key_encrypted,): (String,) = sqlx::query_as( 73 - "SELECT private_key_encrypted FROM relay_signing_keys WHERE id = ?", 74 - ) 75 - .bind(&payload.signing_key) 76 - .fetch_optional(&state.db) 77 - .await 78 - .map_err(|e| { 79 - tracing::error!(error = %e, "failed to query relay signing key"); 80 - ApiError::new(ErrorCode::InternalError, "key lookup failed") 81 - })? 82 - .ok_or_else(|| { 83 - ApiError::new(ErrorCode::NotFound, "signing key not found in relay_signing_keys") 84 - })?; 71 + let (private_key_encrypted,): (String,) = 72 + sqlx::query_as("SELECT private_key_encrypted FROM relay_signing_keys WHERE id = ?") 73 + .bind(&payload.signing_key) 74 + .fetch_optional(&state.db) 75 + .await 76 + .map_err(|e| { 77 + tracing::error!(error = %e, "failed to query relay signing key"); 78 + ApiError::new(ErrorCode::InternalError, "key lookup failed") 79 + })? 80 + .ok_or_else(|| { 81 + ApiError::new( 82 + ErrorCode::NotFound, 83 + "signing key not found in relay_signing_keys", 84 + ) 85 + })?; 85 86 86 87 // Step 4: Decrypt the private key using the master key from config. 87 88 let master_key: &[u8; 32] = state ··· 90 91 .as_ref() 91 92 .map(|s| &*s.0) 92 93 .ok_or_else(|| { 93 - ApiError::new(ErrorCode::InternalError, "signing key master key not configured") 94 + ApiError::new( 95 + ErrorCode::InternalError, 96 + "signing key master key not configured", 97 + ) 94 98 })?; 95 99 96 100 let private_key_bytes = crypto::decrypt_private_key(&private_key_encrypted, master_key) ··· 112 116 ) 113 117 .map_err(|e| { 114 118 tracing::error!(error = %e, "failed to build genesis op"); 115 - ApiError::new(ErrorCode::InternalError, "failed to build genesis operation") 119 + ApiError::new( 120 + ErrorCode::InternalError, 121 + "failed to build genesis operation", 122 + ) 116 123 })?; 117 124 118 125 let did = genesis.did.clone(); ··· 126 133 true 127 134 } else { 128 135 // First attempt: write the DID before calling plc.directory. 129 - sqlx::query( 130 - "UPDATE pending_accounts SET pending_did = ? WHERE id = ?", 131 - ) 132 - .bind(&did) 133 - .bind(&session.account_id) 134 - .execute(&state.db) 135 - .await 136 - .map_err(|e| { 137 - tracing::error!(error = %e, "failed to pre-store pending_did"); 138 - ApiError::new(ErrorCode::InternalError, "failed to store pending DID") 139 - })?; 136 + sqlx::query("UPDATE pending_accounts SET pending_did = ? WHERE id = ?") 137 + .bind(&did) 138 + .bind(&session.account_id) 139 + .execute(&state.db) 140 + .await 141 + .map_err(|e| { 142 + tracing::error!(error = %e, "failed to pre-store pending_did"); 143 + ApiError::new(ErrorCode::InternalError, "failed to store pending DID") 144 + })?; 140 145 false 141 146 }; 142 147 143 148 // Step 7: Check if the account is already fully promoted (idempotency guard for AC2.10). 144 - let already_promoted: bool = sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM accounts WHERE did = ?)") 145 - .bind(&did) 146 - .fetch_one(&state.db) 147 - .await 148 - .map_err(|e| { 149 - tracing::error!(error = %e, "failed to check accounts existence"); 150 - ApiError::new(ErrorCode::InternalError, "database error") 151 - })?; 149 + let already_promoted: bool = 150 + sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM accounts WHERE did = ?)") 151 + .bind(&did) 152 + .fetch_one(&state.db) 153 + .await 154 + .map_err(|e| { 155 + tracing::error!(error = %e, "failed to check accounts existence"); 156 + ApiError::new(ErrorCode::InternalError, "database error") 157 + })?; 152 158 153 159 if already_promoted { 154 - return Err(ApiError::new(ErrorCode::DidAlreadyExists, "DID is already fully promoted")); 160 + return Err(ApiError::new( 161 + ErrorCode::DidAlreadyExists, 162 + "DID is already fully promoted", 163 + )); 155 164 } 156 165 157 166 // Step 8: POST the genesis operation to plc.directory (skipped on retry). ··· 166 175 .await 167 176 .map_err(|e| { 168 177 tracing::error!(error = %e, plc_url = %plc_url, "failed to contact plc.directory"); 169 - ApiError::new(ErrorCode::PlcDirectoryError, "failed to contact plc.directory") 178 + ApiError::new( 179 + ErrorCode::PlcDirectoryError, 180 + "failed to contact plc.directory", 181 + ) 170 182 })?; 171 183 172 184 if !response.status().is_success() { ··· 180 192 } 181 193 182 194 // Step 9: Build the DID document for local storage. 183 - let did_document = build_did_document(&did, &handle, &payload.signing_key, &state.config.public_url); 195 + let did_document = build_did_document( 196 + &did, 197 + &handle, 198 + &payload.signing_key, 199 + &state.config.public_url, 200 + ); 184 201 185 202 // Step 10: Atomically promote the account. 186 203 let mut tx = state ··· 212 229 .inspect_err(|e| tracing::error!(error = %e, "failed to insert did_document")) 213 230 .map_err(|_| ApiError::new(ErrorCode::InternalError, "failed to store DID document"))?; 214 231 215 - sqlx::query( 216 - "INSERT INTO handles (handle, did, created_at) VALUES (?, ?, datetime('now'))", 217 - ) 218 - .bind(&handle) 219 - .bind(&did) 220 - .execute(&mut *tx) 221 - .await 222 - .inspect_err(|e| tracing::error!(error = %e, "failed to insert handle")) 223 - .map_err(|_| ApiError::new(ErrorCode::InternalError, "failed to register handle"))?; 232 + sqlx::query("INSERT INTO handles (handle, did, created_at) VALUES (?, ?, datetime('now'))") 233 + .bind(&handle) 234 + .bind(&did) 235 + .execute(&mut *tx) 236 + .await 237 + .inspect_err(|e| tracing::error!(error = %e, "failed to insert handle")) 238 + .map_err(|_| ApiError::new(ErrorCode::InternalError, "failed to register handle"))?; 224 239 225 240 sqlx::query("DELETE FROM pending_sessions WHERE account_id = ?") 226 241 .bind(&session.account_id) ··· 248 263 .inspect_err(|e| tracing::error!(error = %e, "failed to commit promotion transaction")) 249 264 .map_err(|_| ApiError::new(ErrorCode::InternalError, "failed to commit transaction"))?; 250 265 251 - Ok(Json(CreateDidResponse { did, status: "active" })) 266 + Ok(Json(CreateDidResponse { 267 + did, 268 + status: "active", 269 + })) 252 270 } 253 271 254 272 /// Construct a minimal DID Core document from known fields. ··· 302 320 use sha2::{Digest, Sha256}; 303 321 use tower::ServiceExt; // for `.oneshot()` 304 322 use uuid::Uuid; 305 - use wiremock::{Mock, MockServer, ResponseTemplate, matchers::{method, path_regex}}; 323 + use wiremock::{ 324 + matchers::{method, path_regex}, 325 + Mock, MockServer, ResponseTemplate, 326 + }; 306 327 307 328 // ── Test setup helpers ──────────────────────────────────────────────────── 308 329 ··· 335 356 let rotation_kp = generate_p256_keypair().expect("rotation keypair"); 336 357 337 358 // Encrypt the signing private key with the test master key. 338 - let encrypted = 339 - encrypt_private_key(&signing_kp.private_key_bytes, &TEST_MASTER_KEY) 340 - .expect("encrypt key"); 359 + let encrypted = encrypt_private_key(&signing_kp.private_key_bytes, &TEST_MASTER_KEY) 360 + .expect("encrypt key"); 341 361 342 362 // Insert relay_signing_key. 343 363 sqlx::query( ··· 489 509 490 510 // AC2.1: 200 OK with did + status 491 511 assert_eq!(response.status(), StatusCode::OK); 492 - let body: serde_json::Value = 493 - serde_json::from_slice(&axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap()).unwrap(); 512 + let body: serde_json::Value = serde_json::from_slice( 513 + &axum::body::to_bytes(response.into_body(), usize::MAX) 514 + .await 515 + .unwrap(), 516 + ) 517 + .unwrap(); 494 518 let did = body["did"].as_str().expect("did field"); 495 - assert!(did.starts_with("did:plc:"), "did should start with did:plc:"); 519 + assert!( 520 + did.starts_with("did:plc:"), 521 + "did should start with did:plc:" 522 + ); 496 523 assert_eq!(body["status"], "active"); 497 524 498 525 // AC2.2: accounts row with null password_hash ··· 506 533 assert!(stored_email.contains("alice"), "email should be set"); 507 534 508 535 // AC2.3: did_documents row with non-empty document 509 - let (doc,): (String,) = 510 - sqlx::query_as("SELECT document FROM did_documents WHERE did = ?") 511 - .bind(did) 512 - .fetch_one(&db) 513 - .await 514 - .expect("did_documents row should exist"); 536 + let (doc,): (String,) = sqlx::query_as("SELECT document FROM did_documents WHERE did = ?") 537 + .bind(did) 538 + .fetch_one(&db) 539 + .await 540 + .expect("did_documents row should exist"); 515 541 assert!(!doc.is_empty(), "did_document should be non-empty"); 516 542 517 543 // AC2.4: handles row 518 - let (handle_did,): (String,) = 519 - sqlx::query_as("SELECT did FROM handles WHERE did = ?") 520 - .bind(did) 521 - .fetch_one(&db) 522 - .await 523 - .expect("handles row should exist"); 544 + let (handle_did,): (String,) = sqlx::query_as("SELECT did FROM handles WHERE did = ?") 545 + .bind(did) 546 + .fetch_one(&db) 547 + .await 548 + .expect("handles row should exist"); 524 549 assert_eq!(handle_did, did); 525 550 526 551 // AC2.5: pending_accounts and pending_sessions deleted ··· 602 627 .method("POST") 603 628 .uri("/v1/dids") 604 629 .header("Content-Type", "application/json") 605 - .body(Body::from(r#"{"signingKey":"did:key:z...","rotationKey":"did:key:z..."}"#)) 630 + .body(Body::from( 631 + r#"{"signingKey":"did:key:z...","rotationKey":"did:key:z..."}"#, 632 + )) 606 633 .unwrap(); 607 634 608 635 let response = app.oneshot(request).await.unwrap(); ··· 647 674 let response = app 648 675 .oneshot(create_did_request( 649 676 &setup.session_token, 650 - "did:key:zNONEXISTENT", // Not in relay_signing_keys 677 + "did:key:zNONEXISTENT", // Not in relay_signing_keys 651 678 &setup.rotation_key_id, 652 679 )) 653 680 .await ··· 671 698 Mock::given(method("POST")) 672 699 .and(path_regex(r"^/did:plc:.*$")) 673 700 .respond_with(ResponseTemplate::new(200)) 674 - .expect(1) // Only first call should hit plc.directory 701 + .expect(1) // Only first call should hit plc.directory 675 702 .mount(&mock_server) 676 703 .await; 677 704 ··· 781 808 )) 782 809 .await 783 810 .unwrap(); 784 - assert_eq!(resp2.status(), StatusCode::CONFLICT, "should return 409 DID_ALREADY_EXISTS"); 811 + assert_eq!( 812 + resp2.status(), 813 + StatusCode::CONFLICT, 814 + "should return 409 DID_ALREADY_EXISTS" 815 + ); 785 816 } 786 817 787 818 /// MM-89.AC2.11: plc.directory returns non-2xx → 502 PLC_DIRECTORY_ERROR