commit d105676e835d6fe396bd8617157f2794ca260ce8
parent dcdf70d3a1d47a135cad88572ecb10c065896ff7
Author: Gavin Peacock <gpeacock@adobe.com>
Date: Fri, 26 Aug 2022 10:58:41 -0700
Add RemoteManifestUrl Error, returning url (#120)
This will return a RemoteManifestUrl error if the image has a remote manifest and c2pa-rs is not configured to fetch it. The error contains the url to the remote manifest that should be fetched externally.
Diffstat:
2 files changed, 86 insertions(+), 12 deletions(-)
diff --git a/sdk/src/error.rs b/sdk/src/error.rs
@@ -164,8 +164,6 @@ pub enum Error {
#[error("thread receive error")]
ThreadReceiveError,
- /// No JUMBF data found.
- /// TODO before merging PR: Does this error case need to be part of the public API?
#[error("no JUMBF data found")]
JumbfNotFound,
@@ -175,6 +173,9 @@ pub enum Error {
#[error("could not fetch the remote manifest")]
RemoteManifestFetch(String),
+ #[error("must fetch remote manifests from url")]
+ RemoteManifestUrl(String),
+
#[error("stopped because of logged error")]
LogStop,
diff --git a/sdk/src/store.rs b/sdk/src/store.rs
@@ -1834,10 +1834,27 @@ impl Store {
data: &[u8],
validation_log: &mut impl StatusTracker,
) -> Result<Store> {
- load_jumbf_from_memory(asset_type, data).and_then(|cai_block| {
- // load and validate with CAI toolkit and dump if desired
- Store::from_jumbf(&cai_block, validation_log)
- })
+ match load_jumbf_from_memory(asset_type, data) {
+ Ok(manifest_bytes) => {
+ // load and validate with CAI toolkit and dump if desired
+ Store::from_jumbf(&manifest_bytes, validation_log)
+ }
+ Err(Error::JumbfNotFound) => {
+ let mut buf_reader = Cursor::new(data);
+ if let Some(ext_ref) = crate::utils::xmp_inmemory_utils::XmpInfo::from_source(
+ &mut buf_reader,
+ asset_type,
+ )
+ .provenance
+ {
+ // return an error with the url that should be read
+ Err(Error::RemoteManifestUrl(ext_ref))
+ } else {
+ Err(Error::JumbfNotFound)
+ }
+ }
+ Err(e) => Err(e),
+ }
}
/// load a CAI store from a file
@@ -1874,7 +1891,8 @@ impl Store {
let remote_manifest_bytes = Store::fetch_remote_manifest(&ext_ref)?;
Store::from_jumbf(&remote_manifest_bytes, validation_log)
} else {
- Err(Error::JumbfNotFound)
+ // return an error with the url that should be read
+ Err(Error::RemoteManifestUrl(ext_ref))
}
} else {
Err(Error::JumbfNotFound)
@@ -2736,11 +2754,6 @@ pub mod tests {
.error_str()
.unwrap()
.starts_with("ClaimDecoding"))
- // assert!(matches!(
- // report.get_log()[0].err_val,
- // Some(Error::ClaimDecoding)
- // ));
- //assert_eq!(report[0].validation_status.as_deref(), Some(???)); // what validation status should we have for this?
}
#[test]
@@ -3006,4 +3019,64 @@ pub mod tests {
let mut validation_log = OneShotStatusTracker::default();
Store::load_from_asset(&op, true, &mut validation_log).unwrap();
}
+
+ #[test]
+ fn test_external_manifest_from_memory() {
+ // test adding to actual image
+ let ap = fixture_path("libpng-test.png");
+ let temp_dir = tempdir().expect("temp dir");
+ let op = temp_dir_path(&temp_dir, "libpng-test-c2pa.png");
+
+ let sidecar = op.with_extension(MANIFEST_STORE_EXT);
+
+ // Create claims store.
+ let mut store = Store::new();
+
+ // Create a new claim.
+ let mut claim = create_test_claim().unwrap();
+
+ // Do we generate JUMBF?
+ let signer = temp_signer();
+
+ // start with base url
+ let fp = format!("file:/{}", sidecar.to_str().unwrap());
+ let url = url::Url::parse(&fp).unwrap();
+
+ let url_string: String = url.into();
+
+ // set claim for side car with remote manifest embedding generation
+ claim.set_remote_manifest(url_string.clone()).unwrap();
+
+ store.commit_claim(claim).unwrap();
+
+ let saved_manifest = store.save_to_asset(&ap, &signer, &op).unwrap();
+
+ // delete the sidecar so we can test for url only rea
+ // std::fs::remove_file(sidecar);
+
+ assert!(sidecar.exists());
+
+ // load external manifest
+ let loaded_manifest = std::fs::read(sidecar).unwrap();
+
+ // compare returned to external
+ assert_eq!(saved_manifest, loaded_manifest);
+
+ // Load the exported file into a buffer
+ let file_buffer = std::fs::read(&op).unwrap();
+
+ let mut validation_log = OneShotStatusTracker::default();
+ let result = Store::load_from_memory("png", &file_buffer, true, &mut validation_log);
+
+ assert!(result.is_err());
+
+ // verify that we got RemoteManifestUrl error with the expected url
+ match result {
+ Ok(_store) => panic!("did not expect to have a store"),
+ Err(e) => match e {
+ Error::RemoteManifestUrl(url) => assert_eq!(url, url_string),
+ _ => panic!("unexepected error"),
+ },
+ }
+ }
}