diff --git a/bindings/web5_uniffi/src/lib.rs b/bindings/web5_uniffi/src/lib.rs index ec29be6a..6fdbdc61 100644 --- a/bindings/web5_uniffi/src/lib.rs +++ b/bindings/web5_uniffi/src/lib.rs @@ -10,7 +10,7 @@ use web5_uniffi_wrapper::{ verifiable_presentation_1_1::{ VerifiablePresentation, VerifiablePresentationCreateOptions as VerifiablePresentationCreateOptionsData, - VerifiablePresentationData + VerifiablePresentationData, }, }, crypto::{ diff --git a/bindings/web5_uniffi_wrapper/src/credentials/verifiable_presentation_1_1.rs b/bindings/web5_uniffi_wrapper/src/credentials/verifiable_presentation_1_1.rs index 5ae3f531..a8e8f3e3 100644 --- a/bindings/web5_uniffi_wrapper/src/credentials/verifiable_presentation_1_1.rs +++ b/bindings/web5_uniffi_wrapper/src/credentials/verifiable_presentation_1_1.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; use crate::{dids::bearer_did::BearerDid, errors::Result}; +use serde_json::Value; +use std::collections::HashMap; use std::sync::Arc; use std::time::SystemTime; -use serde_json::Value; use web5::credentials::VerifiablePresentation as InnerVerifiablePresentation; use web5::credentials::VerifiablePresentationCreateOptions as InnerVerifiablePresentationCreateOptions; @@ -26,13 +26,12 @@ impl VerifiablePresentation { vc_jwts: Vec, options: Option, ) -> Result { - let options = options.unwrap_or_default(); let additional_data = match options.json_serialized_additional_data { - Some(additional_data) => { - Some(serde_json::from_str::>(&additional_data)?) - } + Some(additional_data) => Some(serde_json::from_str::>( + &additional_data, + )?), None => None, }; @@ -42,7 +41,7 @@ impl VerifiablePresentation { r#type: options.r#type, issuance_date: options.issuance_date, expiration_date: options.expiration_date, - additional_data: additional_data, + additional_data, }; let inner_vp = InnerVerifiablePresentation::create(holder, vc_jwts, Some(inner_options))?; @@ -64,7 +63,7 @@ impl VerifiablePresentation { verifiable_credential: self.inner_vp.verifiable_credential.clone(), issuance_date: self.inner_vp.issuance_date, expiration_date: self.inner_vp.expiration_date, - json_serialized_additional_data: json_serialized_additional_data, + json_serialized_additional_data, }) } @@ -94,4 +93,4 @@ pub struct VerifiablePresentationData { pub expiration_date: Option, pub verifiable_credential: Vec, pub json_serialized_additional_data: Option, -} \ No newline at end of file +} diff --git a/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt b/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt index 345d9420..b83f58d7 100644 --- a/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt +++ b/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt @@ -7022,7 +7022,8 @@ data class VerifiablePresentationCreateOptionsData ( var `context`: List?, var `type`: List?, var `issuanceDate`: java.time.Instant?, - var `expirationDate`: java.time.Instant? + var `expirationDate`: java.time.Instant?, + var `jsonSerializedAdditionalData`: kotlin.String? ) { companion object @@ -7036,6 +7037,7 @@ public object FfiConverterTypeVerifiablePresentationCreateOptionsData: FfiConver FfiConverterOptionalSequenceString.read(buf), FfiConverterOptionalTimestamp.read(buf), FfiConverterOptionalTimestamp.read(buf), + FfiConverterOptionalString.read(buf), ) } @@ -7044,7 +7046,8 @@ public object FfiConverterTypeVerifiablePresentationCreateOptionsData: FfiConver FfiConverterOptionalSequenceString.allocationSize(value.`context`) + FfiConverterOptionalSequenceString.allocationSize(value.`type`) + FfiConverterOptionalTimestamp.allocationSize(value.`issuanceDate`) + - FfiConverterOptionalTimestamp.allocationSize(value.`expirationDate`) + FfiConverterOptionalTimestamp.allocationSize(value.`expirationDate`) + + FfiConverterOptionalString.allocationSize(value.`jsonSerializedAdditionalData`) ) override fun write(value: VerifiablePresentationCreateOptionsData, buf: ByteBuffer) { @@ -7053,6 +7056,7 @@ public object FfiConverterTypeVerifiablePresentationCreateOptionsData: FfiConver FfiConverterOptionalSequenceString.write(value.`type`, buf) FfiConverterOptionalTimestamp.write(value.`issuanceDate`, buf) FfiConverterOptionalTimestamp.write(value.`expirationDate`, buf) + FfiConverterOptionalString.write(value.`jsonSerializedAdditionalData`, buf) } } @@ -7065,7 +7069,8 @@ data class VerifiablePresentationData ( var `holder`: kotlin.String, var `issuanceDate`: java.time.Instant, var `expirationDate`: java.time.Instant?, - var `verifiableCredential`: List + var `verifiableCredential`: List, + var `jsonSerializedAdditionalData`: kotlin.String? ) { companion object @@ -7081,6 +7086,7 @@ public object FfiConverterTypeVerifiablePresentationData: FfiConverterRustBuffer FfiConverterTimestamp.read(buf), FfiConverterOptionalTimestamp.read(buf), FfiConverterSequenceString.read(buf), + FfiConverterOptionalString.read(buf), ) } @@ -7091,7 +7097,8 @@ public object FfiConverterTypeVerifiablePresentationData: FfiConverterRustBuffer FfiConverterString.allocationSize(value.`holder`) + FfiConverterTimestamp.allocationSize(value.`issuanceDate`) + FfiConverterOptionalTimestamp.allocationSize(value.`expirationDate`) + - FfiConverterSequenceString.allocationSize(value.`verifiableCredential`) + FfiConverterSequenceString.allocationSize(value.`verifiableCredential`) + + FfiConverterOptionalString.allocationSize(value.`jsonSerializedAdditionalData`) ) override fun write(value: VerifiablePresentationData, buf: ByteBuffer) { @@ -7102,6 +7109,7 @@ public object FfiConverterTypeVerifiablePresentationData: FfiConverterRustBuffer FfiConverterTimestamp.write(value.`issuanceDate`, buf) FfiConverterOptionalTimestamp.write(value.`expirationDate`, buf) FfiConverterSequenceString.write(value.`verifiableCredential`, buf) + FfiConverterOptionalString.write(value.`jsonSerializedAdditionalData`, buf) } } diff --git a/crates/web5/src/credentials/presentation_definition.rs b/crates/web5/src/credentials/presentation_definition.rs index cc955bf8..553a42cf 100644 --- a/crates/web5/src/credentials/presentation_definition.rs +++ b/crates/web5/src/credentials/presentation_definition.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use crate::credentials::verifiable_credential_1_1::VerifiableCredential; use jsonpath_rust::{ JsonPathFinder, JsonPathValue::{NewValue, NoValue, Slice}, @@ -8,7 +9,6 @@ use jsonschema::JSONSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, to_value, Map, Value}; use uuid::Uuid; -use crate::credentials::verifiable_credential_1_1::VerifiableCredential; #[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone, PartialEq)] pub enum PexError { @@ -152,7 +152,6 @@ fn generate_token() -> String { } impl PresentationDefinition { - /// Selects Verifiable Credentials (VCs) that match the input descriptors of the presentation definition. /// /// # Arguments @@ -397,12 +396,14 @@ impl JsonSchemaBuilder { #[cfg(test)] mod tests { - use std::collections::HashMap; use super::*; - use serde_json::json; - use crate::credentials::{CredentialSubject, Issuer, VerifiablePresentation, VerifiablePresentationCreateOptions}; + use crate::credentials::{ + CredentialSubject, Issuer, VerifiablePresentation, VerifiablePresentationCreateOptions, + }; use crate::dids::methods::did_jwk::DidJwk; use crate::json::{JsonObject, JsonValue}; + use serde_json::json; + use std::collections::HashMap; #[test] fn test_create_presentation_from_credentials() { @@ -413,31 +414,27 @@ mod tests { id: "test_pd_id".to_string(), name: Some("Test Presentation Definition".to_string()), purpose: Some("Testing".to_string()), - input_descriptors: vec![ - InputDescriptor { - id: "test_input_1".to_string(), - name: Some("Test Input 1".to_string()), - purpose: Some("Testing Input 1".to_string()), - constraints: Constraints { - fields: vec![ - Field { - path: vec!["$.credentialSubject.id".to_string()], - filter: Some(Filter { - r#type: Some("string".to_string()), - pattern: Some("^did:jwk:.*$".to_string()), - const_value: None, - contains: None, - }), - id: None, - name: None, - purpose: None, - optional: None, - predicate: None, - } - ], - }, - } - ], + input_descriptors: vec![InputDescriptor { + id: "test_input_1".to_string(), + name: Some("Test Input 1".to_string()), + purpose: Some("Testing Input 1".to_string()), + constraints: Constraints { + fields: vec![Field { + path: vec!["$.credentialSubject.id".to_string()], + filter: Some(Filter { + r#type: Some("string".to_string()), + pattern: Some("^did:jwk:.*$".to_string()), + const_value: None, + contains: None, + }), + id: None, + name: None, + purpose: None, + optional: None, + predicate: None, + }], + }, + }], submission_requirements: None, }; @@ -445,13 +442,12 @@ mod tests { Issuer::from(issuer_uri.clone()), CredentialSubject::from(issuer_uri.clone()), Default::default(), - ).unwrap(); + ) + .unwrap(); let signed_vcjwt_1 = vc_1.sign(&issuer.clone(), None).unwrap(); - let vc_jwts = vec![ - signed_vcjwt_1 - ]; + let vc_jwts = vec![signed_vcjwt_1]; let result = presentation_definition.create_presentation_from_credentials(&vc_jwts); @@ -459,12 +455,29 @@ mod tests { let presentation_result = result.unwrap(); - assert_eq!(presentation_result.presentation_submission.definition_id, "test_pd_id"); - assert_eq!(presentation_result.presentation_submission.descriptor_map.len(), 1); - assert_eq!(presentation_result.presentation_submission.descriptor_map[0].id, "test_input_1"); - assert_eq!(presentation_result.presentation_submission.descriptor_map[0].format, "jwt_vc"); - assert_eq!(presentation_result.presentation_submission.descriptor_map[0].path, "$.verifiableCredential[0]"); - + assert_eq!( + presentation_result.presentation_submission.definition_id, + "test_pd_id" + ); + assert_eq!( + presentation_result + .presentation_submission + .descriptor_map + .len(), + 1 + ); + assert_eq!( + presentation_result.presentation_submission.descriptor_map[0].id, + "test_input_1" + ); + assert_eq!( + presentation_result.presentation_submission.descriptor_map[0].format, + "jwt_vc" + ); + assert_eq!( + presentation_result.presentation_submission.descriptor_map[0].path, + "$.verifiableCredential[0]" + ); } /// This test demonstrates the full flow of a Presentation Exchange using a Verifiable Credential (VC) and a Presentation Definition (PD). @@ -522,7 +535,7 @@ mod tests { CredentialSubject::from(issuer_uri.clone()), Default::default(), ) - .unwrap(); + .unwrap(); // Step 4: Sign the VC to generate a VC in JWT format let signed_vcjwt_1 = vc_1.sign(&issuer.clone(), None).unwrap(); @@ -556,9 +569,9 @@ mod tests { let vp = VerifiablePresentation::create( holder_uri.clone(), presentation_result.matched_vc_jwts, // Use the selected credentials from the PD - Some(vp_create_options) + Some(vp_create_options), ) - .expect("Failed to create Verifiable Presentation"); + .expect("Failed to create Verifiable Presentation"); // Step 8: Sign the VP to generate a JWT format let vp_jwt = vp.sign(&holder.clone(), None).unwrap(); @@ -654,7 +667,7 @@ mod tests { }, Default::default(), ) - .unwrap(); + .unwrap(); // For vc_2, we add the "role" property to match the second input descriptor let vc_2_credential_subject = CredentialSubject { @@ -670,7 +683,8 @@ mod tests { Issuer::from(issuer_uri.clone()), vc_2_credential_subject, Default::default(), - ).unwrap(); + ) + .unwrap(); // vc_3 won't match either input descriptor let vc_3 = VerifiableCredential::create( @@ -680,7 +694,8 @@ mod tests { additional_properties: None, // No matching role }, Default::default(), - ).unwrap(); + ) + .unwrap(); // Sign all three VCs let signed_vcjwt_1 = vc_1.sign(&issuer.clone(), None).unwrap(); @@ -694,7 +709,7 @@ mod tests { ]; // Unwrap the result of `create_presentation_from_credentials` - let presentation_result= presentation_definition + let presentation_result = presentation_definition .create_presentation_from_credentials(&vc_jwts) .unwrap(); @@ -713,8 +728,12 @@ mod tests { }; // Use the `selected_vcs` directly - let vp = VerifiablePresentation::create(holder_uri.clone(), presentation_result.matched_vc_jwts, Some(vp_create_options)) - .expect("Failed to create Verifiable Presentation"); + let vp = VerifiablePresentation::create( + holder_uri.clone(), + presentation_result.matched_vc_jwts, + Some(vp_create_options), + ) + .expect("Failed to create Verifiable Presentation"); let vp_jwt = vp.sign(&holder.clone(), None).unwrap(); diff --git a/crates/web5/src/credentials/verifiable_presentation_1_1.rs b/crates/web5/src/credentials/verifiable_presentation_1_1.rs index 2aa38e8b..f012c5a6 100644 --- a/crates/web5/src/credentials/verifiable_presentation_1_1.rs +++ b/crates/web5/src/credentials/verifiable_presentation_1_1.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use crate::credentials::josekit::{JoseSigner, JoseVerifier, JoseVerifierAlwaysTrue}; use crate::credentials::verifiable_credential_1_1::VerifiableCredential; use crate::credentials::VerificationError; @@ -17,9 +16,10 @@ use crate::rfc3339::{ use josekit::jws::JwsHeader; use josekit::jwt::JwtPayload; use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::HashMap; use std::sync::Arc; use std::time::SystemTime; -use serde_json::Value; use uuid::Uuid; pub const BASE_PRESENTATION_CONTEXT: &str = "https://www.w3.org/2018/credentials/v1"; @@ -161,7 +161,7 @@ pub fn sign_presentation_with_signer( verifiable_credential: vp.verifiable_credential.clone(), issuance_date: Some(vp.issuance_date), expiration_date: vp.expiration_date, - additional_data: vp.additional_data.clone() + additional_data: vp.additional_data.clone(), }; payload @@ -327,7 +327,7 @@ pub fn decode_vp_jwt(vp_jwt: &str, verify_signature: bool) -> Result