Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
44d8faa
Spike: Retrofit io_utils call sites
scouten-adobe Sep 23, 2025
e509d31
Spike: Adapt verify_cose
scouten-adobe Sep 23, 2025
2a39a23
Spike: Retrofit Store::handle_remote_manifest
scouten-adobe Sep 23, 2025
73aead9
Spike: Retrofit sign_claim
scouten-adobe Sep 23, 2025
296aa51
Spike: Push farther up the Store API chain
scouten-adobe Sep 23, 2025
ffd8015
Spike: Push Settings up through Ingredient API chain
scouten-adobe Sep 24, 2025
de83d42
Spike: Push settings up through Reader API
scouten-adobe Sep 24, 2025
5e638e8
Spike: Push settings farther up Builder and Ingredient API chains
scouten-adobe Sep 24, 2025
b5093a4
Spike: Push settings up through thumbnail utils
scouten-adobe Sep 24, 2025
023fde2
Switch check_ingredient_trust to passed settings
scouten-adobe Sep 24, 2025
427c7e1
Plumb settings through core OCSP logic
scouten-adobe Sep 24, 2025
d3a078f
Plumb settings through Store's OCSP logic
scouten-adobe Sep 24, 2025
eb40a9f
One more reference in ingredient
scouten-adobe Sep 24, 2025
ae3aee6
Plumb settings through add_auto_actions_assertions_settings
scouten-adobe Sep 24, 2025
929a396
Plumb settings through more of Builder
scouten-adobe Sep 24, 2025
899b0ab
Remove last references to get_settings_value in Builder
scouten-adobe Sep 24, 2025
fbe8976
Remove remaining references to get_settings_value in Store
scouten-adobe Sep 24, 2025
c4e255c
Remove remaining references to get_settings_value in Reader
scouten-adobe Sep 24, 2025
3a4d500
Remove remaining references to get_settings_value in Claim
scouten-adobe Sep 24, 2025
68ba524
Remove remaining references to get_settings_value from IdentityAssertion
scouten-adobe Sep 24, 2025
fce4aa8
Remove remaining get_settings_value references from time_stamp code
scouten-adobe Sep 24, 2025
beecb93
Remove remaining references to get_settings_value outside Settings mod
scouten-adobe Sep 24, 2025
81efbdc
Move Settings::get_value to private
scouten-adobe Sep 24, 2025
3da6b20
Move Settings::reset to private
scouten-adobe Sep 24, 2025
c3de5a0
Merge branch 'main' into scouten/settings-not-thread-local
scouten-adobe Sep 24, 2025
4608f62
Clippy
scouten-adobe Sep 24, 2025
8941f2c
cargo fmt
scouten-adobe Sep 24, 2025
4f6e63f
Fix some Wasm build errors
scouten-adobe Sep 24, 2025
913172d
Merge branch 'main' into scouten/settings-not-thread-local
scouten-adobe Sep 24, 2025
eead715
Fix one more Wasm build error
scouten-adobe Sep 24, 2025
efdae9f
cargo fmt
scouten-adobe Sep 24, 2025
31c9dc6
Make Settings::reset() pub(crate) for now
scouten-adobe Sep 24, 2025
953e690
Retrofit Builder::to_claim()
scouten-adobe Sep 24, 2025
7f9e282
Retrofit Builder::add_actions_assertion_settings
scouten-adobe Sep 24, 2025
c3eb1ca
Retrofit Builder::add_auto_actions_assertions_settings
scouten-adobe Sep 24, 2025
7192282
Retrofit Builder::to_store
scouten-adobe Sep 24, 2025
8296652
Retrofit Claim::verify_actions
scouten-adobe Sep 24, 2025
c480a42
Retrofit Claim::verify_internal
scouten-adobe Sep 24, 2025
310ebd1
Retrofit cose_sign::signing_cert_valid
scouten-adobe Sep 24, 2025
e21b6ac
Retrofit cose_sign::cose_sign
scouten-adobe Sep 24, 2025
24538a7
Retrofit Ingredient::from_file_impl
scouten-adobe Sep 24, 2025
b937db4
Merge branch 'main' into scouten/settings-not-thread-local
scouten-adobe Sep 25, 2025
eb2477c
Clippy
scouten-adobe Sep 25, 2025
bd3d3e4
Retrofit Store::new_with_label
scouten-adobe Sep 25, 2025
e58780a
Retrofit Store::new
scouten-adobe Sep 25, 2025
eb170fd
Retrofit Store::get_ocsp_status
scouten-adobe Sep 25, 2025
93ece88
Retrofit Store::get_manifest_labels_for_ocsp
scouten-adobe Sep 25, 2025
230e36c
Retrofit Store::sign_claim
scouten-adobe Sep 25, 2025
dd5c69e
Retrofit Store::from_jumbf
scouten-adobe Sep 25, 2025
c0e6783
Split out public API revisions to TO DO #1454
scouten-adobe Sep 25, 2025
f196ae1
Retrofit Builder::maybe_add_thumbnail
scouten-adobe Sep 25, 2025
0122490
Retrofit Store::iingredient_checks
scouten-adobe Sep 25, 2025
5724172
Retrofit Store::generate_bmff_data_hash_for_stream
scouten-adobe Sep 25, 2025
29116b8
Retrofit Store::get_data_hashed_embeddable_manifest
scouten-adobe Sep 25, 2025
07e826a
Retrofit Store::get_data_hashed_embeddable_manifest_async
scouten-adobe Sep 25, 2025
e974cea
Merge branch 'main' into scouten/settings-not-thread-local
scouten-adobe Sep 30, 2025
39544ef
Retrofit Store::get_box_hashed_embeddable_manifest
scouten-adobe Sep 30, 2025
d8a2881
Retrofit Store::get_box_hashed_embeddable_manifest_async
scouten-adobe Sep 30, 2025
fd4edee
Retrofit Store::start_save_bmff_fragmented
scouten-adobe Sep 30, 2025
118640d
Retrofit Store::save_to_strema(_async) and ::save_to_bmff_fragmented
scouten-adobe Sep 30, 2025
2fed088
Retrofit Store::start_save_stream
scouten-adobe Sep 30, 2025
434938a
Retrofit Store::verify_from_path
scouten-adobe Sep 30, 2025
1c7cb74
Retrofit Store::from_manifest_data_and_stream
scouten-adobe Sep 30, 2025
3607330
Retrofit Store::load_from_file_and_fragments
scouten-adobe Sep 30, 2025
3ac02b0
Retrofit Store::load_ingredient_to_claim
scouten-adobe Sep 30, 2025
d603795
Clippy
scouten-adobe Sep 30, 2025
1d4f8d6
Retrofit Store::test_async_dynamic_assertions
scouten-adobe Oct 1, 2025
924af31
Retrofit BmffHash::create_merkle_map_for_mdat_box
scouten-adobe Oct 1, 2025
263e13d
Retrofit verify_time_stamp
scouten-adobe Oct 1, 2025
0268023
Retrofit Store::get_store_validation_info
scouten-adobe Oct 1, 2025
98222b5
TO REVIEW: Can we avoid passing settings into the BmffIO implementati…
scouten-adobe Oct 1, 2025
45e165f
Retrofit Ingredient::add_to_claim
scouten-adobe Oct 1, 2025
f3352bf
Retrofit parse_and_validate_sigtst
scouten-adobe Oct 1, 2025
b0bf042
TO REVIEW: I don't think default_rfc3161_request needs to have Settin…
scouten-adobe Oct 1, 2025
1653c4f
Clippy
scouten-adobe Oct 1, 2025
350f946
Merge branch 'main' into scouten/settings-not-thread-local
scouten-adobe Oct 1, 2025
9be45f6
Fix up some Wasm build errors
scouten-adobe Oct 1, 2025
42057d5
feat: impl prototype of `ReaderBuilder`
ok-nick Sep 24, 2025
10b2f6a
fix: use validation state from reader constructor
ok-nick Oct 3, 2025
9551bcf
refactor: simplify Reader
ok-nick Oct 3, 2025
b2c687f
fix: private `Ingredient::maybe_add_thumbnail` and clean up todos
ok-nick Oct 3, 2025
9f2cb0c
fix: `Store::add with_settings` and `Store::from_jumbf_with_settings`…
ok-nick Oct 3, 2025
ff0b160
fix: stack overflow when constructing store
ok-nick Oct 6, 2025
4d6fb4d
style: fix clippy lints
ok-nick Oct 6, 2025
07dedf9
fix: remove ingredient new public API for now
ok-nick Oct 6, 2025
779c1fe
style: remove todo to add settings to identity assertion (deferred to…
ok-nick Oct 6, 2025
4e605d0
fix: remove public API changes to builder for now
ok-nick Oct 6, 2025
7aeb9c3
style: remove todos in claim
ok-nick Oct 6, 2025
269fa8f
Revert cosmetic changes to bmff_io.rs
scouten-adobe Oct 10, 2025
a253d21
Merge remote-tracking branch 'origin' into scouten/settings-not-threa…
ok-nick Oct 13, 2025
9c4c34d
fix: settings parameters affected by merge and clippy lints
ok-nick Oct 13, 2025
6cd520b
docs: remove review note
ok-nick Oct 13, 2025
ba61dd0
Merge branch 'scouten/settings-not-thread-local', remote-tracking bra…
ok-nick Oct 14, 2025
18a9ccc
feat: pass settings down the store and add async cases
ok-nick Oct 14, 2025
8a50921
Merge branch 'main' into scouten/settings-not-thread-local
ok-nick Oct 14, 2025
756011f
Merge branch 'scouten/settings-not-thread-local' into ok-nick/setting…
ok-nick Oct 14, 2025
e8f1c12
Merge branch 'main' into scouten/settings-not-thread-local
ok-nick Oct 14, 2025
76a7523
fix: revert Reader::validation_state change
ok-nick Oct 14, 2025
70e49f4
docs: make note of potential refactors
ok-nick Oct 14, 2025
dbe0d34
fix: plumb settings through timestamp
ok-nick Oct 14, 2025
984bb2f
feat: add Store::load_fragments_from_stream_async
ok-nick Oct 15, 2025
c3fb701
feat: add Store::from_manifest_data_and_stream_and_fragments/_async
ok-nick Oct 15, 2025
3b7685c
fix: remove Reader::from_fragments addition
ok-nick Oct 15, 2025
118e497
test: ignore test_builder_ca_jpg for now pending fix
ok-nick Oct 15, 2025
80333d8
docs: clarify review note
ok-nick Oct 15, 2025
65a58bd
Merge branch 'main' of github.com:contentauth/c2pa-rs into scouten/se…
ok-nick Oct 15, 2025
9de74d0
fix: plumb more settings for CAWG identity through
ok-nick Oct 15, 2025
a04ce76
style: fix formatting
ok-nick Oct 15, 2025
b7bbc73
fix: pass in settings for WASM
ok-nick Oct 15, 2025
11c5a06
Merge branch 'scouten/settings-not-thread-local' into ok-nick/setting…
ok-nick Oct 17, 2025
4cae259
Merge remote-tracking branch 'origin' into ok-nick/settings-builders
ok-nick Oct 17, 2025
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
9 changes: 3 additions & 6 deletions sdk/src/assertions/bmff_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,11 +816,10 @@ impl BmffHash {
Ok(())
}

#[cfg(feature = "file_io")]
pub fn verify_stream_segments(
&self,
init_stream: &mut dyn CAIRead,
fragment_paths: &Vec<std::path::PathBuf>,
fragment_paths: &mut [Box<dyn CAIRead>],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This formulation may be necessary, given the iteration you're doing at line 851, but it reads as you'll be changing the membership of fragment_paths rather than you need mutable access to each fragment_stream.

I wonder if there's a way to convey that distinction in meaning.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can store a mutable reference to each stream in the slice although I suspect that would be much more inconvenient than passing a mutable reference to the collection. Let's say you had an owned vec of files, you would have to allocate a new vec that stores mutable references to them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you would still have to box them anyways, but I think ideally we'd have a generic here so they don't need to be.

alg: Option<&str>,
) -> crate::Result<()> {
self.verify_self()?;
Expand Down Expand Up @@ -849,11 +848,9 @@ impl BmffHash {
return Err(Error::HashMismatch("No fragment specified".to_string()));
}

for fp in fragment_paths {
let mut fragment_stream = std::fs::File::open(fp)?;

for mut fragment_stream in fragment_paths {
// get merkle boxes from segment
let c2pa_boxes = read_bmff_c2pa_boxes(&mut fragment_stream)?;
let c2pa_boxes = read_bmff_c2pa_boxes(fragment_stream)?;
let bmff_merkle = c2pa_boxes.bmff_merkle;

if bmff_merkle.is_empty() {
Expand Down
4 changes: 1 addition & 3 deletions sdk/src/claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ pub enum ClaimAssetData<'a> {
Bytes(&'a [u8], &'a str),
Stream(&'a mut dyn CAIRead, &'a str),
StreamFragment(&'a mut dyn CAIRead, &'a mut dyn CAIRead, &'a str),
#[cfg(feature = "file_io")]
StreamFragments(&'a mut dyn CAIRead, &'a Vec<std::path::PathBuf>, &'a str),
StreamFragments(&'a mut dyn CAIRead, &'a mut [Box<dyn CAIRead>], &'a str),
}

#[derive(PartialEq, Debug, Eq, Clone, Hash)]
Expand Down Expand Up @@ -2687,7 +2686,6 @@ impl Claim {
*fragment_data,
Some(claim.alg()),
),
#[cfg(feature = "file_io")]
ClaimAssetData::StreamFragments(initseg_data, fragment_paths, _) => dh
.verify_stream_segments(
*initseg_data,
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ pub enum Error {
}

/// A specialized `Result` type for C2PA toolkit operations.
pub type Result<T> = std::result::Result<T, Error>;
pub type Result<T, E = Error> = std::result::Result<T, E>;

impl From<CoseError> for Error {
fn from(err: CoseError) -> Self {
Expand Down
106 changes: 103 additions & 3 deletions sdk/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ use serde_with::skip_serializing_none;
#[cfg(feature = "file_io")]
use crate::utils::io_utils::uri_to_path;
use crate::{
asset_io::CAIRead,
crypto::base64,
dynamic_assertion::PartialClaim,
error::{Error, Result},
jumbf::labels::{manifest_label_from_uri, to_absolute_uri, to_relative_uri},
jumbf_io,
manifest::StoreOptions,
manifest_store_report::ManifestStoreReport,
settings::get_settings_value,
settings::{get_settings_value, Settings},
status_tracker::StatusTracker,
store::Store,
validation_results::{ValidationResults, ValidationState},
Expand Down Expand Up @@ -72,6 +73,77 @@ pub trait AsyncPostValidator {
) -> Result<Option<Value>>;
}

pub struct ReaderBuilder {
settings: Settings,
external_manifest: Option<Box<dyn CAIRead>>,
fragments: Option<Vec<Box<dyn CAIRead>>>,
}

impl ReaderBuilder {
pub fn new() -> Self {
Self {
settings: Settings::default(),
external_manifest: None,
fragments: None,
}
}

pub fn with_settings(settings: Settings) -> Self {
Self {
settings,
external_manifest: None,
fragments: None,
}
}

pub fn external_manifest(
mut self,
external_manifest: impl Read + Seek + Send + 'static,
) -> Self {
self.external_manifest = Some(Box::new(external_manifest));
self
}

pub fn add_fragment(mut self, fragment: impl Read + Seek + Send + 'static) -> Self {
let fragments = self.fragments.get_or_insert_default();
fragments.push(Box::new(fragment));
self
}

// pub fn http_resolver(self, resolver: impl SyncHttpResolver) -> Self {
// todo!()
// }

// TODO: impl the async cases
// TODO: pass the settings down the stack (waiting on #1444)
#[async_generic]
pub fn build(self, format: &str, stream: impl Read + Seek + Send) -> Result<Reader> {
match self.fragments {
Some(mut fragments) => {
// TODO: can we pass in an external manifest here?
match self.external_manifest {
Some(external_manifest) => {
// TODO: we can add a from_manifest_data_and_fragments function
todo!()
}
None => Reader::from_fragments(format, stream, &mut fragments),
}
}
None => match self.external_manifest {
Some(mut external_manifest) => {
// TODO: internally we actually convert c2pa_data to a stream again, we should modify the function
// signatures to stream by default
let mut c2pa_data = Vec::new();
external_manifest.read_to_end(&mut c2pa_data)?;

Reader::from_manifest_data_and_stream(&c2pa_data, format, stream)
}
None => Reader::from_stream(format, stream),
},
}
}
}

/// Use a Reader to read and validate a manifest store.
#[skip_serializing_none]
#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -297,6 +369,29 @@ impl Reader {
Self::from_store(store, &validation_log)
}

// TODO: doc
pub fn from_fragments(
format: &str,
mut init_segment: impl Read + Seek + Send,
// TODO: make this take impl Read + Seek + Send
fragments: &mut [Box<dyn CAIRead>],
) -> Result<Self> {
let verify = get_settings_value::<bool>("verify.verify_after_reading")?; // defaults to true

let mut validation_log = StatusTracker::default();

match Store::load_fragments_from_stream(
&format,
&mut init_segment,
fragments,
verify,
&mut validation_log,
) {
Ok(store) => Self::from_store(store, &validation_log),
Err(e) => Err(e),
}
}

#[cfg(feature = "file_io")]
/// Loads a [`Reader`]` from an initial segment and fragments. This
/// would be used to load and validate fragmented MP4 files that span
Expand All @@ -314,10 +409,15 @@ impl Reader {

let mut init_segment = std::fs::File::open(path.as_ref())?;

match Store::load_from_file_and_fragments(
let mut fragments: Vec<Box<dyn CAIRead>> = fragments
.iter()
.map(|path| File::open(path).map(|file| Box::new(file) as Box<dyn CAIRead>))
.collect::<Result<_, std::io::Error>>()?;

match Store::load_fragments_from_stream(
&asset_type,
&mut init_segment,
fragments,
&mut fragments,
verify,
&mut validation_log,
) {
Expand Down
19 changes: 10 additions & 9 deletions sdk/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// each license.

#[cfg(feature = "file_io")]
use std::path::{Path, PathBuf};
use std::path::Path;
use std::{
collections::{HashMap, HashSet},
io::{Cursor, Read, Seek},
Expand Down Expand Up @@ -1965,8 +1965,7 @@ impl Store {
let format = typ.to_owned();
object_locations_from_stream(&format, reader)
}
#[cfg(feature = "file_io")]
ClaimAssetData::StreamFragments(reader, _path_bufs, typ) => {
ClaimAssetData::StreamFragments(reader, _fragments, typ) => {
let format = typ.to_owned();
object_locations_from_stream(&format, reader)
}
Expand Down Expand Up @@ -3716,11 +3715,10 @@ impl Store {
/// fragments: list of paths to the fragments to verify
/// verify: if true will run verification checks when loading, all fragments must verify for Ok status
/// validation_log: If present all found errors are logged and returned, otherwise first error causes exit and is returned
#[cfg(feature = "file_io")]
pub fn load_from_file_and_fragments(
pub fn load_fragments_from_stream(
asset_type: &str,
init_segment: &mut dyn CAIRead,
fragments: &Vec<PathBuf>,
fragments: &mut [Box<dyn CAIRead>],
verify: bool,
validation_log: &mut StatusTracker,
) -> Result<Store> {
Expand Down Expand Up @@ -7887,15 +7885,18 @@ pub mod tests {
// test verifying all at once
let mut output_fragments = Vec::new();
for entry in &fragments {
output_fragments.push(new_output_path.join(entry.file_name().unwrap()));
let file =
std::fs::File::open(new_output_path.join(entry.file_name().unwrap()))
.unwrap();
output_fragments.push(Box::new(file) as Box<dyn CAIRead>);
}

//let mut reader = Cursor::new(init_stream);
let mut validation_log = StatusTracker::default();
let _manifest = Store::load_from_file_and_fragments(
let _manifest = Store::load_fragments_from_stream(
"mp4",
&mut init_stream,
&output_fragments,
&mut output_fragments,
false,
&mut validation_log,
)
Expand Down