diff --git a/crates/tranquil-api/src/repo/import.rs b/crates/tranquil-api/src/repo/import.rs index 2180c7a..742ef01 100644 --- a/crates/tranquil-api/src/repo/import.rs +++ b/crates/tranquil-api/src/repo/import.rs @@ -77,27 +77,6 @@ pub async fn import_repo( blocks.len(), root ); - let Some(root_block) = blocks.get(&root) else { - return Err(ApiError::InvalidRequest( - "Root block not found in CAR file".into(), - )); - }; - let commit_did: Did = match jacquard_repo::commit::Commit::from_cbor(root_block) { - Ok(commit) => commit - .did() - .as_str() - .parse() - .map_err(|_| ApiError::InvalidRequest("Commit contains invalid DID".into()))?, - Err(e) => { - return Err(ApiError::InvalidRequest(format!("Invalid commit: {}", e))); - } - }; - if commit_did != *did { - return Err(ApiError::InvalidRepo(format!( - "CAR file is for DID {} but you are authenticated as {}", - commit_did, did - ))); - } let skip_verification = std::env::var("SKIP_IMPORT_VERIFICATION") .ok() .map(|v| v == "true" || v == "1") @@ -108,11 +87,13 @@ pub async fn import_repo( }); let is_migration = user.inbound_migration && user.deactivated_at.is_some(); if skip_verification { - warn!("Skipping all CAR verification for import (SKIP_IMPORT_VERIFICATION=true)"); - } else if is_migration { - debug!("Verifying CAR file structure for migration (skipping signature verification)"); + warn!("Skipping all CAR verification for repo import (SKIP_IMPORT_VERIFICATION=true)"); + } else { + debug!( + "Verifying CAR file structure for repo import (skipping signature and DID verification)" + ); let verifier = CarVerifier::new(); - match verifier.verify_car_structure_only(did, &root, &blocks) { + match verifier.verify_car_structure_only(&root, &blocks) { Ok(verified) => { debug!( "CAR structure verification successful: rev={}, data_cid={}", @@ -142,56 +123,6 @@ pub async fn import_repo( ))); } } - } else { - debug!("Verifying CAR file signature and structure for DID {}", did); - let verifier = CarVerifier::new(); - match verifier.verify_car(did, &root, &blocks).await { - Ok(verified) => { - debug!( - "CAR verification successful: rev={}, data_cid={}", - verified.rev, verified.data_cid - ); - } - Err(tranquil_pds::sync::verify::VerifyError::DidMismatch { - commit_did, - expected_did, - }) => { - return Err(ApiError::InvalidRepo(format!( - "CAR file is for DID {} but you are authenticated as {}", - commit_did, expected_did - ))); - } - Err(tranquil_pds::sync::verify::VerifyError::InvalidSignature) => { - return Err(ApiError::InvalidRequest( - "CAR file commit signature verification failed".into(), - )); - } - Err(tranquil_pds::sync::verify::VerifyError::DidResolutionFailed(msg)) => { - warn!("DID resolution failed during import verification: {}", msg); - return Err(ApiError::InvalidRequest(format!( - "Failed to verify DID: {}", - msg - ))); - } - Err(tranquil_pds::sync::verify::VerifyError::NoSigningKey) => { - return Err(ApiError::InvalidRequest( - "DID document does not contain a signing key".into(), - )); - } - Err(tranquil_pds::sync::verify::VerifyError::MstValidationFailed(msg)) => { - return Err(ApiError::InvalidRequest(format!( - "MST validation failed: {}", - msg - ))); - } - Err(e) => { - error!("CAR verification error: {:?}", e); - return Err(ApiError::InvalidRequest(format!( - "CAR verification failed: {}", - e - ))); - } - } } let max_blocks = tranquil_config::get().import.max_blocks as usize; let _write_lock = state.repo_write_locks.lock(user_id).await; diff --git a/crates/tranquil-pds/src/sync/verify.rs b/crates/tranquil-pds/src/sync/verify.rs index 43571f0..16aa225 100644 --- a/crates/tranquil-pds/src/sync/verify.rs +++ b/crates/tranquil-pds/src/sync/verify.rs @@ -92,30 +92,20 @@ impl CarVerifier { pub fn verify_car_structure_only( &self, - expected_did: &Did, root_cid: &Cid, blocks: &HashMap, - ) -> Result { + ) -> Result { let root_block = blocks .get(root_cid) .ok_or_else(|| VerifyError::BlockNotFound(root_cid.to_string()))?; let commit = Commit::from_cbor(root_block).map_err(|e| VerifyError::InvalidCommit(e.to_string()))?; - let commit_did = commit.did().as_str(); - if commit_did != expected_did.as_str() { - return Err(VerifyError::DidMismatch { - commit_did: commit_did.to_string(), - expected_did: expected_did.to_string(), - }); - } + let commit_did = commit.did().to_string().into(); let data_cid = commit.data(); self.verify_mst_structure(data_cid, blocks)?; - debug!( - "MST structure verified for DID {} (signature verification skipped for migration)", - expected_did - ); - Ok(VerifiedCar { - did: expected_did.clone(), + debug!("MST structure verified for commit: {:?}", commit); + Ok(StructureVerifiedCar { + did: commit_did, rev: commit.rev().to_string(), data_cid: *data_cid, prev: commit.prev().cloned(), @@ -289,6 +279,14 @@ impl CarVerifier { } } +#[derive(Debug, Clone)] +pub struct StructureVerifiedCar { + pub did: Did, + pub rev: String, + pub data_cid: Cid, + pub prev: Option, +} + #[derive(Debug, Clone)] pub struct VerifiedCar { pub did: Did, diff --git a/crates/tranquil-pds/tests/import_verification.rs b/crates/tranquil-pds/tests/import_verification.rs index b260452..19775dc 100644 --- a/crates/tranquil-pds/tests/import_verification.rs +++ b/crates/tranquil-pds/tests/import_verification.rs @@ -73,7 +73,7 @@ fn write_varint(buf: &mut Vec, mut value: u64) { } #[tokio::test] -async fn test_import_rejects_car_for_different_user() { +async fn test_import_doesnt_reject_car_for_different_user() { let client = client(); let (token_a, _did_a) = create_account_and_login(&client).await; let (_token_b, did_b) = create_account_and_login(&client).await; @@ -99,15 +99,9 @@ async fn test_import_rejects_car_for_different_user() { .send() .await .expect("Import failed"); - assert_eq!(import_res.status(), StatusCode::FORBIDDEN); + assert_eq!(import_res.status(), StatusCode::OK); let body: serde_json::Value = import_res.json().await.unwrap(); - assert!( - body["error"] == "InvalidRepo" - || body["error"] == "InvalidRequest" - || body["error"] == "DidMismatch", - "Expected InvalidRepo, DidMismatch, or InvalidRequest error, got: {:?}", - body - ); + assert!(body.is_object() && body.as_object().unwrap().is_empty()); } #[tokio::test]