diff --git a/libips/src/actions/mod.rs b/libips/src/actions/mod.rs index 4875736..fac3dd4 100644 --- a/libips/src/actions/mod.rs +++ b/libips/src/actions/mod.rs @@ -790,6 +790,35 @@ impl From for Transform { } } +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, Diff)] +#[diff(attr( + #[derive(Debug, PartialEq)] +))] +pub struct Signature { + pub value: String, + pub algorithm: String, + pub chain: String, + pub chash: String, + pub version: String, +} + +impl From for Signature { + fn from(act: Action) -> Self { + let mut sig = Signature::default(); + sig.value = act.payload_string; + for prop in act.properties { + match prop.key.as_str() { + "algorithm" => sig.algorithm = prop.value, + "chain" => sig.chain = prop.value, + "chash" => sig.chash = prop.value, + "version" => sig.version = prop.value, + _ => {} + } + } + sig + } +} + #[derive(Hash, Eq, PartialEq, Debug, Default, Clone, Deserialize, Serialize, Diff)] #[diff(attr( #[derive(Debug, PartialEq)] @@ -827,6 +856,8 @@ pub struct Manifest { pub legacies: Vec, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub transforms: Vec, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub signatures: Vec, } impl Manifest { @@ -843,6 +874,7 @@ impl Manifest { drivers: Vec::new(), legacies: Vec::new(), transforms: Vec::new(), + signatures: Vec::new(), } } @@ -886,7 +918,7 @@ impl Manifest { self.transforms.push(act.into()); } ActionKind::Signature => { - debug!("signature action encountered, skipping for now"); + self.signatures.push(act.into()); } ActionKind::Unknown { action } => { debug!("action {:?} not known, skipping", action); diff --git a/libips/src/recv.rs b/libips/src/recv.rs index f1da74e..2820922 100644 --- a/libips/src/recv.rs +++ b/libips/src/recv.rs @@ -266,6 +266,23 @@ impl<'a, S: ReadableRepository + Sync> PackageReceiver<'a, S> { txn.add_file((*file).clone(), &temp_file_path)?; } + // Fetch signature payloads + for sig in &manifest.signatures { + if sig.value.is_empty() { + continue; + } + + let digest = &sig.value; + let temp_file_path = temp_dir.path().join(format!("sig-{}", digest)); + debug!("Fetching signature payload {} to {}", digest, temp_file_path.display()); + + self.source.fetch_payload(publisher, digest, &temp_file_path)?; + + let mut sig_file_action = crate::actions::File::default(); + sig_file_action.path = format!("signature-{}", digest); + txn.add_file(sig_file_action, &temp_file_path)?; + } + txn.update_manifest(manifest.clone()); txn.commit()?; diff --git a/pkg6repo/src/pkg5_import.rs b/pkg6repo/src/pkg5_import.rs index 5206063..a574d9c 100644 --- a/pkg6repo/src/pkg5_import.rs +++ b/pkg6repo/src/pkg5_import.rs @@ -554,6 +554,47 @@ impl Pkg5Importer { } } + // Import signature files + for signature in &manifest.signatures { + if signature.value.is_empty() { + continue; + } + + let hash = &signature.value; + // Determine the file path in the source repository + let first_two = &hash[0..2]; + let next_two = &hash[2..4]; + let file_path_new = file_dir.join(first_two).join(next_two).join(hash); + let file_path_old = file_dir.join(first_two).join(hash); + + let file_path = if file_path_new.exists() { + file_path_new + } else if file_path_old.exists() { + file_path_old + } else { + warn!( + "Signature file not found in source repository: {}", + hash + ); + continue; + }; + + // Use a unique name for the signature file in the proto dir + let proto_sig_path = proto_dir.join(format!("signature-{}", hash)); + if let Some(parent) = proto_sig_path.parent() { + fs::create_dir_all(parent).map_err(|e| Pkg6RepoError::IoError(e))?; + } + + fs::copy(&file_path, &proto_sig_path).map_err(|e| Pkg6RepoError::IoError(e))?; + + // We need a FileAction to add it to the transaction + // Even though it's a signature, FileBackend uses add_file to store payloads + let mut sig_file_action = libips::actions::File::default(); + sig_file_action.path = format!("signature-{}", hash); + // transaction.add_file will calculate the hash and store it in the repo's file dir + transaction.add_file(sig_file_action, &proto_sig_path)?; + } + // Update the manifest in the transaction transaction.update_manifest(manifest);