fix(api): dont verify signature or DID during importRepo
71 unmodified lines7273747576767778798017 unmodified lines9899100101102102103104105106107108109110104105106107108269 unmodified linesExpand all71 unmodified lines }}
#[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; let export_res = client17 unmodified lines .body(car_bytes.to_vec()) .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]async fn test_import_accepts_own_exported_repo() {269 unmodified linesExpand all75 unmodified lines767778798081828384858687888990919293949596979899100808182832 unmodified lines868788891111121139091929394951159697989910021 unmodified lines122123124125145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194126127128129224 unmodified linesExpand all75 unmodified lines did, 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") .unwrap_or_else(|| {2 unmodified lines .unwrap_or(false) }); 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={}", verified.rev, verified.data_cid21 unmodified lines e ))); } } } 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;
224 unmodified linesExpand all90 unmodified lines9192939495959698979899100101102104105106107108109110103104105113114115116117118106107108109110111112166 unmodified linesExpand all2792802812822832842852862872882892902912922932946 unmodified lines90 unmodified lines }
pub fn verify_car_structure_only( &self, expected_did: &Did, root_cid: &Cid, blocks: &HashMap<Cid, Bytes>, ) -> Result<VerifiedCar, VerifyError> { ) -> Result<StructureVerifiedCar, VerifyError> { 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(), })166 unmodified linesExpand all }}
#[derive(Debug, Clone)]pub struct StructureVerifiedCar { pub did: Did, pub rev: String, pub data_cid: Cid, pub prev: Option<Cid>,}
#[derive(Debug, Clone)]pub struct VerifiedCar { pub did: Did, pub rev: String, pub data_cid: Cid,6 unmodified lines