11use crate :: {
22 credman:: CredmanApi ,
33 issuance_matcher:: IssuanceMatcherData ,
4- openid4vci:: { DigitalCredentialCreationRequest , RegularizedOpenId4VciRequestData } ,
4+ openid4vci:: { DigitalCredentialCreationRequest , OpenId4VciRequest , RegularizedOpenId4VciRequestData } ,
55} ;
66
77use nanoserde:: { DeJson , SerJson } ;
88
99#[ derive( SerJson ) ]
1010struct IssuanceMetadata {
1111 eidx : usize ,
12+ pidx : usize ,
1213}
1314
1415const ALLOWED_PROTOCOLS : [ & str ; 4 ] = [
@@ -18,14 +19,6 @@ const ALLOWED_PROTOCOLS: [&str; 4] = [
1819 "openid4vci1.1" ,
1920] ;
2021
21- fn is_protocol_allowed ( protocol : & String , configured : & [ String ] ) -> bool {
22- if configured. is_empty ( ) {
23- ALLOWED_PROTOCOLS . contains ( & protocol. as_str ( ) )
24- } else {
25- configured. contains ( protocol)
26- }
27- }
28-
2922pub fn issuance_main ( credman : & mut impl CredmanApi ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
3023 log:: info!( "Starting issuance matching process" ) ;
3124 let matcher_data_buffer = credman. get_registered_data ( ) ;
@@ -67,44 +60,72 @@ pub fn issuance_main(credman: &mut impl CredmanApi) -> Result<(), Box<dyn std::e
6760 request. requests. len( )
6861 ) ;
6962
70- for ( i, r) in request. requests . iter ( ) . enumerate ( ) {
71- log:: trace!( "Checking request {}: protocol={}" , i, r. protocol) ;
72- if is_protocol_allowed ( & r. protocol , & matcher_data. allowed_protocols ) {
73- let regularized = RegularizedOpenId4VciRequestData :: from ( & r. data ) ;
74- if matcher_data. filter . matches ( & regularized) {
75- log:: info!( "Match found for request {} with protocol {}" , i, r. protocol) ;
76- let version = credman. get_wasm_version ( ) ;
77- for ( index, entry) in matcher_data. entries . iter ( ) . enumerate ( ) {
78- let entry_id = format ! ( "{}_{}" , matcher_data. entry_id, index) ;
79- let icon = & matcher_data_buffer[ entry. icon . 0 ..entry. icon . 1 ] ;
80- if version >= 9 {
81- log:: debug!( "Adding issuance entry (v>=9): {}" , entry_id) ;
82- let metadata = SerJson :: serialize_json ( & IssuanceMetadata { eidx : index } ) ;
83- credman. add_issuance_entry (
84- & entry_id,
85- icon,
86- & entry. title ,
87- & entry. subtitle ,
88- "" ,
89- & metadata,
90- ) ;
91- } else {
92- log:: debug!( "Adding string ID entry (v<9): {}" , entry_id) ;
93- credman. add_string_id_entry (
94- & entry_id,
95- icon,
96- & entry. title ,
97- & entry. subtitle ,
98- "" ,
99- "" ,
100- ) ;
101- }
63+ let passes_filter = |r : & OpenId4VciRequest | {
64+ let regularized = RegularizedOpenId4VciRequestData :: from ( & r. data ) ;
65+ matcher_data. filter . matches ( & regularized)
66+ } ;
67+
68+ let matched_request_index = if !matcher_data. preferred_protocols . is_empty ( ) {
69+ // If preferred_protocols is set, we prioritize matching them in the order of preference.
70+ // For each preferred protocol, we search for a matching request that passes the filter.
71+ matcher_data. preferred_protocols . iter ( ) . find_map ( |preferred_proto| {
72+ request. requests . iter ( ) . enumerate ( )
73+ . find ( |( _, r) | & r. protocol == preferred_proto && passes_filter ( r) )
74+ . map ( |( index, _) | index)
75+ } )
76+ } else {
77+ // If preferred_protocols is empty, we fall back to iterating over the requests in order,
78+ // and matching the first one that is allowed and passes the filter.
79+ request. requests . iter ( ) . enumerate ( ) . find_map ( |( req_index, r) | {
80+ if ALLOWED_PROTOCOLS . contains ( & r. protocol . as_str ( ) ) {
81+ if passes_filter ( r) {
82+ return Some ( req_index) ;
10283 }
103- // Assuming we only need to add one entry if any request matches
104- break ;
84+ } else {
85+ log :: warn! ( "Unsupported protocol: {}" , r . protocol ) ;
10586 }
87+ None
88+ } )
89+ } ;
90+
91+ let Some ( req_index) = matched_request_index else {
92+ log:: info!( "Issuance matching process completed" ) ;
93+ return Ok ( ( ) ) ;
94+ } ;
95+
96+ log:: info!(
97+ "Match found for request {} with protocol {}" ,
98+ req_index,
99+ request. requests[ req_index] . protocol
100+ ) ;
101+ let version = credman. get_wasm_version ( ) ;
102+ for ( index, entry) in matcher_data. entries . iter ( ) . enumerate ( ) {
103+ let entry_id = format ! ( "{}_{}" , matcher_data. entry_id, index) ;
104+ let icon = & matcher_data_buffer[ entry. icon . 0 ..entry. icon . 1 ] ;
105+ if version >= 9 {
106+ log:: debug!( "Adding issuance entry (v>=9): {}" , entry_id) ;
107+ let metadata = SerJson :: serialize_json ( & IssuanceMetadata {
108+ eidx : index,
109+ pidx : req_index,
110+ } ) ;
111+ credman. add_issuance_entry (
112+ & entry_id,
113+ icon,
114+ & entry. title ,
115+ & entry. subtitle ,
116+ "" ,
117+ & metadata,
118+ ) ;
106119 } else {
107- log:: warn!( "Unsupported protocol: {}" , r. protocol) ;
120+ log:: debug!( "Adding string ID entry (v<9): {}" , entry_id) ;
121+ credman. add_string_id_entry (
122+ & entry_id,
123+ icon,
124+ & entry. title ,
125+ & entry. subtitle ,
126+ "" ,
127+ "" ,
128+ ) ;
108129 }
109130 }
110131
@@ -597,7 +618,7 @@ mod test {
597618 "icon": [0, 0]
598619 }
599620 ],
600- "allowed_protocols ": ["my-custom-protocol"],
621+ "preferred_protocols ": ["my-custom-protocol"],
601622 "filter": {
602623 "Pass": {}
603624 }
@@ -647,7 +668,7 @@ mod test {
647668 "icon": [0, 0]
648669 }
649670 ],
650- "allowed_protocols ": ["my-custom-protocol"],
671+ "preferred_protocols ": ["my-custom-protocol"],
651672 "filter": {
652673 "Pass": {}
653674 }
@@ -724,7 +745,7 @@ mod test {
724745 assert ! ( entry. icon. is_none( ) ) ;
725746 assert_eq ! ( entry. call_type, CallType :: Issuance ) ;
726747 assert ! ( entry. explainer. is_none( ) ) ;
727- assert_eq ! ( entry. metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :0}" ) ;
748+ assert_eq ! ( entry. metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :0, \" pidx \" :0 }" ) ;
728749 }
729750
730751 #[ test]
@@ -779,9 +800,75 @@ mod test {
779800 assert_eq ! ( credman. added_entries. len( ) , 2 ) ;
780801 assert_eq ! ( credman. added_entries[ 0 ] . entry_id, c"C_0" ) ;
781802 assert_eq ! ( credman. added_entries[ 0 ] . title. as_ref( ) . unwrap( ) , c"TTTT1" ) ;
782- assert_eq ! ( credman. added_entries[ 0 ] . metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :0}" ) ;
803+ assert_eq ! ( credman. added_entries[ 0 ] . metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :0, \" pidx \" :0 }" ) ;
783804 assert_eq ! ( credman. added_entries[ 1 ] . entry_id, c"C_1" ) ;
784805 assert_eq ! ( credman. added_entries[ 1 ] . title. as_ref( ) . unwrap( ) , c"TTTT2" ) ;
785- assert_eq ! ( credman. added_entries[ 1 ] . metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :1}" ) ;
806+ assert_eq ! ( credman. added_entries[ 1 ] . metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :1,\" pidx\" :0}" ) ;
807+ }
808+
809+ #[ test]
810+ fn match_preferred_protocol_order ( ) {
811+ let mut credman = FakeCredman {
812+ request_json : r#"
813+ {
814+ "requests": [
815+ {
816+ "protocol": "openid4vci-1.0",
817+ "data": {
818+ "credential_issuer": "https://issuer.my",
819+ "credential_configuration_ids": [
820+ "US_SOCIAL_SECURITY_NUMBER"
821+ ],
822+ "grants": {
823+ "authorization_code": {}
824+ },
825+ "credential_issuer_metadata": {
826+ "nonce_endpoint": "https://nonce.my"
827+ }
828+ }
829+ },
830+ {
831+ "protocol": "openid4vci-1.1",
832+ "data": {
833+ "credential_issuer": "https://issuer.my",
834+ "credential_configuration_ids": [
835+ "US_SOCIAL_SECURITY_NUMBER"
836+ ],
837+ "grants": {
838+ "authorization_code": {}
839+ },
840+ "credential_issuer_metadata": {
841+ "nonce_endpoint": "https://nonce.my"
842+ }
843+ }
844+ }
845+ ]
846+ }"# ,
847+ registered_json : r#"
848+ {
849+ "entry_id": "C",
850+ "entries": [
851+ {
852+ "title": "TTTT",
853+ "subtitle": "SSSSS",
854+ "icon": [0, 0]
855+ }
856+ ],
857+ "preferred_protocols": ["openid4vci-1.1", "openid4vci-1.0"],
858+ "filter": {
859+ "Pass": {}
860+ }
861+ }"# ,
862+ icon : Vec :: new ( ) ,
863+ added_entries : Vec :: new ( ) ,
864+ wasm_version : 9 ,
865+ } ;
866+
867+ issuance_main ( & mut credman) . unwrap ( ) ;
868+
869+ assert_eq ! ( credman. added_entries. len( ) , 1 ) ;
870+ let entry = & credman. added_entries [ 0 ] ;
871+ assert_eq ! ( entry. entry_id, c"C_0" ) ;
872+ assert_eq ! ( entry. metadata. as_ref( ) . unwrap( ) , c"{\" eidx\" :0,\" pidx\" :1}" ) ;
786873 }
787874}
0 commit comments