diff --git a/.github/workflows/beta-preflight.yml b/.github/workflows/beta-preflight.yml index 5270c1c1d..3a75ba5fe 100644 --- a/.github/workflows/beta-preflight.yml +++ b/.github/workflows/beta-preflight.yml @@ -114,9 +114,8 @@ jobs: # doc tests. - name: Run doc tests (COVERAGE DISABLED) - run: - cargo test --workspace --all-features --doc - + run: cargo test --workspace --all-features --doc + # - name: Generate code coverage # env: # RUST_BACKTRACE: "1" @@ -223,7 +222,7 @@ jobs: run: cargo binstall -y wasm-bindgen-cli --version ${{ steps.wasm-bindgen-version.outputs.version }} - name: Run Wasm tests - run: cargo test -p c2pa --no-default-features --features rust_native_crypto,fetch_remote_manifests --target wasm32-unknown-unknown + run: cargo test -p c2pa --no-default-features --features rust_native_crypto, --target wasm32-unknown-unknown env: CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER: wasm-bindgen-test-runner WASM_BINDGEN_TEST_TIMEOUT: 60 diff --git a/.github/workflows/tier-1a.yml b/.github/workflows/tier-1a.yml index 7ef7cfe5c..9b8133116 100644 --- a/.github/workflows/tier-1a.yml +++ b/.github/workflows/tier-1a.yml @@ -382,7 +382,7 @@ jobs: run: cargo binstall -y wasm-bindgen-cli --version ${{ steps.wasm-bindgen-version.outputs.version }} - name: Run Wasm tests - run: cargo test -p c2pa --no-default-features --features rust_native_crypto,fetch_remote_manifests,http_reqwest --target wasm32-unknown-unknown + run: cargo test -p c2pa --no-default-features --features rust_native_crypto,http_reqwest --target wasm32-unknown-unknown env: CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER: wasm-bindgen-test-runner WASM_BINDGEN_TEST_TIMEOUT: 60 diff --git a/Makefile b/Makefile index 7e2aaa96d..50b2f80ef 100644 --- a/Makefile +++ b/Makefile @@ -23,20 +23,20 @@ clippy: cargo clippy --features="file_io" --all-targets -- -D warnings test-local: - cargo test --features="file_io, fetch_remote_manifests, add_thumbnails" --all-targets + cargo test --features="file_io, add_thumbnails" --all-targets test-wasm: - cd sdk && wasm-pack test --node -- --no-default-features --features="rust_native_crypto, fetch_remote_manifests, http_reqwest" + cd sdk && wasm-pack test --node -- --no-default-features --features="rust_native_crypto, http_reqwest" test-wasm-web: - cd sdk && wasm-pack test --chrome --headless -- --no-default-features --features="rust_native_crypto, fetch_remote_manifests, http_reqwest" + cd sdk && wasm-pack test --chrome --headless -- --no-default-features --features="rust_native_crypto, http_reqwest" # WASI testing requires upstream llvm clang (not XCode), wasmtime, and the target wasm32-wasip2 on the nightly toolchain test-wasi: ifeq ($(PLATFORM),mac) $(eval CC := /opt/homebrew/opt/llvm/bin/clang) endif - CC=$(CC) CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S cli -S http --dir ." cargo +nightly test --target wasm32-wasip2 -p c2pa --no-default-features --features="rust_native_crypto, file_io, fetch_remote_manifests, add_thumbnails, http_wasi, http_wstd" + CC=$(CC) CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S cli -S http --dir ." cargo +nightly test --target wasm32-wasip2 -p c2pa --no-default-features --features="rust_native_crypto, file_io, add_thumbnails, http_wasi, http_wstd" rm -r sdk/Users # Full local validation, build and test all features including wasm diff --git a/c2pa_c_ffi/Cargo.toml b/c2pa_c_ffi/Cargo.toml index d6bee24b8..4016bede9 100644 --- a/c2pa_c_ffi/Cargo.toml +++ b/c2pa_c_ffi/Cargo.toml @@ -26,7 +26,6 @@ pdf = ["c2pa/pdf"] [dependencies] c2pa = { path = "../sdk", version = "0.75.0", default-features = false, features = [ "add_thumbnails", - "fetch_remote_manifests", "file_io", "pdf", "default_http", diff --git a/c2pa_c_ffi/src/c_api.rs b/c2pa_c_ffi/src/c_api.rs index 139615fb6..7316107a5 100644 --- a/c2pa_c_ffi/src/c_api.rs +++ b/c2pa_c_ffi/src/c_api.rs @@ -2133,6 +2133,19 @@ mod tests { #[test] fn test_c2pa_reader_remote_url() { + let settings = serde_json::json!( { + "verify": { + "remote_manifest_fetch": true + } + }); + let result = unsafe { + c2pa_load_settings( + CString::new(settings.to_string()).unwrap().as_ptr(), + c"json".as_ptr(), + ) + }; + assert_eq!(result, 0); + let mut stream = TestC2paStream::new(include_bytes!(fixture_path!("cloud.jpg")).to_vec()) .into_c_stream(); diff --git a/cli/Cargo.toml b/cli/Cargo.toml index fd51a64fa..30f13c60e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -29,7 +29,6 @@ networking = [ anyhow = "1.0" atree = "0.5.2" c2pa = { path = "../sdk", version = "0.75.0", features = [ - "fetch_remote_manifests", "file_io", "add_thumbnails", "pdf", diff --git a/cli/src/main.rs b/cli/src/main.rs index 505830d07..4b3e13b8d 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -389,6 +389,15 @@ fn blocking_get(url: &str) -> Result { } fn configure_sdk(args: &CliArgs) -> Result<()> { + // Enable remote manifest fetching for backwards compatibility. + Settings::from_toml( + &toml::toml! { + [verify] + remote_manifest_fetch = true + } + .to_string(), + )?; + if args.settings.exists() { Settings::from_file(&args.settings)?; } diff --git a/docs/support-tiers.md b/docs/support-tiers.md index 41bf1dc02..5547d1f93 100644 --- a/docs/support-tiers.md +++ b/docs/support-tiers.md @@ -35,7 +35,7 @@ These requirements are enforced in the [Tier 1A workflow](/.github/workflows/tie ### Tier 1A for c2pa-rs * **Ubuntu:** `x86_64-unknown-linux-gnu`, Rust `stable`, `all` features, `openssl` | `rust_native_crypto`, `glibc` -* **Wasm:** `wasm32-unknown-unknown`, Rust `stable`, `fetch_remote_manifests` feature, `rust_native_crypto` +* **Wasm:** `wasm32-unknown-unknown`, Rust `stable`, feature, `rust_native_crypto` * **WASI:** `wasm32-wasip2`, Rust `nightly-2025-08-25`, `all` features ### Tier 1A for c2pa-c-ffi diff --git a/docs/usage.md b/docs/usage.md index f39de6e7b..883e0c1ed 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -40,7 +40,6 @@ You can enable any of the following features: - **openssl** *(enabled by default)*: Use the vendored `openssl` implementation for cryptography. - **rust_native_crypto**: Use Rust native cryptography. - **add_thumbnails**: Adds the [`image`](https://github.com/image-rs/image) crate to enable auto-generated thumbnails, if possible and enabled in settings. -- **fetch_remote_manifests**: Fetches remote manifests over the network when no embedded manifest is present and that option is enabled in settings. - **file_io**: Enables APIs that use file system I/O. - **json_schema**: Adds the [`schemars`](https://github.com/GREsau/schemars) crate to derive JSON schemas for JSON-compatible structs. - **pdf**: Enables basic PDF read support. @@ -58,6 +57,7 @@ You can enable any of the following features: The following features are no longer supported: +* **fetch_remote_manifests**. Fetching remote manifests can now be enabled with the `verify.remote_manifest_fetch` setting. * **v1_api**. The old API that this enabled has been removed. * **serialize_thumbnails**. Thumbnails can be serialized by accessing resources directly. @@ -156,7 +156,7 @@ fn main() -> Result<()> { let toml = r#" [verify] verify_after_sign = true - + [core] allowed_network_hosts = ["example.com"] "#; @@ -173,7 +173,7 @@ use c2pa::{Context, Settings, Result}; fn main() -> Result<()> { let mut settings = Settings::default(); settings.verify.verify_after_sign = true; - + let context = Context::new().with_settings(settings)?; Ok(()) } @@ -191,12 +191,12 @@ fn main() -> Result<()> { // Configure context let context = Context::new() .with_settings(r#"{"verify": {"remote_manifest_fetch": false}}"#)?; - + // Create reader with context let stream = File::open("path/to/image.jpg")?; let reader = Reader::from_context(context) .with_stream("image/jpeg", stream)?; - + println!("{}", reader.json()); Ok(()) } @@ -220,16 +220,16 @@ fn main() -> Result<()> { "intent": "edit" } }))?; - + // Create builder with context and inline JSON definition let mut builder = Builder::from_context(context) .with_definition(json!({"title": "My Image"}))?; - + // Save with automatic signer from context let mut source = std::fs::File::open("source.jpg")?; let mut dest = Cursor::new(Vec::new()); builder.save_to_stream("image/jpeg", &mut source, &mut dest)?; - + Ok(()) } ``` @@ -265,15 +265,15 @@ fn main() -> Result<()> { // Configure context with signer settings let context = Context::new() .with_settings(include_str!("config.json"))?; - + let mut builder = Builder::from_context(context) .with_definition(json!({"title": "My Image"}))?; - + // Signer is created automatically from context's settings let mut source = std::fs::File::open("source.jpg")?; let mut dest = std::fs::File::create("signed.jpg")?; builder.save_to_stream("image/jpeg", &mut source, &mut dest)?; - + Ok(()) } ``` @@ -293,13 +293,13 @@ fn main() -> Result<()> { SigningAlg::Ps256, None )?; - + // Set it on the context let context = Context::new().with_signer(signer); - + // Later retrieve it let signer_ref = context.signer()?; - + Ok(()) } ``` diff --git a/make_test_images/Cargo.toml b/make_test_images/Cargo.toml index c34646a2c..8edd11193 100644 --- a/make_test_images/Cargo.toml +++ b/make_test_images/Cargo.toml @@ -13,7 +13,6 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } [dependencies] anyhow = "1.0.40" c2pa = { path = "../sdk", version = "0.75.0", features = [ - "fetch_remote_manifests", "file_io", "add_thumbnails", "pdf", diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 5e1c99007..45b16f999 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -31,7 +31,6 @@ rustdoc-args = ["--cfg", "docsrs"] default = ["openssl", "default_http"] add_thumbnails = ["image"] file_io = [] -fetch_remote_manifests = ["dep:wasi"] json_schema = ["dep:schemars"] openssl = [ "dep:openssl", diff --git a/sdk/src/builder.rs b/sdk/src/builder.rs index 74d0b64a5..c8f2baaa6 100644 --- a/sdk/src/builder.rs +++ b/sdk/src/builder.rs @@ -3660,7 +3660,6 @@ mod tests { /// example of creating a builder directly with a [`ManifestDefinition`] #[c2pa_test_async] /// test if the sdk can add a cloud ingredient retrieved from a stream and a cloud manifest - // This works with or without the fetch_remote_manifests feature async fn test_add_cloud_ingredient() { crate::settings::reset_default_settings().ok(); diff --git a/sdk/src/ingredient.rs b/sdk/src/ingredient.rs index de019ba0d..604666cca 100644 --- a/sdk/src/ingredient.rs +++ b/sdk/src/ingredient.rs @@ -1793,7 +1793,6 @@ mod tests { ); } - #[cfg(feature = "fetch_remote_manifests")] #[c2pa_test_async] async fn test_jpg_cloud_from_memory() { crate::settings::set_settings_value("verify.verify_trust", false).unwrap(); @@ -1815,11 +1814,10 @@ mod tests { assert_eq!(ingredient.validation_status(), None); } - #[cfg(not(any(feature = "fetch_remote_manifests", feature = "file_io")))] #[c2pa_test_async] - async fn test_jpg_cloud_from_memory_no_file_io() { + async fn test_jpg_cloud_from_memory_no_remote_fetch() { crate::settings::set_settings_value("verify.verify_trust", false).unwrap(); - crate::settings::set_settings_value("verify.remote_manifest_fetch", true).unwrap(); + crate::settings::set_settings_value("verify.remote_manifest_fetch", false).unwrap(); let image_bytes = include_bytes!("../tests/fixtures/cloud.jpg"); let format = "image/jpeg"; @@ -2065,7 +2063,6 @@ mod tests_file_io { } #[test] - #[cfg(feature = "fetch_remote_manifests")] fn test_jpg_cloud_failure() { let ap = fixture_path("cloudx.jpg"); let ingredient = Ingredient::from_file(ap).expect("from_file"); diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index b29ca0f07..03051c2b0 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -98,7 +98,6 @@ //! - **openssl** *(enabled by default)*: Use the vendored `openssl` implementation for cryptography. //! - **rust_native_crypto**: Use Rust native cryptography. //! - **add_thumbnails**: Adds the [`image`](https://github.com/image-rs/image) crate to enable auto-generated thumbnails, if possible and enabled in settings. -//! - **fetch_remote_manifests**: Fetches remote manifests over the network when no embedded manifest is present and that option is enabled in settings. //! - **file_io**: Enables APIs that use filesystem I/O. //! - **json_schema**: Adds the [`schemars`](https://github.com/GREsau/schemars) crate to derive JSON schemas for JSON-compatible structs. //! - **pdf**: Enables basic PDF read support. diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 3a2622370..da4ae1557 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -243,7 +243,7 @@ impl Reader { #[cfg(feature = "file_io")] /// Add manifest store from a file to the [`Reader`]. - /// If the `fetch_remote_manifests` feature is enabled, and the asset refers to a remote manifest, the function fetches a remote manifest. + /// If the [`Verify::remote_manifest_fetch`] setting is enabled, and the asset refers to a remote manifest, the function fetches a remote manifest. /// /// NOTE: If the file does not have a manifest store, the function will check for a sidecar manifest with the same base file name and a .c2pa extension. /// @@ -270,6 +270,7 @@ impl Reader { /// [CAWG identity] assertions require async calls for validation. /// /// [CAWG identity]: https://cawg.io/identity/ + /// [`Verify::remote_manifest_fetch`]: crate::settings::Verify::remote_manifest_fetch #[async_generic] pub fn with_file>(mut self, path: P) -> Result { let path = path.as_ref(); @@ -332,7 +333,7 @@ impl Reader { } /// Create a manifest store [`Reader`] from a file. - /// If the `fetch_remote_manifests` feature is enabled, and the asset refers to a remote manifest, the function fetches a remote manifest. + /// If the `verify.remote_manifest_fetch` setting is enabled, and the asset refers to a remote manifest, the function fetches a remote manifest. /// /// NOTE: If the file does not have a manifest store, the function will check for a sidecar manifest with the same base file name and a .c2pa extension. /// @@ -1401,11 +1402,10 @@ pub mod tests { use std::io::Cursor; use super::*; - use crate::utils::test::test_context; + use crate::{utils::test::test_context, Settings}; const IMAGE_COMPLEX_MANIFEST: &[u8] = include_bytes!("../tests/fixtures/CACAE-uri-CA.jpg"); const IMAGE_WITH_MANIFEST: &[u8] = include_bytes!("../tests/fixtures/CA.jpg"); - #[cfg(feature = "fetch_remote_manifests")] const IMAGE_WITH_REMOTE_MANIFEST: &[u8] = include_bytes!("../tests/fixtures/cloud.jpg"); const IMAGE_WITH_INGREDIENT_MANIFEST: &[u8] = include_bytes!("../tests/fixtures/CACA.jpg"); @@ -1461,8 +1461,15 @@ pub mod tests { } #[test] - #[cfg(feature = "fetch_remote_manifests")] fn test_reader_remote_url() -> Result<()> { + Settings::from_toml( + &toml::toml! { + [verify] + remote_manifest_fetch = true + } + .to_string(), + )?; + let reader = Reader::from_stream("image/jpeg", Cursor::new(IMAGE_WITH_REMOTE_MANIFEST))?; let remote_url = reader.remote_url(); assert_eq!(remote_url, Some("https://cai-manifests.adobe.com/manifests/adobe-urn-uuid-5f37e182-3687-462e-a7fb-573462780391")); diff --git a/sdk/src/settings/mod.rs b/sdk/src/settings/mod.rs index 5261913ca..d7ee4ef0d 100644 --- a/sdk/src/settings/mod.rs +++ b/sdk/src/settings/mod.rs @@ -343,11 +343,7 @@ pub struct Verify { /// - Constructing a [`Reader`] /// - Adding an [`Ingredient`] to the [`Builder`] /// - /// The default value is true. - /// - ///
- /// This setting is only applicable if the crate is compiled with the `fetch_remote_manifests` feature. - ///
+ /// The default value is false. /// /// [`Reader`]: crate::Reader /// [`Ingredient`]: crate::Ingredient @@ -376,7 +372,7 @@ impl Default for Verify { verify_trust: true, verify_timestamp_trust: !cfg!(test), // verify timestamp trust unless in test mode ocsp_fetch: false, - remote_manifest_fetch: true, + remote_manifest_fetch: false, skip_ingredient_conflict_resolution: false, strict_v1_validation: false, } @@ -1067,7 +1063,7 @@ pub mod tests { // test updating values Settings::set_thread_local_value("core.merkle_tree_chunk_size_in_kb", 10).unwrap(); - Settings::set_thread_local_value("verify.remote_manifest_fetch", false).unwrap(); + Settings::set_thread_local_value("verify.remote_manifest_fetch", true).unwrap(); Settings::set_thread_local_value("builder.thumbnail.enabled", false).unwrap(); Settings::set_thread_local_value( "trust.user_anchors", @@ -1079,7 +1075,7 @@ pub mod tests { get_settings_value::("core.merkle_tree_chunk_size_in_kb").unwrap(), 10 ); - assert!(!get_settings_value::("verify.remote_manifest_fetch").unwrap()); + assert!(get_settings_value::("verify.remote_manifest_fetch").unwrap()); assert!(!get_settings_value::("builder.thumbnail.enabled").unwrap()); assert_eq!( get_settings_value::>("trust.user_anchors").unwrap(), diff --git a/sdk/src/store.rs b/sdk/src/store.rs index 1be44a815..8a22ccbba 100644 --- a/sdk/src/store.rs +++ b/sdk/src/store.rs @@ -91,7 +91,6 @@ use crate::{ }; const MANIFEST_STORE_EXT: &str = "c2pa"; // file extension for external manifests -#[cfg(feature = "fetch_remote_manifests")] const DEFAULT_MANIFEST_RESPONSE_SIZE: usize = 10 * 1024 * 1024; // 10 MB pub(crate) struct ManifestHashes { @@ -3421,7 +3420,6 @@ impl Store { } // fetch remote manifest if possible - #[cfg(feature = "fetch_remote_manifests")] #[async_generic] fn fetch_remote_manifest(url: &str, context: &Context) -> Result> { //const MANIFEST_CONTENT_TYPE: &str = "application/x-c2pa-manifest-store"; // todo verify once these are served @@ -3473,22 +3471,16 @@ impl Store { fn handle_remote_manifest(ext_ref: &str, _context: &Context) -> Result> { // verify provenance path is remote url if Store::is_valid_remote_url(ext_ref) { - #[cfg(feature = "fetch_remote_manifests")] - { - // Everything except browser wasm if fetch_remote_manifests is enabled - if _context.settings().verify.remote_manifest_fetch { - if _sync { - Store::fetch_remote_manifest(ext_ref, _context) - } else { - Store::fetch_remote_manifest_async(ext_ref, _context).await - } + // Everything except browser wasm if fetch_remote_manifests is enabled + if _context.settings().verify.remote_manifest_fetch { + if _sync { + Store::fetch_remote_manifest(ext_ref, _context) } else { - Err(Error::RemoteManifestUrl(ext_ref.to_owned())) + Store::fetch_remote_manifest_async(ext_ref, _context).await } + } else { + Err(Error::RemoteManifestUrl(ext_ref.to_owned())) } - - #[cfg(not(feature = "fetch_remote_manifests"))] - Err(Error::RemoteManifestUrl(ext_ref.to_owned())) } else { Err(Error::JumbfNotFound) } diff --git a/sdk/tests/test_reader.rs b/sdk/tests/test_reader.rs index d3d77f9c4..a3ee2f9e0 100644 --- a/sdk/tests/test_reader.rs +++ b/sdk/tests/test_reader.rs @@ -71,9 +71,16 @@ fn test_reader_xca_jpg() -> Result<()> { compare_to_known_good(&reader, "XCA.json") } -#[cfg(feature = "fetch_remote_manifests")] #[c2pa_test_async] async fn test_reader_remote_url_async() -> Result<()> { + Settings::from_toml( + &toml::toml! { + [verify] + remote_manifest_fetch = true + } + .to_string(), + )?; + let reader = Reader::from_stream_async( "image/jpeg", std::io::Cursor::new(include_bytes!("./fixtures/cloud.jpg")),