Skip to content

Commit 2dd3e6b

Browse files
committed
Use preferred_protocols and refactor matching loop in issuance_main
Renamed allowed_protocols to preferred_protocols in IssuanceMatcherData. Updated matching logic: if preferred_protocols is set, we match in order of preference; record the matched request index as pidx in the metadata. Refactored the matching loop in issuance_main using iterator combinators (find_map, find) for better readability. Updated existing tests and added a new test match_preferred_protocol_order to verify preference ordering and pidx recording. TAG=agy CONV=6222f947-d807-4f7a-8223-5f30b7376340
1 parent 04e647d commit 2dd3e6b

2 files changed

Lines changed: 137 additions & 50 deletions

File tree

CredentialProvider/wasm/matcher-rs/src/issuance.rs

Lines changed: 136 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::{
22
credman::CredmanApi,
33
issuance_matcher::IssuanceMatcherData,
4-
openid4vci::{DigitalCredentialCreationRequest, RegularizedOpenId4VciRequestData},
4+
openid4vci::{DigitalCredentialCreationRequest, OpenId4VciRequest, RegularizedOpenId4VciRequestData},
55
};
66

77
use nanoserde::{DeJson, SerJson};
88

99
#[derive(SerJson)]
1010
struct IssuanceMetadata {
1111
eidx: usize,
12+
pidx: usize,
1213
}
1314

1415
const 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-
2922
pub 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
}

CredentialProvider/wasm/matcher-rs/src/issuance_matcher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,5 @@ pub struct IssuanceMatcherData {
112112
pub entry_id: String,
113113
pub entries: Vec<IssuanceDisplayData>,
114114
pub filter: OpenId4VciFilter,
115-
pub allowed_protocols: Vec<String>,
115+
pub preferred_protocols: Vec<String>,
116116
}

0 commit comments

Comments
 (0)