Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.cargo/config.toml

.vscode
.claude

/semver-checks/target/
sdk/target/
Expand Down
66 changes: 22 additions & 44 deletions c2pa_c_ffi/src/c_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ use std::{
#[cfg(feature = "file_io")]
use c2pa::Ingredient;
use c2pa::{
assertions::DataHash, identity::validator::CawgValidator, Builder as C2paBuilder,
CallbackSigner, Context, ProgressPhase, Reader as C2paReader, Settings as C2paSettings,
SigningAlg,
assertions::DataHash, Builder as C2paBuilder, CallbackSigner, Context, ProgressPhase,
Reader as C2paReader, Settings as C2paSettings, SigningAlg,
};
use tokio::runtime::Builder;

//use tokio::runtime::Builder;
#[cfg(feature = "file_io")]
use crate::json_api::{read_file, sign_file};
#[cfg(test)]
Expand Down Expand Up @@ -1145,30 +1144,6 @@ pub unsafe extern "C" fn c2pa_free_string_array(ptr: *const *const c_char, count
Vec::from_raw_parts(mut_ptr, count, count);
}

// Run CAWG post-validation - this is async and requires a runtime.
fn post_validate(result: Result<C2paReader, c2pa::Error>) -> Result<C2paReader, c2pa::Error> {
match result {
Ok(mut reader) => {
#[cfg(target_arch = "wasm32")]
let runtime = Builder::new_current_thread().enable_all().build();

#[cfg(not(target_arch = "wasm32"))]
let runtime = Builder::new_multi_thread().enable_all().build();

let runtime = match runtime {
Ok(runtime) => runtime,
Err(err) => return Err(c2pa::Error::OtherError(Box::new(err))),
};

match runtime.block_on(reader.post_validate_async(&CawgValidator {})) {
Ok(_) => Ok(reader),
Err(err) => Err(err),
}
}
Err(err) => Err(err),
}
}

/// Creates a new C2paReader from a default context.
///
/// # Safety
Expand Down Expand Up @@ -1228,9 +1203,8 @@ pub unsafe extern "C" fn c2pa_reader_from_stream(
// Legacy C API: inherits thread-local settings set by c2pa_load_settings.
// Prefer c2pa_reader_from_context for new C API usage.
#[allow(deprecated)]
let result = C2paReader::from_stream(&format, stream);
let result = ok_or_return_null!(post_validate(result));
box_tracked!(result)
let reader = ok_or_return_null!(C2paReader::from_stream(&format, stream));
box_tracked!(reader)
}

/// Configures an existing reader with a stream.
Expand Down Expand Up @@ -1261,9 +1235,8 @@ pub unsafe extern "C" fn c2pa_reader_with_stream(
// Now safe to take ownership - all validations passed
untrack_or_return_null!(reader, C2paReader);
let reader = Box::from_raw(reader);
let result = (*reader).with_stream(&format, stream);
let result = ok_or_return_null!(post_validate(result));
box_tracked!(result)
let reader = ok_or_return_null!((*reader).with_stream(&format, stream));
box_tracked!(reader)
}

/// Configures an existing passed in Reader with manifest data and a stream.
Expand Down Expand Up @@ -1300,11 +1273,13 @@ pub unsafe extern "C" fn c2pa_reader_with_manifest_data_and_stream(
// Take ownership of the Reader (needs to remove it from tracking to take it)
untrack_or_return_null!(reader, C2paReader);
let reader = Box::from_raw(reader);
let result = (*reader).with_manifest_data_and_stream(manifest_bytes, &format, stream);
let result = ok_or_return_null!(post_validate(result));

let reader = ok_or_return_null!((*reader).with_manifest_data_and_stream(
manifest_bytes,
&format,
stream
));
// New reader, will be tracked now too
box_tracked!(result)
box_tracked!(reader)
}

/// Configures an existing reader with a fragment stream.
Expand Down Expand Up @@ -1347,9 +1322,8 @@ pub unsafe extern "C" fn c2pa_reader_with_fragment(
// Now safe to take ownership - all validations passed
untrack_or_return_null!(reader, C2paReader);
let reader = Box::from_raw(reader);
let result = (*reader).with_fragment(&format, stream, fragment);
let result = ok_or_return_null!(post_validate(result));
box_tracked!(result)
let reader = ok_or_return_null!((*reader).with_fragment(&format, stream, fragment));
box_tracked!(reader)
}

/// Creates a new C2paReader from a shared Context.
Expand Down Expand Up @@ -1396,7 +1370,7 @@ pub unsafe fn c2pa_reader_from_file(path: *const c_char) -> *mut C2paReader {
let path = cstr_or_return_null!(path);
// Legacy C API: inherits thread-local settings set by c2pa_load_settings.
let result = C2paReader::from_file(&path);
box_tracked!(ok_or_return_null!(post_validate(result)))
box_tracked!(ok_or_return_null!(result))
}

/// Creates and verifies a C2paReader from an asset stream with the given format and manifest data.
Expand Down Expand Up @@ -1432,8 +1406,12 @@ pub unsafe extern "C" fn c2pa_reader_from_manifest_data_and_stream(

// Legacy C API: inherits thread-local settings set by c2pa_load_settings.
#[allow(deprecated)]
let result = C2paReader::from_manifest_data_and_stream(manifest_bytes, &format, stream);
box_tracked!(ok_or_return_null!(post_validate(result)))
let reader = ok_or_return_null!(C2paReader::from_manifest_data_and_stream(
manifest_bytes,
&format,
stream
));
box_tracked!(reader)
}

/// Frees a C2paReader allocated by Rust.
Expand Down
21 changes: 2 additions & 19 deletions c2pa_c_ffi/src/json_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
// specific language governing permissions and limitations under
// each license.

use c2pa::{identity::validator::CawgValidator, Ingredient, Reader, Relationship};
use tokio::runtime::Builder;
use c2pa::{Ingredient, Reader, Relationship};

use crate::{Error, Result, SignerInfo};

Expand All @@ -22,23 +21,7 @@ use crate::{Error, Result, SignerInfo};
#[allow(deprecated)]
pub fn read_file(path: &str, data_dir: Option<String>) -> Result<String> {
// Legacy JSON API: inherits thread-local settings set by c2pa_load_settings.
let mut reader = Reader::from_file(path).map_err(Error::from_c2pa_error)?;

#[cfg(target_arch = "wasm32")]
let runtime = Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| Error::Other(e.to_string()))?;

#[cfg(not(target_arch = "wasm32"))]
let runtime = Builder::new_multi_thread()
.enable_all()
.build()
.map_err(|e| Error::Other(e.to_string()))?;

runtime
.block_on(reader.post_validate_async(&CawgValidator {}))
.map_err(Error::from_c2pa_error)?;
let reader = Reader::from_file(path).map_err(Error::from_c2pa_error)?;

Ok(if let Some(dir) = data_dir {
let json = reader.json();
Expand Down
38 changes: 6 additions & 32 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ use std::{

use anyhow::{anyhow, bail, Context, Result};
use c2pa::{
format_from_path, identity::validator::CawgValidator, settings::Settings, Builder,
ClaimGeneratorInfo, Context as C2paContext, Error, Ingredient, ManifestDefinition, Reader,
Signer,
format_from_path, settings::Settings, Builder, ClaimGeneratorInfo, Context as C2paContext,
Error, Ingredient, ManifestDefinition, Reader, Signer,
};
use clap::{Parser, Subcommand};
use env_logger::Env;
Expand All @@ -40,11 +39,7 @@ use log::debug;
use serde::Deserialize;
use signer::SignConfig;
use tempfile::NamedTempFile;
#[cfg(not(target_os = "wasi"))]
use tokio::runtime::Runtime;
use url::Url;
#[cfg(target_os = "wasi")]
use wstd::runtime::block_on;

use crate::{
callback_signer::{CallbackSigner, CallbackSignerConfig, ExternalProcessRunner},
Expand Down Expand Up @@ -723,20 +718,6 @@ fn verify_fragmented(
Ok(readers)
}

// run cawg validation if supported
fn validate_cawg(reader: &mut Reader) -> Result<()> {
#[cfg(not(target_os = "wasi"))]
{
Runtime::new()?
.block_on(reader.post_validate_async(&CawgValidator {}))
.map_err(anyhow::Error::from)
}
#[cfg(target_os = "wasi")]
{
block_on(reader.post_validate_async(&CawgValidator {})).map_err(anyhow::Error::from)
}
}

fn reader_from_args(
asset_path: &Path,
args: &CliArgs,
Expand Down Expand Up @@ -1033,10 +1014,9 @@ fn main() -> Result<()> {
}

// generate a report on the output file
let mut reader = Reader::from_shared_context(&context)
let reader = Reader::from_shared_context(&context)
.with_file(&output)
.map_err(special_errs)?;
validate_cawg(&mut reader)?;
print_reader(&reader, args.detailed, args.crjson)?;
}
} else {
Expand Down Expand Up @@ -1064,10 +1044,9 @@ fn main() -> Result<()> {
File::create(output.join("ingredient.json"))?.write_all(&report.into_bytes())?;
println!("Ingredient report written to the directory {:?}", &output);
} else {
let mut reader = Reader::from_shared_context(&context)
let reader = Reader::from_shared_context(&context)
.with_file(path)
.map_err(special_errs)?;
validate_cawg(&mut reader)?;
reader.to_folder(&output)?;
let report = reader.to_string();
if args.detailed {
Expand All @@ -1087,19 +1066,14 @@ fn main() -> Result<()> {
fragments_glob: Some(fg),
}) = &args.command
{
let mut stores = verify_fragmented(path, fg, &context)?;
let stores = verify_fragmented(path, fg, &context)?;
if stores.len() == 1 {
validate_cawg(&mut stores[0])?;
println!("{}", stores[0]);
} else {
for store in &mut stores {
validate_cawg(store)?;
}
println!("{} Init manifests validated", stores.len());
}
} else {
let mut reader = reader_from_args(path, &args, &context)?;
validate_cawg(&mut reader)?;
let reader = reader_from_args(path, &args, &context)?;
print_reader(&reader, args.detailed, args.crjson)?;
}

Expand Down
Loading