Skip to content

Commit e2cf2fb

Browse files
authored
Merge branch 'main' into wasm32-wasi_0.41.0
2 parents fca1c33 + 1cda7bd commit e2cf2fb

File tree

7 files changed

+160
-15
lines changed

7 files changed

+160
-15
lines changed

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cawg_identity/CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
66

77
The format of this changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88

9+
## [0.8.0](https://github.com/contentauth/c2pa-rs/compare/cawg-identity-v0.7.0...cawg-identity-v0.8.0)
10+
_12 February 2025_
11+
12+
### Added
13+
14+
* *(cawg_identity)* Add new functions for generating a `Serialize`-able report for entire manifest store (#920)
15+
16+
## [0.7.0](https://github.com/contentauth/c2pa-rs/compare/cawg-identity-v0.6.1...cawg-identity-v0.7.0)
17+
_11 February 2025_
18+
19+
### Added
20+
21+
* *(cawg_identity)* Add `IdentityAssertion::to_summary` and `IdentityAssertion::summarize_all` (#913)
22+
923
## [0.6.1](https://github.com/contentauth/c2pa-rs/compare/cawg-identity-v0.6.0...cawg-identity-v0.6.1)
1024
_11 February 2025_
1125

cawg_identity/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cawg-identity"
3-
version = "0.6.1"
3+
version = "0.8.0"
44
description = "Rust SDK for CAWG (Creator Assertions Working Group) identity assertion"
55
authors = [
66
"Eric Scouten <scouten@adobe.com>",
@@ -24,6 +24,9 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] }
2424
all-features = true
2525
rustdoc-args = ["--cfg", "docsrs"]
2626

27+
[features]
28+
v1_api = ["c2pa/v1_api"]
29+
2730
[dependencies]
2831
async-trait = "0.1.78"
2932
base64 = "0.22.1"

cawg_identity/src/identity_assertion/assertion.rs

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@
1111
// specific language governing permissions and limitations under
1212
// each license.
1313

14-
use std::fmt::{Debug, Formatter};
14+
use std::{
15+
collections::BTreeMap,
16+
fmt::{Debug, Formatter},
17+
};
1518

16-
use c2pa::Manifest;
19+
use c2pa::{Manifest, Reader};
1720
use serde::{Deserialize, Serialize};
1821
use serde_bytes::ByteBuf;
1922

2023
use crate::{
2124
identity_assertion::{
22-
report::{IdentityAssertionReport, IdentityAssertionsForManifest, SignerPayloadReport},
25+
report::{
26+
IdentityAssertionReport, IdentityAssertionsForManifest,
27+
IdentityAssertionsForManifestStore, SignerPayloadReport,
28+
},
2329
signer_payload::SignerPayload,
2430
},
2531
internal::debug_byte_slice::DebugByteSlice,
@@ -116,6 +122,15 @@ impl IdentityAssertion {
116122
manifest: &Manifest,
117123
verifier: &SV,
118124
) -> impl Serialize {
125+
Self::summarize_all_impl(manifest, verifier).await
126+
}
127+
128+
pub(crate) async fn summarize_all_impl<SV: SignatureVerifier>(
129+
manifest: &Manifest,
130+
verifier: &SV,
131+
) -> IdentityAssertionsForManifest<
132+
<<SV as SignatureVerifier>::Output as ToCredentialSummary>::CredentialSummary,
133+
> {
119134
// NOTE: We can't write this using .map(...).collect() because there are async
120135
// calls.
121136
let mut reports: Vec<
@@ -142,6 +157,65 @@ impl IdentityAssertion {
142157
}
143158
}
144159

160+
/// Summarize all of the identity assertions found for a [`ManifestStore`].
161+
///
162+
/// [`ManifestStore`]: c2pa::ManifestStore
163+
#[cfg(feature = "v1_api")]
164+
pub async fn summarize_manifest_store<SV: SignatureVerifier>(
165+
store: &c2pa::ManifestStore,
166+
verifier: &SV,
167+
) -> impl Serialize {
168+
// NOTE: We can't write this using .map(...).collect() because there are async
169+
// calls.
170+
let mut reports: BTreeMap<
171+
String,
172+
IdentityAssertionsForManifest<
173+
<<SV as SignatureVerifier>::Output as ToCredentialSummary>::CredentialSummary,
174+
>,
175+
> = BTreeMap::new();
176+
177+
for (id, manifest) in store.manifests() {
178+
let report = Self::summarize_all_impl(manifest, verifier).await;
179+
reports.insert(id.clone(), report);
180+
}
181+
182+
IdentityAssertionsForManifestStore::<
183+
<<SV as SignatureVerifier>::Output as ToCredentialSummary>::CredentialSummary,
184+
> {
185+
assertions_for_manifest: reports,
186+
}
187+
}
188+
189+
/// Summarize all of the identity assertions found for a [`Reader`].
190+
pub async fn summarize_from_reader<SV: SignatureVerifier>(
191+
reader: &Reader,
192+
verifier: &SV,
193+
) -> impl Serialize {
194+
// NOTE: We can't write this using .map(...).collect() because there are async
195+
// calls.
196+
let mut reports: BTreeMap<
197+
String,
198+
IdentityAssertionsForManifest<
199+
<<SV as SignatureVerifier>::Output as ToCredentialSummary>::CredentialSummary,
200+
>,
201+
> = BTreeMap::new();
202+
203+
for manifest in reader.iter_manifests() {
204+
let report = Self::summarize_all_impl(manifest, verifier).await;
205+
206+
// TO DO: What to do if manifest doesn't have a label?
207+
if let Some(label) = manifest.label() {
208+
reports.insert(label.to_owned(), report);
209+
}
210+
}
211+
212+
IdentityAssertionsForManifestStore::<
213+
<<SV as SignatureVerifier>::Output as ToCredentialSummary>::CredentialSummary,
214+
> {
215+
assertions_for_manifest: reports,
216+
}
217+
}
218+
145219
/// Using the provided [`SignatureVerifier`], check the validity of this
146220
/// identity assertion.
147221
///

cawg_identity/src/identity_assertion/report.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,33 @@
1111
// specific language governing permissions and limitations under
1212
// each license.
1313

14-
use serde::{ser::SerializeSeq, Serialize};
14+
use std::collections::BTreeMap;
15+
16+
use serde::{
17+
ser::{SerializeMap, SerializeSeq},
18+
Serialize,
19+
};
1520

1621
use crate::identity_assertion::signer_payload::SignerPayload;
1722

23+
#[doc(hidden)]
24+
pub struct IdentityAssertionsForManifestStore<IAR: Serialize> {
25+
pub(crate) assertions_for_manifest: BTreeMap<String, IdentityAssertionsForManifest<IAR>>,
26+
}
27+
28+
impl<IAR: Serialize> Serialize for IdentityAssertionsForManifestStore<IAR> {
29+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30+
where
31+
S: serde::Serializer,
32+
{
33+
let mut map = serializer.serialize_map(Some(self.assertions_for_manifest.len()))?;
34+
for (manifest_id, report) in self.assertions_for_manifest.iter() {
35+
map.serialize_entry(manifest_id, report)?;
36+
}
37+
map.end()
38+
}
39+
}
40+
1841
#[doc(hidden)]
1942
pub struct IdentityAssertionsForManifest<IAR: Serialize> {
2043
pub(crate) assertion_reports: Vec<IdentityAssertionReport<IAR>>,

cawg_identity/src/tests/claim_aggregation/interop.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ async fn adobe_connected_identities() {
3333

3434
let mut test_image = Cursor::new(test_image);
3535

36-
let manifest_store = Reader::from_stream(format, &mut test_image).unwrap();
37-
assert_eq!(manifest_store.validation_status(), None);
36+
let reader = Reader::from_stream(format, &mut test_image).unwrap();
37+
assert_eq!(reader.validation_status(), None);
3838

39-
let manifest = manifest_store.active_manifest().unwrap();
39+
let manifest = reader.active_manifest().unwrap();
4040
let mut ia_iter = IdentityAssertion::from_manifest(manifest);
4141

4242
// Should find exactly one identity assertion.
@@ -82,6 +82,15 @@ async fn adobe_connected_identities() {
8282
}
8383
);
8484

85+
// Check the summary report for the entire manifest store.
86+
let ia_summary = IdentityAssertion::summarize_from_reader(&reader, &isv).await;
87+
let ia_json = serde_json::to_string(&ia_summary).unwrap();
88+
89+
assert_eq!(
90+
ia_json,
91+
r#"{"urn:uuid:b55062ef-96b6-4f6e-bb7d-9c415f130471":[{"sig_type":"cawg.identity_claims_aggregation","referenced_assertions":["c2pa.hash.data"],"named_actor":{"@context":["https://www.w3.org/ns/credentials/v2","https://creator-assertions.github.io/tbd/tbd"],"type":["VerifiableCredential","IdentityClaimsAggregationCredential"],"issuer":"did:web:connected-identities.identity-stage.adobe.com","validFrom":"2024-10-03T21:47:02Z","verifiedIdentities":[{"type":"cawg.social_media","username":"Robert Tiles","uri":"https://net.s2stagehance.com/roberttiles","verifiedAt":"2024-09-24T18:15:11Z","provider":{"id":"https://behance.net","name":"behance"}}],"credentialSchema":[{"id":"https://creator-assertions.github.io/schemas/v1/creator-identity-assertion.json","type":"JSONSchema"}]}}]}"#
92+
);
93+
8594
// Check the summary report for this manifest.
8695
let ia_summary = IdentityAssertion::summarize_all(manifest, &isv).await;
8796
let ia_json = serde_json::to_string(&ia_summary).unwrap();
@@ -91,3 +100,25 @@ async fn adobe_connected_identities() {
91100
r#"[{"sig_type":"cawg.identity_claims_aggregation","referenced_assertions":["c2pa.hash.data"],"named_actor":{"@context":["https://www.w3.org/ns/credentials/v2","https://creator-assertions.github.io/tbd/tbd"],"type":["VerifiableCredential","IdentityClaimsAggregationCredential"],"issuer":"did:web:connected-identities.identity-stage.adobe.com","validFrom":"2024-10-03T21:47:02Z","verifiedIdentities":[{"type":"cawg.social_media","username":"Robert Tiles","uri":"https://net.s2stagehance.com/roberttiles","verifiedAt":"2024-09-24T18:15:11Z","provider":{"id":"https://behance.net","name":"behance"}}],"credentialSchema":[{"id":"https://creator-assertions.github.io/schemas/v1/creator-identity-assertion.json","type":"JSONSchema"}]}}]"#
92101
);
93102
}
103+
104+
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
105+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
106+
async fn ims_multiple_manifests() {
107+
let format = "image/jpeg";
108+
let test_image = include_bytes!("../fixtures/claim_aggregation/ims_multiple_manifests.jpg");
109+
110+
let mut test_image = Cursor::new(test_image);
111+
112+
let reader = Reader::from_stream(format, &mut test_image).unwrap();
113+
assert_eq!(reader.validation_status(), None);
114+
115+
// Check the summary report for the entire manifest store.
116+
let isv = IcaSignatureVerifier {};
117+
let ia_summary = IdentityAssertion::summarize_from_reader(&reader, &isv).await;
118+
let ia_json = serde_json::to_string(&ia_summary).unwrap();
119+
120+
assert_eq!(
121+
ia_json,
122+
r#"{"urn:uuid:7256ca36-2a90-44ec-914d-f17c8d70c31f":[{"sig_type":"cawg.identity_claims_aggregation","referenced_assertions":["c2pa.hash.data"],"named_actor":{"@context":["https://www.w3.org/ns/credentials/v2","https://creator-assertions.github.io/tbd/tbd"],"type":["VerifiableCredential","IdentityClaimsAggregationCredential"],"issuer":"did:web:connected-identities.identity-stage.adobe.com","validFrom":"2025-02-13T00:40:47Z","verifiedIdentities":[{"type":"cawg.social_media","username":"firstlast555","uri":"https://net.s2stagehance.com/firstlast555","verifiedAt":"2025-01-10T19:53:59Z","provider":{"id":"https://behance.net","name":"behance"}}],"credentialSchema":[{"id":"https://cawg.io/schemas/v1/creator-identity-assertion.json","type":"JSONSchema"}]}}],"urn:uuid:b55062ef-96b6-4f6e-bb7d-9c415f130471":[{"sig_type":"cawg.identity_claims_aggregation","referenced_assertions":["c2pa.hash.data"],"named_actor":{"@context":["https://www.w3.org/ns/credentials/v2","https://creator-assertions.github.io/tbd/tbd"],"type":["VerifiableCredential","IdentityClaimsAggregationCredential"],"issuer":"did:web:connected-identities.identity-stage.adobe.com","validFrom":"2024-10-03T21:47:02Z","verifiedIdentities":[{"type":"cawg.social_media","username":"Robert Tiles","uri":"https://net.s2stagehance.com/roberttiles","verifiedAt":"2024-09-24T18:15:11Z","provider":{"id":"https://behance.net","name":"behance"}}],"credentialSchema":[{"id":"https://creator-assertions.github.io/schemas/v1/creator-identity-assertion.json","type":"JSONSchema"}]}}]}"#
123+
);
124+
}
208 KB
Loading

0 commit comments

Comments
 (0)