tests.rs (9294B)
1 use super::{ 2 super::{super::PublicKeyCredentialHint, ExtensionReq}, 3 ClientCredentialRequestOptions, CredentialMediationRequirement, CredentialUiMode, 4 ExtensionOwned, FIVE_MINUTES, Hints, NonZeroU32, PublicKeyCredentialRequestOptionsOwned, 5 UserVerificationRequirement, 6 }; 7 use serde_json::Error; 8 #[expect( 9 clippy::panic_in_result_fn, 10 clippy::unwrap_used, 11 reason = "OK in tests" 12 )] 13 #[expect(clippy::cognitive_complexity, reason = "a lot to test")] 14 #[test] 15 fn client_options() -> Result<(), Error> { 16 let mut err = 17 serde_json::from_str::<ClientCredentialRequestOptions>(r#"{"bob":true}"#).unwrap_err(); 18 assert_eq!( 19 err.to_string().get(..71), 20 Some("unknown field `bob`, expected one of `mediation`, `uiMode`, `publicKey`") 21 ); 22 err = serde_json::from_str::<ClientCredentialRequestOptions>( 23 r#"{"mediation":"required","mediation":"required"}"#, 24 ) 25 .unwrap_err(); 26 assert_eq!( 27 err.to_string().get(..27), 28 Some("duplicate field `mediation`") 29 ); 30 let mut options = serde_json::from_str::<ClientCredentialRequestOptions>("{}")?; 31 assert!(matches!( 32 options.mediation, 33 CredentialMediationRequirement::Required 34 )); 35 assert!(options.ui_mode.is_none()); 36 assert!(options.public_key.rp_id.is_none()); 37 assert_eq!(options.public_key.timeout, FIVE_MINUTES); 38 assert!(matches!( 39 options.public_key.user_verification, 40 UserVerificationRequirement::Preferred 41 )); 42 assert_eq!(options.public_key.hints, Hints::EMPTY); 43 assert!(options.public_key.extensions.prf.is_none()); 44 options = serde_json::from_str::<ClientCredentialRequestOptions>( 45 r#"{"mediation":null,"uiMode":null,"publicKey":null}"#, 46 )?; 47 assert!(matches!( 48 options.mediation, 49 CredentialMediationRequirement::Required 50 )); 51 assert!(options.ui_mode.is_none()); 52 assert!(options.public_key.rp_id.is_none()); 53 assert_eq!(options.public_key.timeout, FIVE_MINUTES); 54 assert!(matches!( 55 options.public_key.user_verification, 56 UserVerificationRequirement::Preferred 57 )); 58 assert_eq!(options.public_key.hints, Hints::EMPTY); 59 assert!(options.public_key.extensions.prf.is_none()); 60 options = serde_json::from_str::<ClientCredentialRequestOptions>(r#"{"publicKey":{}}"#)?; 61 assert!(options.public_key.rp_id.is_none()); 62 assert_eq!(options.public_key.timeout, FIVE_MINUTES); 63 assert!(matches!( 64 options.public_key.user_verification, 65 UserVerificationRequirement::Preferred 66 )); 67 assert_eq!(options.public_key.hints, Hints::EMPTY); 68 assert!(options.public_key.extensions.prf.is_none()); 69 options = serde_json::from_str::<ClientCredentialRequestOptions>( 70 r#"{"mediation":"conditional","uiMode":"immediate","publicKey":{"rpId":"example.com","timeout":300000,"allowCredentials":[],"userVerification":"required","extensions":{"prf":{"eval":{"first":"","second":""}}},"hints":["security-key"],"challenge":null}}"#, 71 )?; 72 assert!(matches!( 73 options.mediation, 74 CredentialMediationRequirement::Conditional 75 )); 76 assert_eq!(options.ui_mode, Some(CredentialUiMode::Immediate)); 77 assert!( 78 options 79 .public_key 80 .rp_id 81 .is_some_and(|val| val.as_ref() == "example.com") 82 ); 83 assert_eq!(options.public_key.timeout, FIVE_MINUTES); 84 assert!(matches!( 85 options.public_key.user_verification, 86 UserVerificationRequirement::Required 87 )); 88 assert!( 89 options 90 .public_key 91 .extensions 92 .prf 93 .is_some_and(|prf| prf.first.is_empty() 94 && prf.second.is_some_and(|p| p.is_empty()) 95 && matches!(prf.ext_req, ExtensionReq::Allow)) 96 ); 97 Ok(()) 98 } 99 #[expect( 100 clippy::panic_in_result_fn, 101 clippy::unwrap_used, 102 reason = "OK in tests" 103 )] 104 #[expect(clippy::cognitive_complexity, reason = "a lot to test")] 105 #[test] 106 fn key_options() -> Result<(), Error> { 107 let mut err = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>(r#"{"bob":true}"#) 108 .unwrap_err(); 109 assert_eq!( 110 err.to_string().get(..130), 111 Some( 112 "unknown field `bob`, expected one of `rpId`, `userVerification`, `challenge`, `timeout`, `allowCredentials`, `hints`, `extensions`" 113 ) 114 ); 115 err = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 116 r#"{"rpId":"example.com","rpId":"example.com"}"#, 117 ) 118 .unwrap_err(); 119 assert_eq!(err.to_string().get(..22), Some("duplicate field `rpId`")); 120 err = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 121 r#"{"challenge":"AAAAAAAAAAAAAAAAAAAAAA"}"#, 122 ) 123 .unwrap_err(); 124 assert_eq!( 125 err.to_string().get(..41), 126 Some("invalid type: Option value, expected null") 127 ); 128 err = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 129 r#"{"allowCredentials":[{"type":"public-key","transports":["usb"],"id":"AAAAAAAAAAAAAAAAAAAAAA"}]}"#, 130 ) 131 .unwrap_err(); 132 assert_eq!(err.to_string().get(..19), Some("trailing characters")); 133 err = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>(r#"{"timeout":0}"#) 134 .unwrap_err(); 135 assert_eq!( 136 err.to_string().get(..50), 137 Some("invalid value: integer `0`, expected a nonzero u32") 138 ); 139 err = 140 serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>(r#"{"timeout":4294967296}"#) 141 .unwrap_err(); 142 assert_eq!( 143 err.to_string().get(..59), 144 Some("invalid value: integer `4294967296`, expected a nonzero u32") 145 ); 146 let mut key = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>("{}")?; 147 assert!(key.rp_id.is_none()); 148 assert_eq!(key.timeout, FIVE_MINUTES); 149 assert!(matches!( 150 key.user_verification, 151 UserVerificationRequirement::Preferred 152 )); 153 assert!(key.extensions.prf.is_none()); 154 assert_eq!(key.hints, Hints::EMPTY); 155 key = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 156 r#"{"rpId":null,"timeout":null,"allowCredentials":null,"userVerification":null,"extensions":null,"hints":null,"challenge":null}"#, 157 )?; 158 assert!(key.rp_id.is_none()); 159 assert_eq!(key.timeout, FIVE_MINUTES); 160 assert!(matches!( 161 key.user_verification, 162 UserVerificationRequirement::Preferred 163 )); 164 assert!(key.extensions.prf.is_none()); 165 assert_eq!(key.hints, Hints::EMPTY); 166 key = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 167 r#"{"allowCredentials":[],"extensions":{},"hints":[]}"#, 168 )?; 169 assert!(matches!( 170 key.user_verification, 171 UserVerificationRequirement::Preferred 172 )); 173 assert_eq!(key.hints, Hints::EMPTY); 174 assert!(key.extensions.prf.is_none()); 175 key = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 176 r#"{"extensions":{"prf":null}}"#, 177 )?; 178 assert!(key.extensions.prf.is_none()); 179 key = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 180 r#"{"rpId":"example.com","timeout":300000,"allowCredentials":[],"userVerification":"required","extensions":{"prf":{"eval":{"first":"","second":""}}},"hints":["security-key"],"challenge":null}"#, 181 )?; 182 assert!(key.rp_id.is_some_and(|val| val.as_ref() == "example.com")); 183 assert_eq!(key.timeout, FIVE_MINUTES); 184 assert!(matches!( 185 key.user_verification, 186 UserVerificationRequirement::Required 187 )); 188 assert_eq!( 189 key.hints, 190 Hints::EMPTY.add(PublicKeyCredentialHint::SecurityKey) 191 ); 192 assert!(key.extensions.prf.is_some_and(|prf| prf.first.is_empty() 193 && prf.second.is_some_and(|p| p.is_empty()) 194 && matches!(prf.ext_req, ExtensionReq::Allow))); 195 key = serde_json::from_str::<PublicKeyCredentialRequestOptionsOwned>( 196 r#"{"timeout":4294967295}"#, 197 )?; 198 assert_eq!(key.timeout, NonZeroU32::MAX); 199 Ok(()) 200 } 201 #[expect( 202 clippy::panic_in_result_fn, 203 clippy::unwrap_used, 204 reason = "OK in tests" 205 )] 206 #[test] 207 fn extension() -> Result<(), Error> { 208 let mut err = serde_json::from_str::<ExtensionOwned>(r#"{"bob":true}"#).unwrap_err(); 209 assert_eq!( 210 err.to_string().get(..35), 211 Some("unknown field `bob`, expected `prf`") 212 ); 213 err = serde_json::from_str::<ExtensionOwned>( 214 r#"{"prf":{"eval":{"first":"","second":""}},"prf":{"eval":{"first":"","second":""}}}"#, 215 ) 216 .unwrap_err(); 217 assert_eq!(err.to_string().get(..21), Some("duplicate field `prf`")); 218 err = serde_json::from_str::<ExtensionOwned>(r#"{"prf":{"eval":{"first":null}}}"#).unwrap_err(); 219 assert_eq!( 220 err.to_string().get(..51), 221 Some("invalid type: null, expected base64url-encoded data") 222 ); 223 let mut ext = 224 serde_json::from_str::<ExtensionOwned>(r#"{"prf":{"eval":{"first":"","second":""}}}"#)?; 225 assert!(ext.prf.is_some_and(|prf| prf.first.is_empty() 226 && prf.second.is_some_and(|v| v.is_empty()) 227 && matches!(prf.ext_req, ExtensionReq::Allow))); 228 ext = serde_json::from_str::<ExtensionOwned>(r#"{"prf":null}"#)?; 229 assert!(ext.prf.is_none()); 230 ext = serde_json::from_str::<ExtensionOwned>("{}")?; 231 assert!(ext.prf.is_none()); 232 Ok(()) 233 }