@@ -7,6 +7,11 @@ use tracing::{debug, instrument, trace};
77
88use crate :: {
99 fido:: AuthenticatorData ,
10+ ops:: webauthn:: {
11+ create:: { AuthenticatorSelectionCriteria , PublicKeyCredentialCreationOptionsJSON } ,
12+ idl:: { FromInnerModel , JsonError , WebAuthnIDL } ,
13+ rpid:: RelyingPartyId ,
14+ } ,
1015 proto:: {
1116 ctap1:: { Ctap1RegisteredKey , Ctap1Version } ,
1217 ctap2:: {
@@ -149,10 +154,13 @@ impl MakeCredentialsResponseUnsignedExtensions {
149154 }
150155}
151156
152- #[ derive( Debug , Clone , Copy ) ]
157+ #[ derive( Debug , Clone , Copy , Deserialize ) ]
153158pub enum ResidentKeyRequirement {
159+ #[ serde( rename = "required" ) ]
154160 Required ,
161+ #[ serde( rename = "preferred" ) ]
155162 Preferred ,
163+ #[ serde( rename = "discouraged" , other) ]
156164 Discouraged ,
157165}
158166
@@ -175,6 +183,68 @@ pub struct MakeCredentialRequest {
175183 pub timeout : Duration ,
176184}
177185
186+ impl FromInnerModel < PublicKeyCredentialCreationOptionsJSON , MakeCredentialRequestParsingError >
187+ for MakeCredentialRequest
188+ {
189+ fn from_inner_model (
190+ rpid : & RelyingPartyId ,
191+ inner : PublicKeyCredentialCreationOptionsJSON ,
192+ ) -> Result < Self , MakeCredentialRequestParsingError > {
193+ let resident_key = if inner
194+ . authenticator_selection
195+ . as_ref ( )
196+ . and_then ( |s| Some ( s. require_resident_key ) )
197+ == Some ( true )
198+ {
199+ Some ( ResidentKeyRequirement :: Required )
200+ } else {
201+ inner. authenticator_selection . and_then ( |s| s. resident_key )
202+ } ;
203+
204+ let user_verification = inner
205+ . authenticator_selection
206+ . map_or ( UserVerificationRequirement :: Discouraged , |s| {
207+ s. user_verification
208+ } ) ;
209+
210+ let exclude = match inner. exclude_credentials [ ..] {
211+ [ ] => None ,
212+ _ => Some ( inner. exclude_credentials ) ,
213+ } ;
214+
215+ let extensions = serde_json:: from_value ( serde_json:: Value :: Object ( inner. extensions ) )
216+ . map_err ( MakeCredentialRequestParsingError :: ExtensionError ) ?;
217+
218+ Ok ( Self {
219+ hash : inner. challenge . into ( ) ,
220+ origin : rpid. as_str ( ) . to_owned ( ) ,
221+ relying_party : inner. rp ,
222+ user : inner. user ,
223+ resident_key,
224+ user_verification,
225+ algorithms : inner. params ,
226+ exclude,
227+ extensions,
228+ timeout : Duration :: from_secs ( inner. timeout ) ,
229+ } )
230+ }
231+ }
232+
233+ #[ derive( thiserror:: Error , Debug ) ]
234+ pub enum MakeCredentialRequestParsingError {
235+ /// The client must throw an "EncodingError" DOMException.
236+ #[ error( "Invalid JSON format: {0}" ) ]
237+ EncodingError ( #[ from] JsonError ) ,
238+
239+ #[ error( "Invalid extension: {0}" ) ]
240+ ExtensionError ( JsonError ) ,
241+ }
242+
243+ impl WebAuthnIDL < MakeCredentialRequestParsingError > for MakeCredentialRequest {
244+ type Error = MakeCredentialRequestParsingError ;
245+ type InnerModel = PublicKeyCredentialCreationOptionsJSON ;
246+ }
247+
178248#[ derive( Debug , Default , Clone ) ]
179249pub enum MakeCredentialHmacOrPrfInput {
180250 #[ default]
@@ -315,10 +385,7 @@ impl DowngradableRequest<RegisterRequest> for MakeCredentialRequest {
315385 }
316386
317387 // Options must not include "rk" set to true.
318- if matches ! (
319- self . resident_key,
320- Some ( ResidentKeyRequirement :: Required )
321- ) {
388+ if matches ! ( self . resident_key, Some ( ResidentKeyRequirement :: Required ) ) {
322389 debug ! ( "Not downgradable: request requires resident key" ) ;
323390 return false ;
324391 }
0 commit comments