diff --git a/Cargo.lock b/Cargo.lock index ec9b0e2cd..7d7e0e9d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3411,7 +3411,7 @@ dependencies = [ "bytes", "getrandom", "rand", - "ring 0.17.9", + "ring", "rustc-hash", "rustls", "rustls-pki-types", @@ -3716,34 +3716,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c601484456988d75017d86700d3743b949c21cdc7399f940c75e34680d185c5" -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" dependencies = [ "cc", "cfg-if", "getrandom", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -3841,7 +3824,7 @@ checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "log", "once_cell", - "ring 0.17.9", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3872,7 +3855,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.9", + "ring", "rustls-pki-types", "untrusted", ] diff --git a/Makefile b/Makefile index 85c41b35c..385dd97bc 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,8 @@ test-wasm-web: # WASI testing requires the WASI SDK https://github.com/WebAssembly/wasi-sdk installed in /opt, # wasmtime, and the target wasm32-wasip2 on the nightly toolchain test-wasi: - CC=/opt/wasi-sdk/bin/clang CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S common --dir ." cargo +nightly test --target wasm32-wasip2 -p c2pa -p c2pa-crypto + CC=/opt/wasi-sdk/bin/clang CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S cli -S http --dir ." cargo +nightly test --target wasm32-wasip2 -p c2pa -p c2pa-crypto --all-features + rm -r sdk/Users # Full local validation, build and test all features including wasm # Run this before pushing a PR to pre-validate diff --git a/sdk/src/error.rs b/sdk/src/error.rs index 6abedfc07..49d4892ff 100644 --- a/sdk/src/error.rs +++ b/sdk/src/error.rs @@ -191,10 +191,10 @@ pub enum Error { #[error("required JUMBF box not found")] JumbfBoxNotFound, - #[error("could not fetch the remote manifest")] + #[error("could not fetch the remote manifest {0}")] RemoteManifestFetch(String), - #[error("must fetch remote manifests from url")] + #[error("must fetch remote manifests from url {0}")] RemoteManifestUrl(String), #[error("stopped because of logged error")] diff --git a/sdk/src/store.rs b/sdk/src/store.rs index 5fa7f1ce5..6af9f855f 100644 --- a/sdk/src/store.rs +++ b/sdk/src/store.rs @@ -3286,47 +3286,48 @@ impl Store { }; //const MANIFEST_CONTENT_TYPE: &str = "application/x-c2pa-manifest-store"; // todo verify once these are served - //const DEFAULT_MANIFEST_RESPONSE_SIZE: usize = 10 * 1024 * 1024; // 10 MB + const DEFAULT_MANIFEST_RESPONSE_SIZE: usize = 10 * 1024 * 1024; // 10 MB let parsed_url = Url::parse(url) .map_err(|e| Error::RemoteManifestFetch(format!("invalid URL: {}", e)))?; - let path_with_query = parsed_url[url::Position::BeforeHost..].to_string(); + let authority = parsed_url.authority(); + let path_with_query = parsed_url[url::Position::AfterPort..].to_string(); + let scheme = match parsed_url.scheme() { + "http" => Scheme::Http, + "https" => Scheme::Https, + _ => { + return Err(Error::RemoteManifestFetch( + "unsupported URL scheme".to_string(), + )) + } + }; let request = OutgoingRequest::new(Fields::new()); request.set_path_with_query(Some(&path_with_query)).unwrap(); - request.set_scheme(Some(&Scheme::Https)).unwrap(); + request.set_authority(Some(&authority)).unwrap(); + request.set_scheme(Some(&scheme)).unwrap(); match outgoing_handler::handle(request, None) { Ok(resp) => { resp.subscribe().block(); let response = resp .get() - .expect("HTTP request response missing") - .expect("HTTP request response requested more than once") - .expect("HTTP request failed"); + .ok_or(Error::RemoteManifestFetch( + "HTTP request response missing".to_string(), + ))? + .map_err(|_| { + Error::RemoteManifestFetch( + "HTTP request response requested more than once".to_string(), + ) + })? + .map_err(|_| Error::RemoteManifestFetch("HTTP request failed".to_string()))?; if response.status() == 200 { - let raw_header = response.headers().get("Content-Length"); - if raw_header.first().map(|val| val.is_empty()).unwrap_or(true) { - return Err(Error::RemoteManifestFetch( - "url returned no content length".to_string(), - )); - } - let str_parsed_header = match std::str::from_utf8(raw_header.first().unwrap()) { - Ok(s) => s, - Err(e) => { - return Err(Error::RemoteManifestFetch(format!( - "error parsing content length header: {}", - e - ))) - } - }; - let content_length: usize = match str_parsed_header.parse() { - Ok(s) => s, - Err(e) => { - return Err(Error::RemoteManifestFetch(format!( - "error parsing content length header: {}", - e - ))) - } - }; + let content_length: usize = response + .headers() + .get("Content-Length") + .first() + .and_then(|val| if val.is_empty() { None } else { Some(val) }) + .and_then(|val| std::str::from_utf8(val).ok()) + .and_then(|str_parsed_header| str_parsed_header.parse().ok()) + .unwrap_or(DEFAULT_MANIFEST_RESPONSE_SIZE); let body = { let mut buf = Vec::with_capacity(content_length); let response_body = response diff --git a/sdk/src/utils/test.rs b/sdk/src/utils/test.rs index c1f904fd2..511dd94f0 100644 --- a/sdk/src/utils/test.rs +++ b/sdk/src/utils/test.rs @@ -389,107 +389,6 @@ impl crate::signer::RemoteSigner for TempRemoteSigner { } } -/* todo: This test should be replaced by a rust_native signer if desired to sign from wasm -#[cfg(target_arch = "wasm32")] -struct WebCryptoSigner { - signing_alg: SigningAlg, - signing_alg_name: String, - certs: Vec>, - key: Vec, -} - -#[cfg(target_arch = "wasm32")] -impl WebCryptoSigner { - pub fn new(alg: &str, cert: &str, key: &str) -> Self { - static START_CERTIFICATE: &str = "-----BEGIN CERTIFICATE-----"; - static END_CERTIFICATE: &str = "-----END CERTIFICATE-----"; - static START_KEY: &str = "-----BEGIN PRIVATE KEY-----"; - static END_KEY: &str = "-----END PRIVATE KEY-----"; - - let mut name = alg.to_owned().to_uppercase(); - name.insert(2, '-'); - - let key = key - .replace("\n", "") - .replace(START_KEY, "") - .replace(END_KEY, ""); - let key = c2pa_crypto::base64::decode(&key).unwrap(); - - let certs = cert - .replace("\n", "") - .replace(START_CERTIFICATE, "") - .split(END_CERTIFICATE) - .map(|x| c2pa_crypto::base64::decode(x).unwrap()) - .collect(); - - Self { - signing_alg: alg.parse().unwrap(), - signing_alg_name: name, - certs, - key, - } - } -} - -#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] -#[async_trait::async_trait(?Send)] -impl AsyncSigner for WebCryptoSigner { - fn alg(&self) -> SigningAlg { - self.signing_alg - } - - fn certs(&self) -> Result>> { - Ok(self.certs.clone()) - } - - async fn sign(&self, claim_bytes: Vec) -> crate::error::Result> { - use c2pa_crypto::raw_signature::webcrypto::WindowOrWorker; - use js_sys::{Array, Object, Reflect, Uint8Array}; - use wasm_bindgen_futures::JsFuture; - use web_sys::CryptoKey; - let context = WindowOrWorker::new().unwrap(); - let crypto = context.subtle_crypto().unwrap(); - - let mut data = claim_bytes.clone(); - let promise = crypto - .digest_with_str_and_u8_array("SHA-256", &mut data) - .unwrap(); - let result = JsFuture::from(promise).await.unwrap(); - let mut digest = Uint8Array::new(&result).to_vec(); - - let key = Uint8Array::new_with_length(self.key.len() as u32); - key.copy_from(&self.key); - let usages = Array::new(); - usages.push(&"sign".into()); - let alg = Object::new(); - Reflect::set(&alg, &"name".into(), &"ECDSA".into()).unwrap(); - Reflect::set(&alg, &"namedCurve".into(), &"P-256".into()).unwrap(); - - let promise = crypto - .import_key_with_object("pkcs8", &key, &alg, true, &usages) - .unwrap(); - let key: CryptoKey = JsFuture::from(promise).await.unwrap().into(); - - let alg = Object::new(); - Reflect::set(&alg, &"name".into(), &"ECDSA".into()).unwrap(); - Reflect::set(&alg, &"hash".into(), &"SHA-256".into()).unwrap(); - let promise = crypto - .sign_with_object_and_u8_array(&alg, &key, &mut digest) - .unwrap(); - let result = JsFuture::from(promise).await.unwrap(); - Ok(Uint8Array::new(&result).to_vec()) - } - - fn reserve_size(&self) -> usize { - 10000 - } - - async fn send_timestamp_request(&self, _: &[u8]) -> Option>> { - None - } -} -*/ - /// Create a [`RemoteSigner`] instance that can be used for testing purposes. /// /// # Returns diff --git a/sdk/tests/integration.rs b/sdk/tests/integration.rs index 22577ae70..2746964fd 100644 --- a/sdk/tests/integration.rs +++ b/sdk/tests/integration.rs @@ -13,7 +13,6 @@ /// Complete functional integration test with parent and ingredients. // Isolate from wasm by wrapping in module. - #[cfg(feature = "file_io")] mod integration_1 { use std::{io, path::PathBuf}; diff --git a/sdk/tests/test_builder.rs b/sdk/tests/test_builder.rs index a4dad8106..9f801b095 100644 --- a/sdk/tests/test_builder.rs +++ b/sdk/tests/test_builder.rs @@ -21,7 +21,7 @@ mod common; use common::{compare_stream_to_known_good, fixtures_path, test_signer}; #[test] -#[ignore] // TODO: Test does not pass in WASI or native +#[cfg(all(feature = "add_thumbnails", feature = "file_io"))] fn test_builder_ca_jpg() -> Result<()> { let manifest_def = std::fs::read_to_string(fixtures_path("simple_manifest.json"))?; let mut builder = Builder::from_json(&manifest_def)?; diff --git a/sdk/tests/v2_api_integration.rs b/sdk/tests/v2_api_integration.rs index d26bcb195..1b0cbff49 100644 --- a/sdk/tests/v2_api_integration.rs +++ b/sdk/tests/v2_api_integration.rs @@ -147,10 +147,13 @@ mod integration_v2 { dest }; - // write dest to file for debugging - let debug_path = format!("{}/../target/v2_test.jpg", env!("CARGO_MANIFEST_DIR")); - std::fs::write(debug_path, dest.get_ref())?; - dest.rewind()?; + #[cfg(not(target_os = "wasi"))] + { + // write dest to file for debugging + let debug_path = format!("{}/../target/v2_test.jpg", env!("CARGO_MANIFEST_DIR")); + std::fs::write(debug_path, dest.get_ref())?; + dest.rewind()?; + } let reader = Reader::from_stream(format, &mut dest)?;