client.rs (5244B)
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 //! Example C2PA client application 15 16 use std::path::PathBuf; 17 18 use anyhow::Result; 19 use c2pa::{ 20 assertions::{c2pa_action, labels, Action, Actions, CreativeWork, Exif, SchemaDotOrgPerson}, 21 create_signer, Ingredient, Manifest, Reader as ManifestStore, SigningAlg, 22 }; 23 24 const GENERATOR: &str = "test_app/0.1"; 25 const INDENT_SPACE: usize = 2; 26 27 // Example for reading the contents of a manifest store, recursively showing nested manifests 28 fn show_manifest(manifest_store: &ManifestStore, manifest_label: &str, level: usize) -> Result<()> { 29 let indent = " ".repeat(level * INDENT_SPACE); 30 31 println!("{indent}manifest_label: {manifest_label}"); 32 if let Some(manifest) = manifest_store.get_manifest(manifest_label) { 33 println!( 34 "{}title: {} , format: {}, instance_id: {}", 35 indent, 36 manifest.title().unwrap_or_default(), 37 manifest.format(), 38 manifest.instance_id() 39 ); 40 41 for assertion in manifest.assertions().iter() { 42 println!("{}", assertion.label_with_instance()); 43 match assertion.label() { 44 labels::ACTIONS => { 45 let actions: Actions = assertion.to_assertion()?; 46 for action in actions.actions { 47 println!("{}{}", indent, action.action()); 48 } 49 } 50 labels::CREATIVE_WORK => { 51 let creative_work: CreativeWork = assertion.to_assertion()?; 52 if let Some(authors) = creative_work.author() { 53 for author in authors { 54 if let Some(name) = author.name() { 55 println!("{indent}author = {name} "); 56 } 57 } 58 } 59 if let Some(url) = creative_work.get::<String>("url") { 60 println!("{indent}url = {url} "); 61 } 62 } 63 _ => {} 64 } 65 } 66 67 for ingredient in manifest.ingredients().iter() { 68 println!("{}Ingredient title:{}", indent, ingredient.title()); 69 if let Some(label) = ingredient.active_manifest() { 70 show_manifest(manifest_store, label, level + 1)?; 71 } 72 } 73 } 74 Ok(()) 75 } 76 77 pub fn main() -> Result<()> { 78 let args: Vec<String> = std::env::args().collect(); 79 // allow passing in source and dest paths or use defaults 80 let (src, dst) = match args.len() >= 3 { 81 true => (args[1].as_str(), args[2].as_str()), 82 false => ( 83 "sdk/tests/fixtures/earth_apollo17.jpg", 84 "target/tmp/client.jpg", 85 ), 86 }; 87 88 let source = PathBuf::from(src); 89 let dest = PathBuf::from(dst); 90 // if a filepath was provided on the command line, read it as a parent file 91 let parent = Ingredient::from_file(source.as_path())?; 92 93 // create an action assertion stating that we imported this file 94 let actions = Actions::new().add_action( 95 Action::new(c2pa_action::PLACED) 96 .set_parameter("identifier", parent.instance_id().to_owned())?, 97 ); 98 99 // build a creative work assertion 100 let creative_work = 101 CreativeWork::new().add_author(SchemaDotOrgPerson::new().set_name("me")?)?; 102 103 let exif = Exif::from_json_str( 104 r#"{ 105 "@context" : { 106 "exif": "http://ns.adobe.com/exif/1.0/" 107 }, 108 "exif:GPSVersionID": "2.2.0.0", 109 "exif:GPSLatitude": "39,21.102N", 110 "exif:GPSLongitude": "74,26.5737W", 111 "exif:GPSAltitudeRef": 0, 112 "exif:GPSAltitude": "100963/29890", 113 "exif:GPSTimeStamp": "2019-09-22T18:22:57Z" 114 }"#, 115 )?; 116 117 // create a new Manifest 118 let mut manifest = Manifest::new(GENERATOR.to_owned()); 119 // add parent and assertions 120 manifest 121 .set_parent(parent)? 122 .add_assertion(&actions)? 123 .add_assertion(&creative_work)? 124 .add_assertion(&exif)?; 125 126 // sign and embed into the target file 127 let signcert_path = "sdk/tests/fixtures/certs/es256.pub"; 128 let pkey_path = "sdk/tests/fixtures/certs/es256.pem"; 129 let signer = create_signer::from_files(signcert_path, pkey_path, SigningAlg::Es256, None)?; 130 131 manifest.embed(&source, &dest, &*signer)?; 132 133 let manifest_store = ManifestStore::from_file(&dest)?; 134 135 // example of how to print out the whole manifest as json 136 println!("{manifest_store}\n"); 137 138 // walk through the manifest and access data. 139 140 if let Some(manifest_label) = manifest_store.active_label() { 141 show_manifest(&manifest_store, manifest_label, 0)?; 142 } 143 144 Ok(()) 145 }