@@ -9,9 +9,12 @@ use tracing::{debug, instrument, trace};
99use crate :: {
1010 fido:: AuthenticatorData ,
1111 ops:: webauthn:: {
12- create:: PublicKeyCredentialCreationOptionsJSON ,
13- idl:: { Base64UrlString , FromInnerModel , JsonError , WebAuthnIDL } ,
14- rpid:: RelyingPartyId ,
12+ client_data:: ClientData ,
13+ idl:: {
14+ create:: PublicKeyCredentialCreationOptionsJSON , Base64UrlString , FromInnerModel ,
15+ JsonError , WebAuthnIDL ,
16+ } ,
17+ Operation , RelyingPartyId ,
1518 } ,
1619 proto:: {
1720 ctap1:: { Ctap1RegisteredKey , Ctap1Version } ,
@@ -162,7 +165,7 @@ impl MakeCredentialsResponseUnsignedExtensions {
162165 }
163166}
164167
165- #[ derive( Debug , Clone , Copy , Deserialize ) ]
168+ #[ derive( Debug , Clone , Copy , Deserialize , PartialEq ) ]
166169pub enum ResidentKeyRequirement {
167170 #[ serde( rename = "required" ) ]
168171 Required ,
@@ -172,7 +175,7 @@ pub enum ResidentKeyRequirement {
172175 Discouraged ,
173176}
174177
175- #[ derive( Debug , Clone ) ]
178+ #[ derive( Debug , Clone , PartialEq ) ]
176179pub struct MakeCredentialRequest {
177180 pub hash : Vec < u8 > ,
178181 pub origin : String ,
@@ -221,14 +224,21 @@ impl FromInnerModel<PublicKeyCredentialCreationOptionsJSON, MakeCredentialReques
221224
222225 let timeout: Duration = inner
223226 . timeout
224- . map ( |s| Duration :: from_secs ( s. into ( ) ) )
227+ . map ( |s| Duration :: from_millis ( s. into ( ) ) )
225228 . unwrap_or ( DEFAULT_TIMEOUT ) ;
226229
230+ let client_data_json = ClientData {
231+ operation : Operation :: MakeCredential ,
232+ challenge : inner. challenge . to_vec ( ) ,
233+ origin : rpid. to_string ( ) ,
234+ cross_origin : None ,
235+ } ;
236+
227237 Ok ( Self {
228- hash : inner . challenge . into ( ) ,
238+ hash : client_data_json . hash ( ) ,
229239 origin : rpid. to_owned ( ) . into ( ) ,
230240 relying_party : inner. rp ,
231- user : inner. user ,
241+ user : inner. user . into ( ) ,
232242 resident_key,
233243 user_verification,
234244 algorithms : inner. params ,
@@ -255,7 +265,7 @@ impl WebAuthnIDL<MakeCredentialRequestParsingError> for MakeCredentialRequest {
255265 type InnerModel = PublicKeyCredentialCreationOptionsJSON ;
256266}
257267
258- #[ derive( Debug , Clone , Deserialize ) ]
268+ #[ derive( Debug , Clone , Deserialize , PartialEq ) ]
259269pub struct MakeCredentialPrfInput {
260270 #[ serde( rename = "eval" ) ]
261271 pub _eval : Option < JsonValue > ,
@@ -267,7 +277,7 @@ pub struct MakeCredentialPrfOutput {
267277 pub enabled : Option < bool > ,
268278}
269279
270- #[ derive( Debug , Clone , Deserialize ) ]
280+ #[ derive( Debug , Clone , Deserialize , PartialEq ) ]
271281pub struct CredentialProtectionExtension {
272282 #[ serde( rename = "credentialProtectionPolicy" ) ]
273283 pub policy : CredentialProtectionPolicy ,
@@ -324,7 +334,7 @@ pub struct CredentialPropsExtension {
324334 pub rk : Option < bool > ,
325335}
326336
327- #[ derive( Debug , Default , Clone , Deserialize ) ]
337+ #[ derive( Debug , Default , Clone , Deserialize , PartialEq ) ]
328338pub struct MakeCredentialLargeBlobExtensionInput {
329339 pub support : MakeCredentialLargeBlobExtension ,
330340}
@@ -346,7 +356,7 @@ pub struct MakeCredentialLargeBlobExtensionOutput {
346356 pub supported : Option < bool > ,
347357}
348358
349- #[ derive( Debug , Default , Clone , Deserialize ) ]
359+ #[ derive( Debug , Default , Clone , Deserialize , PartialEq ) ]
350360pub struct MakeCredentialsRequestExtensions {
351361 #[ serde( rename = "credProps" ) ]
352362 pub cred_props : Option < bool > ,
@@ -452,3 +462,86 @@ impl DowngradableRequest<RegisterRequest> for MakeCredentialRequest {
452462 Ok ( downgraded)
453463 }
454464}
465+
466+ #[ cfg( test) ]
467+ mod tests {
468+ use std:: time:: Duration ;
469+
470+ use crate :: ops:: webauthn:: MakeCredentialRequest ;
471+ use crate :: ops:: webauthn:: RelyingPartyId ;
472+
473+ use super :: * ;
474+
475+ pub const REQUEST_BASE_JSON : & str = r#"
476+ {
477+ "rp": {
478+ "id": "example.org",
479+ "name": "example.org"
480+ },
481+ "user": {
482+ "id": "dXNlcmlk",
483+ "name": "mario.rossi",
484+ "displayName": "Mario Rossi"
485+ },
486+ "challenge": "Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu",
487+ "pubKeyCredParams": [
488+ {
489+ "type": "public-key",
490+ "alg": -7
491+ }
492+ ],
493+ "timeout": 30000,
494+ "excludeCredentials": [],
495+ "authenticatorSelection": {
496+ "residentKey": "discouraged",
497+ "userVerification": "preferred"
498+ },
499+ "attestation": "none",
500+ "attestationFormats": ["packed", "fido-u2f"]
501+ }
502+ "# ;
503+
504+ fn request_base ( ) -> MakeCredentialRequest {
505+ MakeCredentialRequest {
506+ origin : "example.org" . to_string ( ) ,
507+ hash : ClientData {
508+ operation : Operation :: MakeCredential ,
509+ challenge : base64_url:: decode ( "Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu" )
510+ . unwrap ( ) ,
511+ origin : "example.org" . to_string ( ) ,
512+ cross_origin : None ,
513+ }
514+ . hash ( ) ,
515+ relying_party : Ctap2PublicKeyCredentialRpEntity :: new ( "example.org" , "example.org" ) ,
516+ user : Ctap2PublicKeyCredentialUserEntity :: new ( b"userid" , "mario.rossi" , "Mario Rossi" ) ,
517+ resident_key : Some ( ResidentKeyRequirement :: Discouraged ) ,
518+ user_verification : UserVerificationRequirement :: Preferred ,
519+ algorithms : vec ! [ Ctap2CredentialType :: default ( ) ] ,
520+ exclude : None ,
521+ extensions : None ,
522+ timeout : Duration :: from_secs ( 30 ) ,
523+ }
524+ }
525+
526+ fn json_field_add ( str : & str , field : & str , value : & str ) -> String {
527+ let mut v: serde_json:: Value = serde_json:: from_str ( str) . unwrap ( ) ;
528+ v. as_object_mut ( )
529+ . unwrap ( )
530+ . insert ( field. to_owned ( ) , serde_json:: from_str ( value) . unwrap ( ) ) ;
531+ serde_json:: to_string ( & v) . unwrap ( )
532+ }
533+
534+ fn json_field_rm ( str : & str , field : & str ) -> String {
535+ let mut v: serde_json:: Value = serde_json:: from_str ( str) . unwrap ( ) ;
536+ v. as_object_mut ( ) . unwrap ( ) . remove ( field) ;
537+ serde_json:: to_string ( & v) . unwrap ( )
538+ }
539+
540+ #[ test]
541+ fn test_request_from_json_base ( ) {
542+ let rpid = RelyingPartyId :: try_from ( "example.org" ) . unwrap ( ) ;
543+ let req: MakeCredentialRequest =
544+ MakeCredentialRequest :: from_json ( & rpid, REQUEST_BASE_JSON ) . unwrap ( ) ;
545+ assert_eq ! ( req, request_base( ) ) ;
546+ }
547+ }
0 commit comments