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 2955fdda1fe0e7fff2c2c202b7d74940012c24bc
parent b146bb7545086656941ae452428aef8c1b3ef6d6
Author: Dylan ross <dylan.ssor@gmail.com>
Date:   Fri,  2 Dec 2022 17:31:02 -0600

makes manifest#add_redaction public; adds test (#156)

* makes manifest#add_redaction public; adds test

* prefers redaction to retraction

Co-authored-by: Dylan Ross <dyross@adobe.com>
Diffstat:
Msdk/src/claim.rs | 7+++----
Msdk/src/manifest.rs | 65++++++++++++++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/sdk/src/claim.rs b/sdk/src/claim.rs @@ -737,13 +737,12 @@ impl Claim { } } - /// Not ready for use!!!!! /// Redact an assertion from a prior claim. /// This will remove the assertion from the JUMBF fn redact_assertion(&mut self, assertion_uri: &str) -> Result<()> { // cannot redact action assertions per the spec let (label, _instance) = Claim::assertion_label_from_link(assertion_uri); - if label == assertions::labels::ACTIONS { + if label == labels::ACTIONS { return Err(Error::AssertionInvalidRedaction); } @@ -930,7 +929,7 @@ impl Claim { } }; - // check for self redacted assertions and illegal readactions + // check for self redacted assertions and illegal redactions if let Some(redactions) = claim.redactions() { for r in redactions { let r_manifest = jumbf::labels::manifest_label_from_uri(r) @@ -949,7 +948,7 @@ impl Claim { if r.contains(assertions::labels::ACTIONS) { let log_item = log_item!( claim.uri(), - "readaction of action assertions disallowed", + "redaction of action assertions disallowed", "verify_internal" ) .error(Error::ClaimDisallowedRedaction) diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs @@ -358,7 +358,6 @@ impl Manifest { } /// Retrieves an assertion by label and instance if it exists or Error::NotFound - /// pub fn find_assertion_with_instance<T: DeserializeOwned>( &self, label: &str, @@ -375,9 +374,9 @@ impl Manifest { } } - // keep this private until we support it externally - #[allow(dead_code)] - pub(crate) fn add_redaction<S: Into<String>>(&mut self, label: S) -> Result<&mut Self> { + /// Redacts an assertion from the parent [Ingredient] of this manifest using the provided + /// assertion label. + pub fn add_redaction<S: Into<String>>(&mut self, label: S) -> Result<&mut Self> { // todo: any way to verify if this assertion exists in the parent claim here? match self.redactions.as_mut() { Some(redactions) => redactions.push(label.into()), @@ -881,18 +880,20 @@ pub(crate) mod tests { #[cfg(feature = "sign")] use crate::utils::test::temp_signer; - use crate::{ - assertions::{c2pa_action, Action, Actions}, - utils::test::TEST_VC, - Manifest, Result, - }; #[cfg(feature = "file_io")] use crate::{ + assertions::labels::ACTIONS, + error::Error, status_tracker::{DetailedStatusTracker, StatusTracker}, store::Store, utils::test::{fixture_path, temp_dir_path, temp_fixture_path, TEST_SMALL_JPEG}, validation_status, Ingredient, }; + use crate::{ + assertions::{c2pa_action, Action, Actions}, + utils::test::TEST_VC, + Manifest, Result, + }; // example of random data structure as an assertion #[derive(serde::Serialize)] @@ -1084,11 +1085,6 @@ pub(crate) mod tests { .set_parent(Ingredient::from_file(&output).expect("from_file")) .expect("set_parent"); - // todo: add a test to validate that actions assertions cannot be redacted - // let mut actions = Actions::new(); - // actions.add_action(Action::new(C2PA_ACTION_EDITED).parameters("gaussian_blur")); - // ws.add_assertion("c2pa.actions", &actions).expect("add_assertion"); // must use .get() with Actions - // redact the assertion manifest2 .add_redaction(ASSERTION_LABEL) @@ -1116,6 +1112,45 @@ pub(crate) mod tests { } #[test] + #[cfg(feature = "file_io")] + fn test_action_assertion_redaction_error() { + let temp_dir = tempdir().expect("temp dir"); + let parent_output = temp_fixture_path(&temp_dir, TEST_SMALL_JPEG); + + // Create parent with a c2pa_action type assertion. + let mut parent_manifest = test_manifest(); + let actions = Actions::new().add_action( + Action::new(c2pa_action::FILTERED) + .set_parameter("name".to_owned(), "gaussian blur") + .unwrap() + .set_when("2015-06-26T16:43:23+0200"), + ); + parent_manifest + .add_assertion(&actions) + .expect("add_assertion"); + + let signer = temp_signer(); + parent_manifest + .embed(&parent_output, &parent_output, &signer) + .expect("embed"); + + // Add parent_manifest as an ingredient of the new manifest and redact the assertion `c2pa.actions`. + let mut manifest = test_manifest(); + manifest + .set_parent(Ingredient::from_file(&parent_output).expect("from_file")) + .expect("set_parent"); + assert!(manifest.add_redaction(ACTIONS).is_ok()); + + // Attempt embedding the manifest with the invalid redaction. + let redact_output = temp_fixture_path(&temp_dir, TEST_SMALL_JPEG); + let embed_result = manifest.embed(&redact_output, &redact_output, &signer); + assert!(matches!( + embed_result.err().unwrap(), + Error::AssertionInvalidRedaction + )); + } + + #[test] fn manifest_assertion_instances() { let mut manifest = Manifest::new("test".to_owned()); let actions = Actions::new().add_action(Action::new(c2pa_action::EDITED)); @@ -1165,7 +1200,7 @@ pub(crate) mod tests { #[async_trait::async_trait] impl crate::signer::RemoteSigner for MyRemoteSigner { - async fn sign_remote(&self, claim_bytes: &[u8]) -> crate::error::Result<Vec<u8>> { + async fn sign_remote(&self, claim_bytes: &[u8]) -> Result<Vec<u8>> { let signer = crate::openssl::temp_signer_async::AsyncSignerAdapter::new( crate::SigningAlg::Ps256, );