commit dcdf70d3a1d47a135cad88572ecb10c065896ff7
parent 4a783b5d4e322c7213d4ab26a7d00283dad40087
Author: Gavin Peacock <gpeacock@adobe.com>
Date: Fri, 26 Aug 2022 09:19:58 -0700
Convert status_log error val to a string so that we can return full errors (#121)
* Convert status_tracker err_val to string
* Use set_error in load_from_asset and memory
* Simplify and return all errors
Diffstat:
3 files changed, 63 insertions(+), 69 deletions(-)
diff --git a/sdk/src/status_tracker.rs b/sdk/src/status_tracker.rs
@@ -22,7 +22,7 @@ pub struct LogItem {
pub function: String, // Function where failure occurred
pub line: String, // Line number for error
pub description: String, // Description of the failure
- pub err_val: Option<Error>, // Actual error code
+ err_val: Option<String>, // Actual error code as string
pub validation_status: Option<String>, // C2PA code if available
}
@@ -42,12 +42,25 @@ impl LogItem {
// add an error value
pub fn error(self, err: Error) -> Self {
LogItem {
- err_val: Some(err),
+ err_val: Some(format!("{:?}", err)),
..self
}
}
// add an error value
+ pub fn set_error(self, err: &Error) -> Self {
+ LogItem {
+ err_val: Some(format!("{:?}", err)),
+ ..self
+ }
+ }
+
+ /// returns a reference to the error string if there is one
+ pub fn error_str(&self) -> Option<&str> {
+ self.err_val.as_deref()
+ }
+
+ // add an error value
pub fn validation_status(self, status: &str) -> Self {
LogItem {
validation_status: Some(status.to_string()),
@@ -191,14 +204,12 @@ pub fn report_has_status(report: &[LogItem], val: &str) -> bool {
}
/// Check to see if report contains a specific error
-/// Note: Only the out error object is matched for nested errors like
-/// "Error::InvalidClaim(InvalidClaimError::ClaimSignatureDescriptionBoxInvalid)".
-/// In this case any "InvalidClaim" would match
#[allow(dead_code)] // in case we make use of these or export this
pub fn report_has_err(report: &[LogItem], err: Error) -> bool {
+ let err_type = format!("{:?}", &err);
report.iter().any(|vi| {
if let Some(e) = &vi.err_val {
- std::mem::discriminant(e) == std::mem::discriminant(&err)
+ e == &err_type
} else {
false
}
diff --git a/sdk/src/store.rs b/sdk/src/store.rs
@@ -47,7 +47,7 @@ use crate::{
error::{Error, Result},
hash_utils::{hash_by_alg, vec_compare, verify_by_alg},
jumbf::{self, boxes::*},
- jumbf_io::{get_cailoader_handler, load_jumbf_from_memory},
+ jumbf_io::load_jumbf_from_memory,
status_tracker::{log_item, OneShotStatusTracker, StatusTracker},
validation_status, ManifestStoreReport,
};
@@ -1906,19 +1906,10 @@ impl Store {
Ok(store)
})
.map_err(|e| {
- let err = match e {
- Error::PrereleaseError => Error::PrereleaseError,
- Error::JumbfNotFound => Error::JumbfNotFound,
- Error::IoError(_) => {
- Error::FileNotFound(asset_path.to_string_lossy().to_string())
- }
- Error::UnsupportedType => Error::UnsupportedType,
- Error::RemoteManifestFetch(_) => Error::RemoteManifestFetch("".to_string()),
- _ => Error::LogStop,
- };
- let log_item = log_item!("asset", "error loading file", "load_from_asset").error(e);
- validation_log.log_silent(log_item);
- err
+ validation_log.log_silent(
+ log_item!("asset", "error loading file", "load_from_asset").set_error(&e),
+ );
+ e
})
}
@@ -1926,30 +1917,14 @@ impl Store {
asset_type: &str,
data: &[u8],
validation_log: &mut impl StatusTracker,
- ) -> Result<(Store, Option<String>)> {
- let cai_loader = get_cailoader_handler(asset_type).ok_or(Error::UnsupportedType)?;
-
- let mut buf_reader = Cursor::new(data);
-
- // check for xmp, error if not present
- let xmp = cai_loader.read_xmp(&mut buf_reader);
-
+ ) -> Result<Store> {
// load jumbf if available
- Self::load_cai_from_memory(asset_type, data, validation_log)
- .map(|store| (store, xmp))
- .map_err(|e| {
- let err = match e {
- Error::PrereleaseError => Error::PrereleaseError,
- Error::JumbfNotFound => Error::JumbfNotFound,
- Error::UnsupportedType => Error::UnsupportedType,
- Error::RemoteManifestFetch(_) => Error::RemoteManifestFetch("".to_string()),
- _ => Error::LogStop,
- };
- let log_item =
- log_item!("asset", "error loading asset", "get_store_from_memory").error(e);
- validation_log.log_silent(log_item);
- err
- })
+ Self::load_cai_from_memory(asset_type, data, validation_log).map_err(|e| {
+ validation_log.log_silent(
+ log_item!("asset", "error loading asset", "get_store_from_memory").set_error(&e),
+ );
+ e
+ })
}
/// Returns embedded remote manifest URL if available
@@ -1981,17 +1956,15 @@ impl Store {
verify: bool,
validation_log: &mut impl StatusTracker,
) -> Result<Store> {
- Store::get_store_from_memory(asset_type, data, validation_log).and_then(
- |(store, _xmp_opt)| {
- // verify the store
- if verify {
- // verify store and claims
- Store::verify_store(&store, &ClaimAssetData::ByteData(data), validation_log)?;
- }
+ Store::get_store_from_memory(asset_type, data, validation_log).and_then(|store| {
+ // verify the store
+ if verify {
+ // verify store and claims
+ Store::verify_store(&store, &ClaimAssetData::ByteData(data), validation_log)?;
+ }
- Ok(store)
- },
- )
+ Ok(store)
+ })
}
/// Load Store from a in-memory asset asychronously validating
@@ -2005,7 +1978,7 @@ impl Store {
verify: bool,
validation_log: &mut impl StatusTracker,
) -> Result<Store> {
- let (store, _xmp_opt) = Store::get_store_from_memory(asset_type, data, validation_log)?;
+ let store = Store::get_store_from_memory(asset_type, data, validation_log)?;
// verify the store
if verify {
@@ -2619,10 +2592,7 @@ pub mod tests {
);
assert!(!report.get_log().is_empty());
let errors = report_split_errors(report.get_log_mut());
- assert!(matches!(
- errors[0].err_val.as_ref(),
- Some(Error::IoError(_err))
- ));
+ assert!(errors[0].error_str().unwrap().starts_with("IoError"));
}
#[test]
@@ -2638,10 +2608,7 @@ pub mod tests {
);
assert!(!report.get_log().is_empty());
let errors = report_split_errors(report.get_log_mut());
- assert!(matches!(
- errors[0].err_val.as_ref(),
- Some(Error::PrereleaseError)
- ));
+ assert!(errors[0].error_str().unwrap().starts_with("Prerelease"));
}
#[test]
@@ -2765,10 +2732,14 @@ pub mod tests {
// modify a required field label in the claim - causes failure to read claim from cbor
let report = patch_and_report("C.jpg", b"claim_generator", b"claim_generatur");
assert!(!report.get_log().is_empty());
- assert!(matches!(
- report.get_log()[0].err_val,
- Some(Error::ClaimDecoding)
- ));
+ assert!(report.get_log()[0]
+ .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?
}
@@ -2783,7 +2754,7 @@ pub mod tests {
assert!(!report.get_log().is_empty());
let errors = report_split_errors(report.get_log_mut());
- assert!(matches!(errors[0].err_val, Some(Error::HashMismatch(_))));
+ assert!(errors[0].error_str().unwrap().starts_with("HashMismatch"));
assert_eq!(
errors[0].validation_status.as_deref(),
Some(validation_status::ASSERTION_DATAHASH_MISMATCH)
diff --git a/sdk/src/validation_status.rs b/sdk/src/validation_status.rs
@@ -92,6 +92,18 @@ impl ValidationStatus {
}
// Maps errors into validation_status codes.
+ fn code_from_error_str(error: &str) -> &str {
+ match error {
+ e if e.starts_with("ClaimMissing") => CLAIM_MISSING,
+ e if e.starts_with("AssertionMissing") => ASSERTION_MISSING,
+ e if e.starts_with("AssertionDecoding") => STATUS_ASSERTION_MALFORMED, // todo: no code for invalid assertion format
+ e if e.starts_with("HashMismatch") => ASSERTION_DATAHASH_MATCH,
+ e if e.starts_with("PrereleaseError") => STATUS_PRERELEASE,
+ _ => STATUS_OTHER,
+ }
+ }
+
+ // Maps errors into validation_status codes.
fn code_from_error(error: &Error) -> &str {
match error {
Error::ClaimMissing { .. } => CLAIM_MISSING,
@@ -121,8 +133,8 @@ impl ValidationStatus {
),
// If we don't have a validation_status, then make one from the err_val
// using the description plus error text explanation.
- None => item.err_val.as_ref().map(|e| {
- let code = Self::code_from_error(e);
+ None => item.error_str().as_ref().map(|e| {
+ let code = Self::code_from_error_str(e);
Self::new(code.to_string())
.set_url(item.label.to_string())
.set_explanation(format!("{}: {}", item.description, e))