tests.rs (57245B)
1 use super::{ 2 super::{super::super::request::register::USER_HANDLE_MIN_LEN, AuthenticatorAttachment}, 3 DiscoverableAuthenticationRelaxed, DiscoverableCustomAuthentication, 4 NonDiscoverableAuthenticationRelaxed, NonDiscoverableCustomAuthentication, 5 }; 6 use rsa::sha2::{Digest as _, Sha256}; 7 use serde::de::{Error as _, Unexpected}; 8 use serde_json::Error; 9 #[expect(clippy::unwrap_used, reason = "OK in tests")] 10 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 11 #[expect( 12 clippy::cognitive_complexity, 13 clippy::too_many_lines, 14 reason = "a lot to test" 15 )] 16 #[test] 17 fn eddsa_authentication_deserialize_data_mismatch() { 18 let c_data_json = serde_json::json!({}).to_string(); 19 let auth_data: [u8; 37] = [ 20 // `rpIdHash`. 21 0, 22 0, 23 0, 24 0, 25 0, 26 0, 27 0, 28 0, 29 0, 30 0, 31 0, 32 0, 33 0, 34 0, 35 0, 36 0, 37 0, 38 0, 39 0, 40 0, 41 0, 42 0, 43 0, 44 0, 45 0, 46 0, 47 0, 48 0, 49 0, 50 0, 51 0, 52 0, 53 // `flags`. 54 0b0000_0101, 55 // `signCount`. 56 0, 57 0, 58 0, 59 0, 60 ]; 61 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 62 let b64_adata = base64url_nopad::encode(auth_data.as_slice()); 63 let b64_sig = base64url_nopad::encode([].as_slice()); 64 let b64_user = base64url_nopad::encode(b"\x00".as_slice()); 65 // Base case is valid. 66 assert!( 67 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 68 serde_json::json!({ 69 "id": "AAAAAAAAAAAAAAAAAAAAAA", 70 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 71 "response": { 72 "clientDataJSON": b64_cdata_json, 73 "authenticatorData": b64_adata, 74 "signature": b64_sig, 75 "userHandle": b64_user, 76 }, 77 "authenticatorAttachment": "cross-platform", 78 "clientExtensionResults": {}, 79 "type": "public-key" 80 }) 81 .to_string() 82 .as_str() 83 ) 84 .is_ok_and( 85 |auth| auth.0.response.client_data_json == c_data_json.as_bytes() 86 && auth.0.response.authenticator_data_and_c_data_hash[..37] == auth_data 87 && auth.0.response.authenticator_data_and_c_data_hash[37..] 88 == *Sha256::digest(c_data_json.as_bytes()) 89 && matches!( 90 auth.0.authenticator_attachment, 91 AuthenticatorAttachment::CrossPlatform 92 ) 93 ) 94 ); 95 // `id` and `rawId` mismatch. 96 let mut err = Error::invalid_value( 97 Unexpected::Bytes( 98 base64url_nopad::decode(b"ABABABABABABABABABABAA") 99 .unwrap() 100 .as_slice(), 101 ), 102 &format!("id and rawId to match: CredentialId({:?})", [0u8; 16]).as_str(), 103 ) 104 .to_string() 105 .into_bytes(); 106 assert_eq!( 107 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 108 serde_json::json!({ 109 "id": "AAAAAAAAAAAAAAAAAAAAAA", 110 "rawId": "ABABABABABABABABABABAA", 111 "response": { 112 "clientDataJSON": b64_cdata_json, 113 "authenticatorData": b64_adata, 114 "signature": b64_sig, 115 "userHandle": b64_user, 116 }, 117 "authenticatorAttachment": "cross-platform", 118 "clientExtensionResults": {}, 119 "type": "public-key" 120 }) 121 .to_string() 122 .as_str() 123 ) 124 .unwrap_err() 125 .to_string() 126 .into_bytes() 127 .get(..err.len()), 128 Some(err.as_slice()) 129 ); 130 // missing `id`. 131 err = Error::missing_field("id").to_string().into_bytes(); 132 assert_eq!( 133 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 134 serde_json::json!({ 135 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 136 "response": { 137 "clientDataJSON": b64_cdata_json, 138 "authenticatorData": b64_adata, 139 "signature": b64_sig, 140 "userHandle": b64_user, 141 }, 142 "authenticatorAttachment": "cross-platform", 143 "clientExtensionResults": {}, 144 "type": "public-key" 145 }) 146 .to_string() 147 .as_str() 148 ) 149 .unwrap_err() 150 .to_string() 151 .into_bytes() 152 .get(..err.len()), 153 Some(err.as_slice()) 154 ); 155 // `null` `id`. 156 err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId") 157 .to_string() 158 .into_bytes(); 159 assert_eq!( 160 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 161 serde_json::json!({ 162 "id": null, 163 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 164 "response": { 165 "clientDataJSON": b64_cdata_json, 166 "authenticatorData": b64_adata, 167 "signature": b64_sig, 168 "userHandle": b64_user, 169 }, 170 "clientExtensionResults": {}, 171 "type": "public-key" 172 }) 173 .to_string() 174 .as_str() 175 ) 176 .unwrap_err() 177 .to_string() 178 .into_bytes() 179 .get(..err.len()), 180 Some(err.as_slice()) 181 ); 182 // missing `rawId`. 183 drop( 184 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 185 serde_json::json!({ 186 "id": "AAAAAAAAAAAAAAAAAAAAAA", 187 "response": { 188 "clientDataJSON": b64_cdata_json, 189 "authenticatorData": b64_adata, 190 "signature": b64_sig, 191 "userHandle": b64_user, 192 }, 193 "clientExtensionResults": {}, 194 "type": "public-key" 195 }) 196 .to_string() 197 .as_str(), 198 ) 199 .unwrap(), 200 ); 201 // `null` `rawId`. 202 err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId") 203 .to_string() 204 .into_bytes(); 205 assert_eq!( 206 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 207 serde_json::json!({ 208 "id": "AAAAAAAAAAAAAAAAAAAAAA", 209 "rawId": null, 210 "response": { 211 "clientDataJSON": b64_cdata_json, 212 "authenticatorData": b64_adata, 213 "signature": b64_sig, 214 "userHandle": b64_user, 215 }, 216 "clientExtensionResults": {}, 217 "type": "public-key" 218 }) 219 .to_string() 220 .as_str() 221 ) 222 .unwrap_err() 223 .to_string() 224 .into_bytes() 225 .get(..err.len()), 226 Some(err.as_slice()) 227 ); 228 // Missing `authenticatorData`. 229 err = Error::missing_field("authenticatorData") 230 .to_string() 231 .into_bytes(); 232 assert_eq!( 233 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 234 serde_json::json!({ 235 "id": "AAAAAAAAAAAAAAAAAAAAAA", 236 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 237 "response": { 238 "clientDataJSON": b64_cdata_json, 239 "signature": b64_sig, 240 "userHandle": b64_user, 241 }, 242 "clientExtensionResults": {}, 243 "type": "public-key" 244 }) 245 .to_string() 246 .as_str() 247 ) 248 .unwrap_err() 249 .to_string() 250 .into_bytes() 251 .get(..err.len()), 252 Some(err.as_slice()) 253 ); 254 // `null` `authenticatorData`. 255 err = Error::invalid_type(Unexpected::Other("null"), &"AuthenticatorData") 256 .to_string() 257 .into_bytes(); 258 assert_eq!( 259 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 260 serde_json::json!({ 261 "id": "AAAAAAAAAAAAAAAAAAAAAA", 262 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 263 "response": { 264 "clientDataJSON": b64_cdata_json, 265 "authenticatorData": null, 266 "signature": b64_sig, 267 "userHandle": b64_user, 268 }, 269 "clientExtensionResults": {}, 270 "type": "public-key" 271 }) 272 .to_string() 273 .as_str() 274 ) 275 .unwrap_err() 276 .to_string() 277 .into_bytes() 278 .get(..err.len()), 279 Some(err.as_slice()) 280 ); 281 // Missing `signature`. 282 err = Error::missing_field("signature").to_string().into_bytes(); 283 assert_eq!( 284 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 285 serde_json::json!({ 286 "id": "AAAAAAAAAAAAAAAAAAAAAA", 287 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 288 "response": { 289 "clientDataJSON": b64_cdata_json, 290 "authenticatorData": b64_adata, 291 "userHandle": b64_user, 292 }, 293 "clientExtensionResults": {}, 294 "type": "public-key" 295 }) 296 .to_string() 297 .as_str() 298 ) 299 .unwrap_err() 300 .to_string() 301 .into_bytes() 302 .get(..err.len()), 303 Some(err.as_slice()) 304 ); 305 // `null` `signature`. 306 err = Error::invalid_type(Unexpected::Other("null"), &"base64url-encoded data") 307 .to_string() 308 .into_bytes(); 309 assert_eq!( 310 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 311 serde_json::json!({ 312 "id": "AAAAAAAAAAAAAAAAAAAAAA", 313 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 314 "response": { 315 "clientDataJSON": b64_cdata_json, 316 "authenticatorData": b64_adata, 317 "signature": null, 318 "userHandle": b64_user, 319 }, 320 "clientExtensionResults": {}, 321 "type": "public-key" 322 }) 323 .to_string() 324 .as_str() 325 ) 326 .unwrap_err() 327 .to_string() 328 .into_bytes() 329 .get(..err.len()), 330 Some(err.as_slice()) 331 ); 332 // Missing `userHandle`. 333 drop( 334 serde_json::from_str::<NonDiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 335 serde_json::json!({ 336 "id": "AAAAAAAAAAAAAAAAAAAAAA", 337 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 338 "response": { 339 "clientDataJSON": b64_cdata_json, 340 "authenticatorData": b64_adata, 341 "signature": b64_sig, 342 }, 343 "clientExtensionResults": {}, 344 "type": "public-key" 345 }) 346 .to_string() 347 .as_str(), 348 ) 349 .unwrap(), 350 ); 351 // `null` `userHandle`. 352 drop( 353 serde_json::from_str::<NonDiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 354 serde_json::json!({ 355 "id": "AAAAAAAAAAAAAAAAAAAAAA", 356 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 357 "response": { 358 "clientDataJSON": b64_cdata_json, 359 "authenticatorData": b64_adata, 360 "signature": b64_sig, 361 "userHandle": null, 362 }, 363 "clientExtensionResults": {}, 364 "type": "public-key" 365 }) 366 .to_string() 367 .as_str(), 368 ) 369 .unwrap(), 370 ); 371 // `null` `authenticatorAttachment`. 372 assert!( 373 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 374 serde_json::json!({ 375 "id": "AAAAAAAAAAAAAAAAAAAAAA", 376 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 377 "response": { 378 "clientDataJSON": b64_cdata_json, 379 "authenticatorData": b64_adata, 380 "signature": b64_sig, 381 "userHandle": b64_user, 382 }, 383 "authenticatorAttachment": null, 384 "clientExtensionResults": {}, 385 "type": "public-key" 386 }) 387 .to_string() 388 .as_str() 389 ) 390 .is_ok_and(|auth| matches!( 391 auth.0.authenticator_attachment, 392 AuthenticatorAttachment::None 393 )) 394 ); 395 // Unknown `authenticatorAttachment`. 396 err = Error::invalid_value( 397 Unexpected::Str("Platform"), 398 &"'platform' or 'cross-platform'", 399 ) 400 .to_string() 401 .into_bytes(); 402 assert_eq!( 403 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 404 serde_json::json!({ 405 "id": "AAAAAAAAAAAAAAAAAAAAAA", 406 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 407 "response": { 408 "clientDataJSON": b64_cdata_json, 409 "authenticatorData": b64_adata, 410 "signature": b64_sig, 411 "userHandle": b64_user, 412 }, 413 "authenticatorAttachment": "Platform", 414 "clientExtensionResults": {}, 415 "type": "public-key" 416 }) 417 .to_string() 418 .as_str() 419 ) 420 .unwrap_err() 421 .to_string() 422 .into_bytes() 423 .get(..err.len()), 424 Some(err.as_slice()) 425 ); 426 // Missing `clientDataJSON`. 427 err = Error::missing_field("clientDataJSON") 428 .to_string() 429 .into_bytes(); 430 assert_eq!( 431 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 432 serde_json::json!({ 433 "id": "AAAAAAAAAAAAAAAAAAAAAA", 434 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 435 "response": { 436 "authenticatorData": b64_adata, 437 "signature": b64_sig, 438 "userHandle": b64_user, 439 }, 440 "clientExtensionResults": {}, 441 "type": "public-key" 442 }) 443 .to_string() 444 .as_str() 445 ) 446 .unwrap_err() 447 .to_string() 448 .into_bytes() 449 .get(..err.len()), 450 Some(err.as_slice()) 451 ); 452 // `null` `clientDataJSON`. 453 err = Error::invalid_type(Unexpected::Other("null"), &"base64url-encoded data") 454 .to_string() 455 .into_bytes(); 456 assert_eq!( 457 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 458 serde_json::json!({ 459 "id": "AAAAAAAAAAAAAAAAAAAAAA", 460 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 461 "response": { 462 "clientDataJSON": null, 463 "authenticatorData": b64_adata, 464 "signature": b64_sig, 465 "userHandle": b64_user, 466 }, 467 "clientExtensionResults": {}, 468 "type": "public-key" 469 }) 470 .to_string() 471 .as_str() 472 ) 473 .unwrap_err() 474 .to_string() 475 .into_bytes() 476 .get(..err.len()), 477 Some(err.as_slice()) 478 ); 479 // Missing `response`. 480 err = Error::missing_field("response").to_string().into_bytes(); 481 assert_eq!( 482 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 483 serde_json::json!({ 484 "id": "AAAAAAAAAAAAAAAAAAAAAA", 485 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 486 "clientExtensionResults": {}, 487 "type": "public-key" 488 }) 489 .to_string() 490 .as_str() 491 ) 492 .unwrap_err() 493 .to_string() 494 .into_bytes() 495 .get(..err.len()), 496 Some(err.as_slice()) 497 ); 498 // `null` `response`. 499 err = Error::invalid_type(Unexpected::Other("null"), &"AuthenticatorAssertion") 500 .to_string() 501 .into_bytes(); 502 assert_eq!( 503 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 504 serde_json::json!({ 505 "id": "AAAAAAAAAAAAAAAAAAAAAA", 506 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 507 "response": null, 508 "clientExtensionResults": {}, 509 "type": "public-key" 510 }) 511 .to_string() 512 .as_str() 513 ) 514 .unwrap_err() 515 .to_string() 516 .into_bytes() 517 .get(..err.len()), 518 Some(err.as_slice()) 519 ); 520 // Empty `response`. 521 err = Error::missing_field("clientDataJSON") 522 .to_string() 523 .into_bytes(); 524 assert_eq!( 525 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 526 serde_json::json!({ 527 "id": "AAAAAAAAAAAAAAAAAAAAAA", 528 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 529 "response": {}, 530 "clientExtensionResults": {}, 531 "type": "public-key" 532 }) 533 .to_string() 534 .as_str() 535 ) 536 .unwrap_err() 537 .to_string() 538 .into_bytes() 539 .get(..err.len()), 540 Some(err.as_slice()) 541 ); 542 // Missing `clientExtensionResults`. 543 drop( 544 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 545 serde_json::json!({ 546 "id": "AAAAAAAAAAAAAAAAAAAAAA", 547 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 548 "response": { 549 "clientDataJSON": b64_cdata_json, 550 "authenticatorData": b64_adata, 551 "signature": b64_sig, 552 "userHandle": b64_user, 553 }, 554 "type": "public-key" 555 }) 556 .to_string() 557 .as_str(), 558 ) 559 .unwrap(), 560 ); 561 // `null` `clientExtensionResults`. 562 drop( 563 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 564 serde_json::json!({ 565 "id": "AAAAAAAAAAAAAAAAAAAAAA", 566 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 567 "response": { 568 "clientDataJSON": b64_cdata_json, 569 "authenticatorData": b64_adata, 570 "signature": b64_sig, 571 "userHandle": b64_user, 572 }, 573 "clientExtensionResults": null, 574 "type": "public-key" 575 }) 576 .to_string() 577 .as_str(), 578 ) 579 .unwrap(), 580 ); 581 // Missing `type`. 582 drop( 583 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 584 serde_json::json!({ 585 "id": "AAAAAAAAAAAAAAAAAAAAAA", 586 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 587 "response": { 588 "clientDataJSON": b64_cdata_json, 589 "authenticatorData": b64_adata, 590 "signature": b64_sig, 591 "userHandle": b64_user, 592 }, 593 "clientExtensionResults": {}, 594 }) 595 .to_string() 596 .as_str(), 597 ) 598 .unwrap(), 599 ); 600 // `null` `type`. 601 err = Error::invalid_type(Unexpected::Other("null"), &"public-key") 602 .to_string() 603 .into_bytes(); 604 assert_eq!( 605 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 606 serde_json::json!({ 607 "id": "AAAAAAAAAAAAAAAAAAAAAA", 608 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 609 "response": { 610 "clientDataJSON": b64_cdata_json, 611 "authenticatorData": b64_adata, 612 "signature": b64_sig, 613 "userHandle": b64_user, 614 }, 615 "clientExtensionResults": {}, 616 "type": null 617 }) 618 .to_string() 619 .as_str() 620 ) 621 .unwrap_err() 622 .to_string() 623 .into_bytes() 624 .get(..err.len()), 625 Some(err.as_slice()) 626 ); 627 // Not exactly `public-type` `type`. 628 err = Error::invalid_value(Unexpected::Str("Public-key"), &"public-key") 629 .to_string() 630 .into_bytes(); 631 assert_eq!( 632 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 633 serde_json::json!({ 634 "id": "AAAAAAAAAAAAAAAAAAAAAA", 635 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 636 "response": { 637 "clientDataJSON": b64_cdata_json, 638 "authenticatorData": b64_adata, 639 "signature": b64_sig, 640 "userHandle": b64_user, 641 }, 642 "clientExtensionResults": {}, 643 "type": "Public-key" 644 }) 645 .to_string() 646 .as_str() 647 ) 648 .unwrap_err() 649 .to_string() 650 .into_bytes() 651 .get(..err.len()), 652 Some(err.as_slice()) 653 ); 654 // `null`. 655 err = Error::invalid_type(Unexpected::Other("null"), &"PublicKeyCredential") 656 .to_string() 657 .into_bytes(); 658 assert_eq!( 659 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 660 serde_json::json!(null).to_string().as_str() 661 ) 662 .unwrap_err() 663 .to_string() 664 .into_bytes() 665 .get(..err.len()), 666 Some(err.as_slice()) 667 ); 668 // Empty. 669 err = Error::missing_field("response").to_string().into_bytes(); 670 assert_eq!( 671 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 672 serde_json::json!({}).to_string().as_str() 673 ) 674 .unwrap_err() 675 .to_string() 676 .into_bytes() 677 .get(..err.len()), 678 Some(err.as_slice()) 679 ); 680 // Unknown field in `response`. 681 drop( 682 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 683 serde_json::json!({ 684 "id": "AAAAAAAAAAAAAAAAAAAAAA", 685 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 686 "response": { 687 "clientDataJSON": b64_cdata_json, 688 "authenticatorData": b64_adata, 689 "signature": b64_sig, 690 "userHandle": b64_user, 691 "foo": true, 692 }, 693 "clientExtensionResults": {}, 694 "type": "public-key" 695 }) 696 .to_string() 697 .as_str(), 698 ) 699 .unwrap(), 700 ); 701 // Duplicate field in `response`. 702 err = Error::duplicate_field("userHandle") 703 .to_string() 704 .into_bytes(); 705 assert_eq!( 706 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 707 format!( 708 "{{ 709 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 710 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 711 \"response\": {{ 712 \"clientDataJSON\": \"{b64_cdata_json}\", 713 \"authenticatorData\": \"{b64_adata}\", 714 \"signature\": \"{b64_sig}\", 715 \"userHandle\": \"{b64_user}\", 716 \"userHandle\": \"{b64_user}\" 717 }}, 718 \"clientExtensionResults\": {{}}, 719 \"type\": \"public-key\" 720 }}" 721 ) 722 .as_str() 723 ) 724 .unwrap_err() 725 .to_string() 726 .into_bytes() 727 .get(..err.len()), 728 Some(err.as_slice()) 729 ); 730 // Unknown field in `PublicKeyCredential`. 731 drop( 732 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 733 serde_json::json!({ 734 "id": "AAAAAAAAAAAAAAAAAAAAAA", 735 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 736 "response": { 737 "clientDataJSON": b64_cdata_json, 738 "authenticatorData": b64_adata, 739 "signature": b64_sig, 740 "userHandle": b64_user, 741 }, 742 "clientExtensionResults": {}, 743 "type": "public-key", 744 "foo": true, 745 }) 746 .to_string() 747 .as_str(), 748 ) 749 .unwrap(), 750 ); 751 // Duplicate field in `PublicKeyCredential`. 752 err = Error::duplicate_field("id").to_string().into_bytes(); 753 assert_eq!( 754 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 755 format!( 756 "{{ 757 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 758 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 759 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 760 \"response\": {{ 761 \"clientDataJSON\": \"{b64_cdata_json}\", 762 \"authenticatorData\": \"{b64_adata}\", 763 \"signature\": \"{b64_sig}\", 764 \"userHandle\": \"{b64_user}\" 765 }}, 766 \"clientExtensionResults\": {{}}, 767 \"type\": \"public-key\" 768 }}" 769 ) 770 .as_str() 771 ) 772 .unwrap_err() 773 .to_string() 774 .into_bytes() 775 .get(..err.len()), 776 Some(err.as_slice()) 777 ); 778 // Base case is valid. 779 assert!( 780 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 781 serde_json::json!({ 782 "id": "AAAAAAAAAAAAAAAAAAAAAA", 783 "clientDataJSON": b64_cdata_json, 784 "authenticatorData": b64_adata, 785 "signature": b64_sig, 786 "userHandle": b64_user, 787 "authenticatorAttachment": "cross-platform", 788 "clientExtensionResults": {}, 789 "type": "public-key" 790 }) 791 .to_string() 792 .as_str() 793 ) 794 .is_ok_and( 795 |auth| auth.0.response.client_data_json == c_data_json.as_bytes() 796 && auth.0.response.authenticator_data_and_c_data_hash[..37] == auth_data 797 && auth.0.response.authenticator_data_and_c_data_hash[37..] 798 == *Sha256::digest(c_data_json.as_bytes()) 799 && matches!( 800 auth.0.authenticator_attachment, 801 AuthenticatorAttachment::CrossPlatform 802 ) 803 ) 804 ); 805 // missing `id`. 806 err = Error::missing_field("id").to_string().into_bytes(); 807 assert_eq!( 808 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 809 serde_json::json!({ 810 "clientDataJSON": b64_cdata_json, 811 "authenticatorData": b64_adata, 812 "signature": b64_sig, 813 "userHandle": b64_user, 814 "authenticatorAttachment": "cross-platform", 815 "clientExtensionResults": {}, 816 "type": "public-key" 817 }) 818 .to_string() 819 .as_str() 820 ) 821 .unwrap_err() 822 .to_string() 823 .into_bytes() 824 .get(..err.len()), 825 Some(err.as_slice()) 826 ); 827 // `null` `id`. 828 err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId") 829 .to_string() 830 .into_bytes(); 831 assert_eq!( 832 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 833 serde_json::json!({ 834 "id": null, 835 "clientDataJSON": b64_cdata_json, 836 "authenticatorData": b64_adata, 837 "signature": b64_sig, 838 "userHandle": b64_user, 839 "clientExtensionResults": {}, 840 "type": "public-key" 841 }) 842 .to_string() 843 .as_str() 844 ) 845 .unwrap_err() 846 .to_string() 847 .into_bytes() 848 .get(..err.len()), 849 Some(err.as_slice()) 850 ); 851 // Missing `authenticatorData`. 852 err = Error::missing_field("authenticatorData") 853 .to_string() 854 .into_bytes(); 855 assert_eq!( 856 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 857 serde_json::json!({ 858 "id": "AAAAAAAAAAAAAAAAAAAAAA", 859 "clientDataJSON": b64_cdata_json, 860 "signature": b64_sig, 861 "userHandle": b64_user, 862 "clientExtensionResults": {}, 863 "type": "public-key" 864 }) 865 .to_string() 866 .as_str() 867 ) 868 .unwrap_err() 869 .to_string() 870 .into_bytes() 871 .get(..err.len()), 872 Some(err.as_slice()) 873 ); 874 // `null` `authenticatorData`. 875 err = Error::invalid_type(Unexpected::Other("null"), &"AuthenticatorData") 876 .to_string() 877 .into_bytes(); 878 assert_eq!( 879 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 880 serde_json::json!({ 881 "id": "AAAAAAAAAAAAAAAAAAAAAA", 882 "clientDataJSON": b64_cdata_json, 883 "authenticatorData": null, 884 "signature": b64_sig, 885 "userHandle": b64_user, 886 "clientExtensionResults": {}, 887 "type": "public-key" 888 }) 889 .to_string() 890 .as_str() 891 ) 892 .unwrap_err() 893 .to_string() 894 .into_bytes() 895 .get(..err.len()), 896 Some(err.as_slice()) 897 ); 898 // Missing `signature`. 899 err = Error::missing_field("signature").to_string().into_bytes(); 900 assert_eq!( 901 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 902 serde_json::json!({ 903 "id": "AAAAAAAAAAAAAAAAAAAAAA", 904 "clientDataJSON": b64_cdata_json, 905 "authenticatorData": b64_adata, 906 "userHandle": b64_user, 907 "clientExtensionResults": {}, 908 "type": "public-key" 909 }) 910 .to_string() 911 .as_str() 912 ) 913 .unwrap_err() 914 .to_string() 915 .into_bytes() 916 .get(..err.len()), 917 Some(err.as_slice()) 918 ); 919 // `null` `signature`. 920 err = Error::invalid_type(Unexpected::Other("null"), &"base64url-encoded data") 921 .to_string() 922 .into_bytes(); 923 assert_eq!( 924 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 925 serde_json::json!({ 926 "id": "AAAAAAAAAAAAAAAAAAAAAA", 927 "clientDataJSON": b64_cdata_json, 928 "authenticatorData": b64_adata, 929 "signature": null, 930 "userHandle": b64_user, 931 "clientExtensionResults": {}, 932 "type": "public-key" 933 }) 934 .to_string() 935 .as_str() 936 ) 937 .unwrap_err() 938 .to_string() 939 .into_bytes() 940 .get(..err.len()), 941 Some(err.as_slice()) 942 ); 943 // Missing `userHandle`. 944 drop( 945 serde_json::from_str::<NonDiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 946 serde_json::json!({ 947 "id": "AAAAAAAAAAAAAAAAAAAAAA", 948 "clientDataJSON": b64_cdata_json, 949 "authenticatorData": b64_adata, 950 "signature": b64_sig, 951 "clientExtensionResults": {}, 952 "type": "public-key" 953 }) 954 .to_string() 955 .as_str(), 956 ) 957 .unwrap(), 958 ); 959 // `null` `userHandle`. 960 drop( 961 serde_json::from_str::<NonDiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 962 serde_json::json!({ 963 "id": "AAAAAAAAAAAAAAAAAAAAAA", 964 "clientDataJSON": b64_cdata_json, 965 "authenticatorData": b64_adata, 966 "signature": b64_sig, 967 "userHandle": null, 968 "clientExtensionResults": {}, 969 "type": "public-key" 970 }) 971 .to_string() 972 .as_str(), 973 ) 974 .unwrap(), 975 ); 976 // `null` `authenticatorAttachment`. 977 assert!( 978 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 979 serde_json::json!({ 980 "id": "AAAAAAAAAAAAAAAAAAAAAA", 981 "clientDataJSON": b64_cdata_json, 982 "authenticatorData": b64_adata, 983 "signature": b64_sig, 984 "userHandle": b64_user, 985 "authenticatorAttachment": null, 986 "clientExtensionResults": {}, 987 "type": "public-key" 988 }) 989 .to_string() 990 .as_str() 991 ) 992 .is_ok_and(|auth| matches!( 993 auth.0.authenticator_attachment, 994 AuthenticatorAttachment::None 995 )) 996 ); 997 // Unknown `authenticatorAttachment`. 998 err = Error::invalid_value( 999 Unexpected::Str("Platform"), 1000 &"'platform' or 'cross-platform'", 1001 ) 1002 .to_string() 1003 .into_bytes(); 1004 assert_eq!( 1005 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1006 serde_json::json!({ 1007 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1008 "clientDataJSON": b64_cdata_json, 1009 "authenticatorData": b64_adata, 1010 "signature": b64_sig, 1011 "userHandle": b64_user, 1012 "authenticatorAttachment": "Platform", 1013 "clientExtensionResults": {}, 1014 "type": "public-key" 1015 }) 1016 .to_string() 1017 .as_str() 1018 ) 1019 .unwrap_err() 1020 .to_string() 1021 .into_bytes() 1022 .get(..err.len()), 1023 Some(err.as_slice()) 1024 ); 1025 // Missing `clientDataJSON`. 1026 err = Error::missing_field("clientDataJSON") 1027 .to_string() 1028 .into_bytes(); 1029 assert_eq!( 1030 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1031 serde_json::json!({ 1032 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1033 "authenticatorData": b64_adata, 1034 "signature": b64_sig, 1035 "userHandle": b64_user, 1036 "clientExtensionResults": {}, 1037 "type": "public-key" 1038 }) 1039 .to_string() 1040 .as_str() 1041 ) 1042 .unwrap_err() 1043 .to_string() 1044 .into_bytes() 1045 .get(..err.len()), 1046 Some(err.as_slice()) 1047 ); 1048 // `null` `clientDataJSON`. 1049 err = Error::invalid_type(Unexpected::Other("null"), &"base64url-encoded data") 1050 .to_string() 1051 .into_bytes(); 1052 assert_eq!( 1053 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1054 serde_json::json!({ 1055 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1056 "clientDataJSON": null, 1057 "authenticatorData": b64_adata, 1058 "signature": b64_sig, 1059 "userHandle": b64_user, 1060 "clientExtensionResults": {}, 1061 "type": "public-key" 1062 }) 1063 .to_string() 1064 .as_str() 1065 ) 1066 .unwrap_err() 1067 .to_string() 1068 .into_bytes() 1069 .get(..err.len()), 1070 Some(err.as_slice()) 1071 ); 1072 // Empty. 1073 err = Error::missing_field("authenticatorData") 1074 .to_string() 1075 .into_bytes(); 1076 assert_eq!( 1077 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1078 serde_json::json!({}).to_string().as_str() 1079 ) 1080 .unwrap_err() 1081 .to_string() 1082 .into_bytes() 1083 .get(..err.len()), 1084 Some(err.as_slice()) 1085 ); 1086 // Missing `clientExtensionResults`. 1087 err = Error::missing_field("clientExtensionResults") 1088 .to_string() 1089 .into_bytes(); 1090 assert_eq!( 1091 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1092 serde_json::json!({ 1093 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1094 "clientDataJSON": b64_cdata_json, 1095 "authenticatorData": b64_adata, 1096 "signature": b64_sig, 1097 "userHandle": b64_user, 1098 "type": "public-key" 1099 }) 1100 .to_string() 1101 .as_str() 1102 ) 1103 .unwrap_err() 1104 .to_string() 1105 .into_bytes() 1106 .get(..err.len()), 1107 Some(err.as_slice()) 1108 ); 1109 // `null` `clientExtensionResults`. 1110 err = Error::invalid_type(Unexpected::Other("null"), &"ClientExtensionsOutputs") 1111 .to_string() 1112 .into_bytes(); 1113 assert_eq!( 1114 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1115 serde_json::json!({ 1116 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1117 "clientDataJSON": b64_cdata_json, 1118 "authenticatorData": b64_adata, 1119 "signature": b64_sig, 1120 "userHandle": b64_user, 1121 "clientExtensionResults": null, 1122 "type": "public-key" 1123 }) 1124 .to_string() 1125 .as_str() 1126 ) 1127 .unwrap_err() 1128 .to_string() 1129 .into_bytes() 1130 .get(..err.len()), 1131 Some(err.as_slice()) 1132 ); 1133 drop( 1134 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1135 serde_json::json!({ 1136 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1137 "clientDataJSON": b64_cdata_json, 1138 "authenticatorData": b64_adata, 1139 "signature": b64_sig, 1140 "userHandle": b64_user, 1141 "clientExtensionResults": {}, 1142 }) 1143 .to_string() 1144 .as_str(), 1145 ) 1146 .unwrap(), 1147 ); 1148 // `null` `type`. 1149 err = Error::invalid_type(Unexpected::Other("null"), &"public-key") 1150 .to_string() 1151 .into_bytes(); 1152 assert_eq!( 1153 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1154 serde_json::json!({ 1155 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1156 "clientDataJSON": b64_cdata_json, 1157 "authenticatorData": b64_adata, 1158 "signature": b64_sig, 1159 "userHandle": b64_user, 1160 "clientExtensionResults": {}, 1161 "type": null 1162 }) 1163 .to_string() 1164 .as_str() 1165 ) 1166 .unwrap_err() 1167 .to_string() 1168 .into_bytes() 1169 .get(..err.len()), 1170 Some(err.as_slice()) 1171 ); 1172 // Not exactly `public-type` `type`. 1173 err = Error::invalid_value(Unexpected::Str("Public-key"), &"public-key") 1174 .to_string() 1175 .into_bytes(); 1176 assert_eq!( 1177 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1178 serde_json::json!({ 1179 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1180 "clientDataJSON": b64_cdata_json, 1181 "authenticatorData": b64_adata, 1182 "signature": b64_sig, 1183 "userHandle": b64_user, 1184 "clientExtensionResults": {}, 1185 "type": "Public-key" 1186 }) 1187 .to_string() 1188 .as_str() 1189 ) 1190 .unwrap_err() 1191 .to_string() 1192 .into_bytes() 1193 .get(..err.len()), 1194 Some(err.as_slice()) 1195 ); 1196 // `null`. 1197 err = Error::invalid_type(Unexpected::Other("null"), &"CustomAuthentication") 1198 .to_string() 1199 .into_bytes(); 1200 assert_eq!( 1201 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1202 serde_json::json!(null).to_string().as_str() 1203 ) 1204 .unwrap_err() 1205 .to_string() 1206 .into_bytes() 1207 .get(..err.len()), 1208 Some(err.as_slice()) 1209 ); 1210 // Unknown field. 1211 err = Error::unknown_field( 1212 "foo", 1213 [ 1214 "authenticatorAttachment", 1215 "authenticatorData", 1216 "clientDataJSON", 1217 "clientExtensionResults", 1218 "id", 1219 "signature", 1220 "type", 1221 "userHandle", 1222 ] 1223 .as_slice(), 1224 ) 1225 .to_string() 1226 .into_bytes(); 1227 assert_eq!( 1228 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1229 serde_json::json!({ 1230 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1231 "clientDataJSON": b64_cdata_json, 1232 "authenticatorData": b64_adata, 1233 "signature": b64_sig, 1234 "userHandle": b64_user, 1235 "foo": true, 1236 "clientExtensionResults": {}, 1237 "type": "public-key" 1238 }) 1239 .to_string() 1240 .as_str() 1241 ) 1242 .unwrap_err() 1243 .to_string() 1244 .into_bytes() 1245 .get(..err.len()), 1246 Some(err.as_slice()) 1247 ); 1248 // Duplicate field. 1249 err = Error::duplicate_field("userHandle") 1250 .to_string() 1251 .into_bytes(); 1252 assert_eq!( 1253 serde_json::from_str::<DiscoverableCustomAuthentication<USER_HANDLE_MIN_LEN>>( 1254 format!( 1255 "{{ 1256 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1257 \"clientDataJSON\": \"{b64_cdata_json}\", 1258 \"authenticatorData\": \"{b64_adata}\", 1259 \"signature\": \"{b64_sig}\", 1260 \"userHandle\": \"{b64_user}\", 1261 \"userHandle\": \"{b64_user}\" 1262 \"clientExtensionResults\": {{}}, 1263 \"type\": \"public-key\" 1264 }}" 1265 ) 1266 .as_str() 1267 ) 1268 .unwrap_err() 1269 .to_string() 1270 .into_bytes() 1271 .get(..err.len()), 1272 Some(err.as_slice()) 1273 ); 1274 } 1275 #[expect(clippy::unwrap_used, reason = "OK in tests")] 1276 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 1277 #[expect(clippy::too_many_lines, reason = "a lot to test")] 1278 #[test] 1279 fn client_extensions() { 1280 let c_data_json = serde_json::json!({}).to_string(); 1281 let auth_data: [u8; 37] = [ 1282 // `rpIdHash`. 1283 0, 1284 0, 1285 0, 1286 0, 1287 0, 1288 0, 1289 0, 1290 0, 1291 0, 1292 0, 1293 0, 1294 0, 1295 0, 1296 0, 1297 0, 1298 0, 1299 0, 1300 0, 1301 0, 1302 0, 1303 0, 1304 0, 1305 0, 1306 0, 1307 0, 1308 0, 1309 0, 1310 0, 1311 0, 1312 0, 1313 0, 1314 0, 1315 // `flags`. 1316 0b0000_0101, 1317 // `signCount`. 1318 0, 1319 0, 1320 0, 1321 0, 1322 ]; 1323 let b64_cdata_json = base64url_nopad::encode(c_data_json.as_bytes()); 1324 let b64_adata = base64url_nopad::encode(auth_data.as_slice()); 1325 let b64_sig = base64url_nopad::encode([].as_slice()); 1326 let b64_user = base64url_nopad::encode(b"\x00".as_slice()); 1327 // Base case is valid. 1328 assert!( 1329 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1330 serde_json::json!({ 1331 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1332 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1333 "response": { 1334 "clientDataJSON": b64_cdata_json, 1335 "authenticatorData": b64_adata, 1336 "signature": b64_sig, 1337 "userHandle": b64_user, 1338 }, 1339 "authenticatorAttachment": "cross-platform", 1340 "clientExtensionResults": {}, 1341 "type": "public-key" 1342 }) 1343 .to_string() 1344 .as_str() 1345 ) 1346 .is_ok_and( 1347 |auth| auth.0.response.client_data_json == c_data_json.as_bytes() 1348 && auth.0.response.authenticator_data_and_c_data_hash[..37] == auth_data 1349 && auth.0.response.authenticator_data_and_c_data_hash[37..] 1350 == *Sha256::digest(c_data_json.as_bytes()) 1351 && matches!( 1352 auth.0.authenticator_attachment, 1353 AuthenticatorAttachment::CrossPlatform 1354 ) 1355 ) 1356 ); 1357 // `null` `prf`. 1358 drop( 1359 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1360 serde_json::json!({ 1361 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1362 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1363 "response": { 1364 "clientDataJSON": b64_cdata_json, 1365 "authenticatorData": b64_adata, 1366 "signature": b64_sig, 1367 "userHandle": b64_user, 1368 }, 1369 "clientExtensionResults": { 1370 "prf": null 1371 }, 1372 "type": "public-key" 1373 }) 1374 .to_string() 1375 .as_str(), 1376 ) 1377 .unwrap(), 1378 ); 1379 // Unknown `clientExtensionResults`. 1380 drop( 1381 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1382 serde_json::json!({ 1383 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1384 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1385 "response": { 1386 "clientDataJSON": b64_cdata_json, 1387 "authenticatorData": b64_adata, 1388 "signature": b64_sig, 1389 "userHandle": b64_user, 1390 }, 1391 "clientExtensionResults": { 1392 "Prf": null 1393 }, 1394 "type": "public-key" 1395 }) 1396 .to_string() 1397 .as_str(), 1398 ) 1399 .unwrap(), 1400 ); 1401 // Duplicate field. 1402 let mut err = Error::duplicate_field("prf").to_string().into_bytes(); 1403 assert_eq!( 1404 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1405 format!( 1406 "{{ 1407 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1408 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1409 \"response\": {{ 1410 \"clientDataJSON\": \"{b64_cdata_json}\", 1411 \"authenticatorData\": \"{b64_adata}\", 1412 \"signature\": \"{b64_sig}\", 1413 \"userHandle\": \"{b64_user}\" 1414 }}, 1415 \"clientExtensionResults\": {{ 1416 \"prf\": null, 1417 \"prf\": null 1418 }}, 1419 \"type\": \"public-key\" 1420 }}" 1421 ) 1422 .as_str() 1423 ) 1424 .unwrap_err() 1425 .to_string() 1426 .into_bytes() 1427 .get(..err.len()), 1428 Some(err.as_slice()) 1429 ); 1430 // `null` `results`. 1431 drop( 1432 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1433 serde_json::json!({ 1434 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1435 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1436 "response": { 1437 "clientDataJSON": b64_cdata_json, 1438 "authenticatorData": b64_adata, 1439 "signature": b64_sig, 1440 "userHandle": b64_user, 1441 }, 1442 "clientExtensionResults": { 1443 "prf": { 1444 "results": null, 1445 } 1446 }, 1447 "type": "public-key" 1448 }) 1449 .to_string() 1450 .as_str(), 1451 ) 1452 .unwrap(), 1453 ); 1454 // Duplicate field in `prf`. 1455 err = Error::duplicate_field("results").to_string().into_bytes(); 1456 assert_eq!( 1457 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1458 format!( 1459 "{{ 1460 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1461 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1462 \"response\": {{ 1463 \"clientDataJSON\": \"{b64_cdata_json}\", 1464 \"authenticatorData\": \"{b64_adata}\", 1465 \"signature\": \"{b64_sig}\", 1466 \"userHandle\": \"{b64_user}\" 1467 }}, 1468 \"clientExtensionResults\": {{ 1469 \"prf\": {{ 1470 \"results\": null, 1471 \"results\": null 1472 }} 1473 }}, 1474 \"type\": \"public-key\" 1475 }}" 1476 ) 1477 .as_str() 1478 ) 1479 .unwrap_err() 1480 .to_string() 1481 .into_bytes() 1482 .get(..err.len()), 1483 Some(err.as_slice()) 1484 ); 1485 // Missing `first`. 1486 drop( 1487 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1488 serde_json::json!({ 1489 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1490 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1491 "response": { 1492 "clientDataJSON": b64_cdata_json, 1493 "authenticatorData": b64_adata, 1494 "signature": b64_sig, 1495 "userHandle": b64_user, 1496 }, 1497 "clientExtensionResults": { 1498 "prf": { 1499 "results": {}, 1500 } 1501 }, 1502 "type": "public-key" 1503 }) 1504 .to_string() 1505 .as_str(), 1506 ) 1507 .unwrap(), 1508 ); 1509 // `null` `first`. 1510 drop( 1511 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1512 serde_json::json!({ 1513 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1514 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1515 "response": { 1516 "clientDataJSON": b64_cdata_json, 1517 "authenticatorData": b64_adata, 1518 "signature": b64_sig, 1519 "userHandle": b64_user, 1520 }, 1521 "clientExtensionResults": { 1522 "prf": { 1523 "results": { 1524 "first": null 1525 }, 1526 } 1527 }, 1528 "type": "public-key" 1529 }) 1530 .to_string() 1531 .as_str(), 1532 ) 1533 .unwrap(), 1534 ); 1535 // `null` `second`. 1536 drop( 1537 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1538 serde_json::json!({ 1539 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1540 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1541 "response": { 1542 "clientDataJSON": b64_cdata_json, 1543 "authenticatorData": b64_adata, 1544 "signature": b64_sig, 1545 "userHandle": b64_user, 1546 }, 1547 "clientExtensionResults": { 1548 "prf": { 1549 "results": { 1550 "first": null, 1551 "second": null 1552 }, 1553 } 1554 }, 1555 "type": "public-key" 1556 }) 1557 .to_string() 1558 .as_str(), 1559 ) 1560 .unwrap(), 1561 ); 1562 // Non-`null` `first`. 1563 err = Error::invalid_type(Unexpected::Option, &"null") 1564 .to_string() 1565 .into_bytes(); 1566 assert_eq!( 1567 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1568 serde_json::json!({ 1569 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1570 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1571 "response": { 1572 "clientDataJSON": b64_cdata_json, 1573 "authenticatorData": b64_adata, 1574 "signature": b64_sig, 1575 "userHandle": b64_user, 1576 }, 1577 "clientExtensionResults": { 1578 "prf": { 1579 "results": { 1580 "first": "" 1581 }, 1582 } 1583 }, 1584 "type": "public-key" 1585 }) 1586 .to_string() 1587 .as_str() 1588 ) 1589 .unwrap_err() 1590 .to_string() 1591 .into_bytes() 1592 .get(..err.len()), 1593 Some(err.as_slice()) 1594 ); 1595 // Non-`null` `second`. 1596 err = Error::invalid_type(Unexpected::Option, &"null") 1597 .to_string() 1598 .into_bytes(); 1599 assert_eq!( 1600 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1601 serde_json::json!({ 1602 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1603 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1604 "response": { 1605 "clientDataJSON": b64_cdata_json, 1606 "authenticatorData": b64_adata, 1607 "signature": b64_sig, 1608 "userHandle": b64_user, 1609 }, 1610 "clientExtensionResults": { 1611 "prf": { 1612 "results": { 1613 "first": null, 1614 "second": "" 1615 }, 1616 } 1617 }, 1618 "type": "public-key" 1619 }) 1620 .to_string() 1621 .as_str() 1622 ) 1623 .unwrap_err() 1624 .to_string() 1625 .into_bytes() 1626 .get(..err.len()), 1627 Some(err.as_slice()) 1628 ); 1629 // `enabled` is still not allowed. 1630 err = Error::unknown_field("enabled", ["results"].as_slice()) 1631 .to_string() 1632 .into_bytes(); 1633 assert_eq!( 1634 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1635 serde_json::json!({ 1636 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1637 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1638 "response": { 1639 "clientDataJSON": b64_cdata_json, 1640 "authenticatorData": b64_adata, 1641 "signature": b64_sig, 1642 "userHandle": b64_user, 1643 }, 1644 "clientExtensionResults": { 1645 "prf": { 1646 "enabled": true, 1647 "results": null 1648 } 1649 }, 1650 "type": "public-key" 1651 }) 1652 .to_string() 1653 .as_str() 1654 ) 1655 .unwrap_err() 1656 .to_string() 1657 .into_bytes() 1658 .get(..err.len()), 1659 Some(err.as_slice()) 1660 ); 1661 // Unknown `prf` field. 1662 drop( 1663 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1664 serde_json::json!({ 1665 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1666 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1667 "response": { 1668 "clientDataJSON": b64_cdata_json, 1669 "authenticatorData": b64_adata, 1670 "signature": b64_sig, 1671 "userHandle": b64_user, 1672 }, 1673 "clientExtensionResults": { 1674 "prf": { 1675 "foo": true, 1676 "results": null 1677 } 1678 }, 1679 "type": "public-key" 1680 }) 1681 .to_string() 1682 .as_str(), 1683 ) 1684 .unwrap(), 1685 ); 1686 // Unknown `results` field. 1687 drop( 1688 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1689 serde_json::json!({ 1690 "id": "AAAAAAAAAAAAAAAAAAAAAA", 1691 "rawId": "AAAAAAAAAAAAAAAAAAAAAA", 1692 "response": { 1693 "clientDataJSON": b64_cdata_json, 1694 "authenticatorData": b64_adata, 1695 "signature": b64_sig, 1696 "userHandle": b64_user, 1697 }, 1698 "clientExtensionResults": { 1699 "prf": { 1700 "results": { 1701 "first": null, 1702 "Second": null 1703 } 1704 } 1705 }, 1706 "type": "public-key" 1707 }) 1708 .to_string() 1709 .as_str(), 1710 ) 1711 .unwrap(), 1712 ); 1713 // Duplicate field in `results`. 1714 err = Error::duplicate_field("first").to_string().into_bytes(); 1715 assert_eq!( 1716 serde_json::from_str::<DiscoverableAuthenticationRelaxed<USER_HANDLE_MIN_LEN>>( 1717 format!( 1718 "{{ 1719 \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1720 \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\", 1721 \"response\": {{ 1722 \"clientDataJSON\": \"{b64_cdata_json}\", 1723 \"authenticatorData\": \"{b64_adata}\", 1724 \"signature\": \"{b64_sig}\", 1725 \"userHandle\": \"{b64_user}\" 1726 }}, 1727 \"clientExtensionResults\": {{ 1728 \"prf\": {{ 1729 \"results\": {{ 1730 \"first\": null, 1731 \"first\": null 1732 }} 1733 }} 1734 }}, 1735 \"type\": \"public-key\" 1736 }}" 1737 ) 1738 .as_str() 1739 ) 1740 .unwrap_err() 1741 .to_string() 1742 .into_bytes() 1743 .get(..err.len()), 1744 Some(err.as_slice()) 1745 ); 1746 }