c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

commit 5daeb4ed3d388cc397e03c95f9b2e1fc4bae4005
parent 992968f1f8e63f2818bd95d1ef82af50e46eaab2
Author: Gavin  Peacock <gpeacock@adobe.com>
Date:   Tue, 20 Sep 2022 16:48:20 -0700

manifest_data was missing for remote manifests (#135)

* manifest_data was missing for remote manifests on Ingredient::from_file()
* remove time dependency
Diffstat:
Msdk/Cargo.toml | 1-
Msdk/src/ingredient.rs | 42++++++++++++++++++++++++++++++++----------
Msdk/src/store.rs | 38+++++++++++++++++++++++++-------------
3 files changed, 57 insertions(+), 24 deletions(-)

diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml @@ -78,7 +78,6 @@ serde-transcode = "1.1.1" sha2 = "0.10.2" tempfile = "3.1.0" thiserror = ">= 1.0.20, < 1.0.32" -time = ">= 0.2.23" twoway = "0.2.1" url = "2.2.2" uuid = { version = "0.8.1", features = ["serde", "v4", "wasm-bindgen"] } diff --git a/sdk/src/ingredient.rs b/sdk/src/ingredient.rs @@ -387,10 +387,7 @@ impl Ingredient { #[cfg(feature = "file_io")] fn from_file_impl(path: &Path, options: &dyn IngredientOptions) -> Result<Self> { // these are declared inside this function in order to isolate them for wasm builds - use crate::{ - jumbf_io, - status_tracker::{DetailedStatusTracker, StatusTracker}, - }; + use crate::status_tracker::{log_item, DetailedStatusTracker, StatusTracker}; #[cfg(feature = "diagnostics")] let _t = crate::utils::time_it::TimeIt::new("Ingredient:from_file_with_options"); @@ -413,14 +410,39 @@ impl Ingredient { // optionally generate a hash so we know if the file has changed ingredient.hash = options.hash(path); - let mut report = DetailedStatusTracker::new(); + let mut validation_log = DetailedStatusTracker::new(); + + // retrieve the manifest bytes from embedded, sidecar or remote and convert to store if found + let (result, manifest_bytes) = match Store::load_jumbf_from_path(path) { + Ok(manifest_bytes) => { + ( + Store::from_jumbf(&manifest_bytes, &mut validation_log) + .and_then(|mut store| { + // verify the store + store + .verify_from_path(path, &mut validation_log) + .map(|_| store) + }) + .map_err(|e| { + // add a log entry for the error so we act like verify + validation_log.log_silent( + log_item!("asset", "error loading file", "Ingredient::from_file") + .set_error(&e), + ); + e + }), + Some(manifest_bytes), + ) + } + Err(err) => (Err(err), None), + }; // generate a store from the buffer and then validate from the asset path // load and verify store in single call - no need to call low level jumbf_io functions - match Store::load_from_asset(path, true, &mut report) { + match result { Ok(store) => { // generate ValidationStatus from ValidationItems filtering for only errors - let statuses = status_for_store(&store, &mut report); + let statuses = status_for_store(&store, &mut validation_log); if let Some(claim) = store.provenance_claim() { // if the parent claim is valid and has a thumbnail, use it @@ -438,7 +460,7 @@ impl Ingredient { } ingredient.active_manifest = Some(claim.label().to_string()); } - ingredient.manifest_data = jumbf_io::load_jumbf_from_file(path).ok(); + ingredient.manifest_data = manifest_bytes; ingredient.validation_status = if statuses.is_empty() { None } else { @@ -453,7 +475,7 @@ impl Ingredient { // we can ignore the error here because it should have a log entry corresponding to it debug!("ingredient {:?}", e); // convert any other error to a validation status - let statuses: Vec<ValidationStatus> = report + let statuses: Vec<ValidationStatus> = validation_log .get_log() .iter() .filter_map(ValidationStatus::from_validation_item) @@ -886,7 +908,7 @@ mod tests_file_io { let ingredient = Ingredient::from_file(&ap).expect("from_file"); stats(&ingredient); - println!("ingredient = {}", ingredient); + //println!("ingredient = {}", ingredient); assert_eq!(ingredient.title(), BAD_SIGNATURE_JPEG); assert_eq!(ingredient.format(), "image/jpeg"); test_thumbnail(&ingredient, "image/jpeg"); diff --git a/sdk/src/store.rs b/sdk/src/store.rs @@ -1857,26 +1857,21 @@ impl Store { } } - /// load a CAI store from a file + /// load jumbf given a file path + /// + /// This handles, embedded, sidecar and remote manifests /// /// in_path - path to source file /// validation_log - optional vec to contain addition info about the asset #[cfg(feature = "file_io")] - fn load_cai_from_file( - in_path: &Path, - validation_log: &mut impl StatusTracker, - ) -> Result<Store> { + pub fn load_jumbf_from_path(in_path: &Path) -> Result<Vec<u8>> { let external_manifest = in_path.with_extension(MANIFEST_STORE_EXT); match load_jumbf_from_file(in_path) { - Ok(manifest_bytes) => { - // load and validate with CAI toolkit and dump if desired - Store::from_jumbf(&manifest_bytes, validation_log) - } + Ok(manifest_bytes) => Ok(manifest_bytes), Err(Error::JumbfNotFound) => { if external_manifest.exists() { - let external_manifest_bytes = std::fs::read(external_manifest)?; - Store::from_jumbf(&external_manifest_bytes, validation_log) + std::fs::read(external_manifest).map_err(Error::IoError) } else { // check for remote manifest let mut asset_reader = std::fs::File::open(in_path)?; @@ -1888,8 +1883,7 @@ impl Store { .provenance { if cfg!(feature = "fetch_remote_manifests") { - let remote_manifest_bytes = Store::fetch_remote_manifest(&ext_ref)?; - Store::from_jumbf(&remote_manifest_bytes, validation_log) + Store::fetch_remote_manifest(&ext_ref) } else { // return an error with the url that should be read Err(Error::RemoteManifestUrl(ext_ref)) @@ -1903,6 +1897,24 @@ impl Store { } } + /// load a CAI store from a file + /// + /// in_path - path to source file + /// validation_log - optional vec to contain addition info about the asset + #[cfg(feature = "file_io")] + fn load_cai_from_file( + in_path: &Path, + validation_log: &mut impl StatusTracker, + ) -> Result<Store> { + match Self::load_jumbf_from_path(in_path) { + Ok(manifest_bytes) => { + // load and validate with CAI toolkit + Store::from_jumbf(&manifest_bytes, validation_log) + } + Err(e) => Err(e), + } + } + /// Load Store from claims in an existing asset /// asset_path: path to input asset /// verify: determines whether to verify the contents of the provenance claim. Must be set true to use validation_log