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

integration.rs (8131B)


      1 // Copyright 2022 Adobe. All rights reserved.
      2 // This file is licensed to you under the Apache License,
      3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
      4 // or the MIT license (http://opensource.org/licenses/MIT),
      5 // at your option.
      6 
      7 // Unless required by applicable law or agreed to in writing,
      8 // this software is distributed on an "AS IS" BASIS, WITHOUT
      9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
     10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the
     11 // specific language governing permissions and limitations under
     12 // each license.
     13 
     14 /// Complete functional integration test with parent and ingredients.
     15 // Isolate from wasm by wrapping in module.
     16 #[cfg(feature = "file_io")]
     17 mod integration_1 {
     18 
     19     use std::path::PathBuf;
     20 
     21     use c2pa::{
     22         assertions::{c2pa_action, Action, Actions},
     23         create_signer,
     24         settings::load_settings_from_str,
     25         Ingredient, Manifest, ManifestStore, Result, Signer, SigningAlg,
     26     };
     27     use tempfile::tempdir;
     28 
     29     const GENERATOR: &str = "app";
     30 
     31     // prevent tests from polluting the results of each other because of Rust unit test concurrency
     32     static PROTECT: std::sync::Mutex<u32> = std::sync::Mutex::new(1); // prevent tests from polluting the results of each other
     33 
     34     fn get_temp_signer() -> Box<dyn Signer> {
     35         // sign and embed into the target file
     36         let mut signcert_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     37         signcert_path.push("tests/fixtures/certs/ps256.pub");
     38         let mut pkey_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     39         pkey_path.push("tests/fixtures/certs/ps256.pem");
     40         create_signer::from_files(signcert_path, pkey_path, SigningAlg::Ps256, None)
     41             .expect("get_signer_from_files")
     42     }
     43 
     44     fn configure_trust(
     45         trust_anchors: Option<String>,
     46         allowed_list: Option<String>,
     47         trust_config: Option<String>,
     48     ) -> Result<()> {
     49         let ta = r#"{"trust": { "trust_anchors": replacement_val } }"#;
     50         let al = r#"{"trust": { "allowed_list": replacement_val } }"#;
     51         let tc = r#"{"trust": { "trust_config": replacement_val } }"#;
     52 
     53         let mut enable_trust_checks = false;
     54         if let Some(trust_list) = trust_anchors {
     55             let replacement_val = serde_json::Value::String(trust_list).to_string(); // escape string
     56             let setting = ta.replace("replacement_val", &replacement_val);
     57 
     58             load_settings_from_str(&setting, "json")?;
     59 
     60             enable_trust_checks = true;
     61         }
     62 
     63         if let Some(allowed_list) = allowed_list {
     64             let replacement_val = serde_json::Value::String(allowed_list).to_string(); // escape string
     65             let setting = al.replace("replacement_val", &replacement_val);
     66 
     67             load_settings_from_str(&setting, "json")?;
     68 
     69             enable_trust_checks = true;
     70         }
     71 
     72         if let Some(trust_config) = trust_config {
     73             let replacement_val = serde_json::Value::String(trust_config).to_string(); // escape string
     74             let setting = tc.replace("replacement_val", &replacement_val);
     75 
     76             load_settings_from_str(&setting, "json")?;
     77 
     78             enable_trust_checks = true;
     79         }
     80 
     81         // enable trust checks
     82         if enable_trust_checks {
     83             load_settings_from_str(r#"{"verify": { "verify_trust": true} }"#, "json")?;
     84         }
     85 
     86         Ok(())
     87     }
     88 
     89     #[test]
     90     #[cfg(feature = "file_io")]
     91     fn test_embed_manifest() -> Result<()> {
     92         let _protect = PROTECT.lock().unwrap();
     93 
     94         // set up parent and destination paths
     95         let dir = tempdir()?;
     96         let output_path = dir.path().join("test_file.jpg");
     97         let mut parent_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     98         parent_path.push("tests/fixtures/earth_apollo17.jpg");
     99         let mut ingredient_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    100         ingredient_path.push("tests/fixtures/libpng-test.png");
    101 
    102         let config = include_bytes!("../tests/fixtures/certs/trust/store.cfg");
    103         let priv_trust = include_bytes!("../tests/fixtures/certs/trust/test_cert_root_bundle.pem");
    104 
    105         // Configure before first use so that trust settings are used for all calls.
    106         // In production code you should check that the file is indeed UTF-8 text.
    107         configure_trust(
    108             Some(String::from_utf8_lossy(priv_trust).to_string()),
    109             None,
    110             Some(String::from_utf8_lossy(config).to_string()),
    111         )?;
    112 
    113         // create a new Manifest
    114         let mut manifest = Manifest::new(GENERATOR.to_owned());
    115 
    116         // allocate actions so we can add them
    117         let mut actions = Actions::new();
    118 
    119         // add a parent ingredient
    120         let parent = Ingredient::from_file(&parent_path)?;
    121         // add an action assertion stating that we imported this file
    122         actions = actions.add_action(
    123             Action::new(c2pa_action::EDITED)
    124                 .set_when("2015-06-26T16:43:23+0200")
    125                 .set_parameter("name".to_owned(), "import")?
    126                 .set_parameter("identifier".to_owned(), parent.instance_id().to_owned())?,
    127         );
    128 
    129         // set the parent ingredient
    130         manifest.set_parent(parent)?;
    131 
    132         actions = actions.add_action(
    133             Action::new("c2pa.edit").set_parameter("name".to_owned(), "brightnesscontrast")?,
    134         );
    135 
    136         // add an ingredient
    137         let ingredient = Ingredient::from_file(&ingredient_path)?;
    138 
    139         // add an action assertion stating that we imported this file
    140         actions = actions.add_action(
    141             Action::new(c2pa_action::EDITED)
    142                 .set_parameter("name".to_owned(), "import")?
    143                 .set_parameter("identifier".to_owned(), ingredient.instance_id().to_owned())?,
    144             // could add other parameters for position and size here
    145         );
    146 
    147         manifest.add_ingredient(ingredient);
    148 
    149         manifest.add_assertion(&actions)?;
    150 
    151         // sign and embed into the target file
    152         let signer = get_temp_signer();
    153         manifest.embed(&parent_path, &output_path, &*signer)?;
    154 
    155         // read our new file with embedded manifest
    156         let manifest_store = ManifestStore::from_file(&output_path)?;
    157 
    158         println!("{manifest_store}");
    159 
    160         assert!(manifest_store.get_active().is_some());
    161         if let Some(manifest) = manifest_store.get_active() {
    162             assert!(manifest.title().is_some());
    163             assert_eq!(manifest.ingredients().len(), 2);
    164         } else {
    165             panic!("no manifest in store");
    166         }
    167         Ok(())
    168     }
    169 
    170     #[test]
    171     #[cfg(feature = "file_io")]
    172     fn test_embed_json_manifest() -> Result<()> {
    173         let _protect = PROTECT.lock().unwrap();
    174 
    175         c2pa::settings::reset_default_settings().unwrap();
    176 
    177         // set up parent and destination paths
    178         let dir = tempdir()?;
    179         let output_path = dir.path().join("test_file.jpg");
    180 
    181         let mut fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    182         fixture_path.push("tests/fixtures");
    183 
    184         let mut parent_path = fixture_path.clone();
    185         parent_path.push("earth_apollo17.jpg");
    186         let mut manifest_path = fixture_path.clone();
    187         manifest_path.push("manifest.json");
    188 
    189         let json = std::fs::read_to_string(manifest_path)?;
    190 
    191         let mut manifest = Manifest::from_json(&json)?;
    192         manifest.with_base_path(fixture_path.canonicalize()?)?;
    193 
    194         // sign and embed into the target file
    195         let signer = get_temp_signer();
    196         manifest.embed(&parent_path, &output_path, &*signer)?;
    197 
    198         // read our new file with embedded manifest
    199         let manifest_store = ManifestStore::from_file(&output_path)?;
    200 
    201         println!("{manifest_store}");
    202         // std::fs::copy(&output_path, "test_file.jpg")?; // for debugging to get copy of the file
    203 
    204         assert!(manifest_store.get_active().is_some());
    205         if let Some(manifest) = manifest_store.get_active() {
    206             assert!(manifest.title().is_some());
    207             assert_eq!(manifest.ingredients().len(), 2);
    208         } else {
    209             panic!("no manifest in store");
    210         }
    211         Ok(())
    212     }
    213 }