webauthn.rs (35315B)
1 use crate::{ 2 api::{EmptyResult, JsonResult, PasswordOrOtpData}, 3 auth::{self, Headers}, 4 config, 5 db::{ 6 DbConn, 7 models::{WebAuthn, WebAuthnInfo}, 8 }, 9 error::Error, 10 }; 11 use data_encoding::{BASE64, BASE64URL_NOPAD}; 12 use rocket::Route; 13 use rocket::serde::json::Json; 14 use serde::de::{Deserialize, Deserializer, Error as SerdeErr, MapAccess, Unexpected, Visitor}; 15 use std::fmt::{self, Formatter}; 16 use uuid::Uuid; 17 use webauthn_rp::{ 18 AggErr, 19 request::{ 20 InsertResult, 21 auth::NonDiscoverableCredentialRequestOptions, 22 register::{ 23 Nickname, PublicKeyCredentialCreationOptions, PublicKeyCredentialUserEntity, 24 UserHandle16, Username, 25 }, 26 }, 27 response::{ 28 AuthTransports, AuthenticatorAttachment, CollectedClientData, CredentialId, 29 auth::NonDiscoverableAuthentication16, 30 register::{AuthenticatorAttestation, Registration}, 31 }, 32 }; 33 34 pub fn routes() -> Vec<Route> { 35 routes![ 36 activate_webauthn, 37 activate_webauthn_put, 38 delete_webauthn, 39 generate_webauthn_challenge, 40 get_webauthn, 41 ] 42 } 43 #[post("/two-factor/get-webauthn", data = "<data>")] 44 async fn get_webauthn(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn) -> JsonResult { 45 let data: PasswordOrOtpData = data.into_inner(); 46 let user = headers.user; 47 data.validate(&user)?; 48 let keys = WebAuthnInfo::get_all_by_user(&user.uuid, &conn).await?; 49 Ok(Json(json!({ 50 "enabled": !keys.is_empty(), 51 "keys": keys, 52 "object": "twoFactorWebAuthn" 53 }))) 54 } 55 #[post("/two-factor/get-webauthn-challenge", data = "<data>")] 56 async fn generate_webauthn_challenge( 57 data: Json<PasswordOrOtpData>, 58 headers: Headers, 59 conn: DbConn, 60 ) -> JsonResult { 61 let data: PasswordOrOtpData = data.into_inner(); 62 let user = headers.user; 63 data.validate(&user)?; 64 let name = Username::try_from(user.email.as_str()).map_err(AggErr::Username)?; 65 let uuid = Uuid::parse_str(user.uuid.as_str()) 66 .map_err(|e| Error::from(e.to_string()))? 67 .into_bytes(); 68 let id = UserHandle16::from(uuid); 69 let display_name = Some(Nickname::try_from(user.name.as_str()).map_err(AggErr::Nickname)?); 70 let (server, client) = PublicKeyCredentialCreationOptions::second_factor( 71 &config::get_config().rp_id, 72 PublicKeyCredentialUserEntity { 73 name, 74 id: &id, 75 display_name, 76 }, 77 WebAuthn::get_registered_creds(user.uuid.as_str(), &conn).await?, 78 ) 79 .start_ceremony() 80 .map_err(AggErr::CreationOptions)?; 81 match auth::get_reg_ceremonies().insert_or_replace_all_expired(server) { 82 InsertResult::Success => { 83 let mut challenge_value = serde_json::to_value(client)?; 84 challenge_value["status"] = "ok".into(); 85 challenge_value["errorMessage"] = "".into(); 86 Ok(Json(challenge_value)) 87 } 88 InsertResult::CapacityFull => Err(Error::from(String::from( 89 "too many active ceremonies. try again later", 90 ))), 91 InsertResult::Duplicate => Err(Error::from(String::from("duplicate webauthn challenge"))), 92 } 93 } 94 struct Type; 95 impl<'e> Deserialize<'e> for Type { 96 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 97 where 98 D: Deserializer<'e>, 99 { 100 struct TypeVisitor; 101 impl Visitor<'_> for TypeVisitor { 102 type Value = Type; 103 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 104 formatter.write_str("public-key") 105 } 106 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 107 where 108 E: SerdeErr, 109 { 110 if v == "public-key" { 111 Ok(Type) 112 } else { 113 Err(E::invalid_value(Unexpected::Str(v), &"public-key")) 114 } 115 } 116 } 117 deserializer.deserialize_str(TypeVisitor) 118 } 119 } 120 struct RegistrationWrapper(Registration); 121 impl<'de> Deserialize<'de> for RegistrationWrapper { 122 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 123 where 124 D: Deserializer<'de>, 125 { 126 struct RegistrationVisitor; 127 impl<'d> Visitor<'d> for RegistrationVisitor { 128 type Value = RegistrationWrapper; 129 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 130 formatter.write_str("RegistrationWrapper") 131 } 132 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 133 where 134 A: MapAccess<'d>, 135 { 136 enum Field { 137 Id, 138 RawId, 139 Response, 140 Extensions, 141 Type, 142 } 143 impl<'e> Deserialize<'e> for Field { 144 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 145 where 146 D: Deserializer<'e>, 147 { 148 struct FieldVisitor; 149 impl Visitor<'_> for FieldVisitor { 150 type Value = Field; 151 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 152 write!( 153 formatter, 154 "'{ID}', '{RAW_ID}', '{RESPONSE}', '{EXTENSIONS}', or '{TYPE}'" 155 ) 156 } 157 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 158 where 159 E: SerdeErr, 160 { 161 match v { 162 ID => Ok(Field::Id), 163 RAW_ID => Ok(Field::RawId), 164 RESPONSE => Ok(Field::Response), 165 EXTENSIONS => Ok(Field::Extensions), 166 TYPE => Ok(Field::Type), 167 _ => Err(E::unknown_field(v, FIELDS)), 168 } 169 } 170 } 171 deserializer.deserialize_identifier(FieldVisitor) 172 } 173 } 174 struct RawId(CredentialId<Vec<u8>>); 175 impl<'e> Deserialize<'e> for RawId { 176 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 177 where 178 D: Deserializer<'e>, 179 { 180 struct RawIdVisitor; 181 impl Visitor<'_> for RawIdVisitor { 182 type Value = RawId; 183 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 184 formatter.write_str("RawId") 185 } 186 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 187 where 188 E: SerdeErr, 189 { 190 BASE64.decode(v.as_bytes()).map_err(E::custom).and_then( 191 |base64url| { 192 BASE64URL_NOPAD 193 .decode(base64url.as_slice()) 194 .map_err(E::custom) 195 .and_then(|cred_id| { 196 CredentialId::try_from(cred_id) 197 .map_err(E::custom) 198 .map(RawId) 199 }) 200 }, 201 ) 202 } 203 } 204 deserializer.deserialize_str(RawIdVisitor) 205 } 206 } 207 struct AuthAttestWrapper(AuthenticatorAttestation); 208 impl<'e> Deserialize<'e> for AuthAttestWrapper { 209 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 210 where 211 D: Deserializer<'e>, 212 { 213 struct AuthAttestVisitor; 214 impl<'f> Visitor<'f> for AuthAttestVisitor { 215 type Value = AuthAttestWrapper; 216 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 217 formatter.write_str("AuthAttestWrapper") 218 } 219 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 220 where 221 A: MapAccess<'f>, 222 { 223 enum AuthField { 224 AttestationObject, 225 ClientDataJson, 226 } 227 impl<'g> Deserialize<'g> for AuthField { 228 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 229 where 230 D: Deserializer<'g>, 231 { 232 struct AuthFieldVisitor; 233 impl Visitor<'_> for AuthFieldVisitor { 234 type Value = AuthField; 235 fn expecting( 236 &self, 237 formatter: &mut Formatter<'_>, 238 ) -> fmt::Result 239 { 240 write!( 241 formatter, 242 "'{ATTESTATION_OBJECT}' or '{CLIENT_DATA_JSON}'" 243 ) 244 } 245 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 246 where 247 E: SerdeErr, 248 { 249 match v { 250 ATTESTATION_OBJECT => { 251 Ok(AuthField::AttestationObject) 252 } 253 CLIENT_DATA_JSON => { 254 Ok(AuthField::ClientDataJson) 255 } 256 _ => Err(E::unknown_field(v, AUTH_FIELDS)), 257 } 258 } 259 } 260 deserializer.deserialize_identifier(AuthFieldVisitor) 261 } 262 } 263 struct Base64(Vec<u8>); 264 impl<'g> Deserialize<'g> for Base64 { 265 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 266 where 267 D: Deserializer<'g>, 268 { 269 struct Base64Visitor; 270 impl Visitor<'_> for Base64Visitor { 271 type Value = Base64; 272 fn expecting( 273 &self, 274 formatter: &mut Formatter<'_>, 275 ) -> fmt::Result 276 { 277 formatter.write_str("base64-encoded value") 278 } 279 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 280 where 281 E: SerdeErr, 282 { 283 BASE64 284 .decode(v.as_bytes()) 285 .map_err(E::custom) 286 .map(Base64) 287 } 288 } 289 deserializer.deserialize_str(Base64Visitor) 290 } 291 } 292 let mut att_obj = None; 293 let mut client_data = None; 294 while let Some(key) = map.next_key()? { 295 match key { 296 AuthField::AttestationObject => { 297 if att_obj.is_some() { 298 return Err(SerdeErr::duplicate_field( 299 ATTESTATION_OBJECT, 300 )); 301 } 302 att_obj = map 303 .next_value::<Base64>() 304 .map(|base64| Some(base64.0))?; 305 } 306 AuthField::ClientDataJson => { 307 if client_data.is_some() { 308 return Err(SerdeErr::duplicate_field( 309 CLIENT_DATA_JSON, 310 )); 311 } 312 client_data = map 313 .next_value::<Base64>() 314 .map(|base64| Some(base64.0))?; 315 } 316 } 317 } 318 att_obj 319 .ok_or_else(|| SerdeErr::missing_field(ATTESTATION_OBJECT)) 320 .and_then(|attestation_object| { 321 client_data 322 .ok_or_else(|| { 323 SerdeErr::missing_field(CLIENT_DATA_JSON) 324 }) 325 .map(|client_data_json| { 326 AuthAttestWrapper(AuthenticatorAttestation::new( 327 client_data_json, 328 attestation_object, 329 AuthTransports::NONE, 330 )) 331 }) 332 }) 333 } 334 } 335 const ATTESTATION_OBJECT: &str = "attestationObject"; 336 const CLIENT_DATA_JSON: &str = "clientDataJSON"; 337 const AUTH_FIELDS: &[&str; 2] = &[ATTESTATION_OBJECT, CLIENT_DATA_JSON]; 338 deserializer.deserialize_struct( 339 "AuthAttestWrapper", 340 AUTH_FIELDS, 341 AuthAttestVisitor, 342 ) 343 } 344 } 345 let mut id = None; 346 let mut raw_id = None; 347 let mut response = None; 348 let mut extensions = None; 349 let mut typ = false; 350 while let Some(key) = map.next_key()? { 351 match key { 352 Field::Id => { 353 if id.is_some() { 354 return Err(SerdeErr::duplicate_field(ID)); 355 } 356 id = map.next_value::<CredentialId<Vec<u8>>>().map(Some)?; 357 } 358 Field::RawId => { 359 if raw_id.is_some() { 360 return Err(SerdeErr::duplicate_field(RAW_ID)); 361 } 362 raw_id = map.next_value::<RawId>().map(Some)?; 363 } 364 Field::Response => { 365 if response.is_some() { 366 return Err(SerdeErr::duplicate_field(RESPONSE)); 367 } 368 response = map 369 .next_value::<AuthAttestWrapper>() 370 .map(|attest| Some(attest.0))?; 371 } 372 Field::Extensions => { 373 if extensions.is_some() { 374 return Err(SerdeErr::duplicate_field(EXTENSIONS)); 375 } 376 extensions = map.next_value().map(Some)?; 377 } 378 Field::Type => { 379 if typ { 380 return Err(SerdeErr::duplicate_field(TYPE)); 381 } 382 typ = map.next_value::<Type>().map(|_| true)?; 383 } 384 } 385 } 386 id.ok_or_else(|| SerdeErr::missing_field(ID)).and_then(|i| { 387 raw_id 388 .ok_or_else(|| SerdeErr::missing_field(RAW_ID)) 389 .and_then(|r| { 390 if i == r.0 { 391 response 392 .ok_or_else(|| SerdeErr::missing_field(RESPONSE)) 393 .and_then(|resp| { 394 extensions 395 .ok_or_else(|| SerdeErr::missing_field(EXTENSIONS)) 396 .and_then(|ext| { 397 if typ { 398 Ok(RegistrationWrapper(Registration::new( 399 resp, 400 AuthenticatorAttachment::None, 401 ext, 402 ))) 403 } else { 404 Err(SerdeErr::missing_field(TYPE)) 405 } 406 }) 407 }) 408 } else { 409 Err(SerdeErr::invalid_value( 410 Unexpected::Bytes(r.0.as_ref()), 411 &format!("id: {:?} to match rawId", i.as_ref()).as_str(), 412 )) 413 } 414 }) 415 }) 416 } 417 } 418 const ID: &str = "id"; 419 const RAW_ID: &str = "rawId"; 420 const RESPONSE: &str = "response"; 421 const EXTENSIONS: &str = "extensions"; 422 const TYPE: &str = "type"; 423 const FIELDS: &[&str; 5] = &[ID, RAW_ID, RESPONSE, EXTENSIONS, TYPE]; 424 deserializer.deserialize_struct("RegistrationWrapper", FIELDS, RegistrationVisitor) 425 } 426 } 427 428 #[derive(Deserialize)] 429 #[serde(rename_all = "camelCase")] 430 struct EnableWebauthnData { 431 id: i64, 432 name: String, 433 device_response: RegistrationWrapper, 434 master_password_hash: String, 435 } 436 437 #[post("/two-factor/webauthn", data = "<data>")] 438 async fn activate_webauthn( 439 data: Json<EnableWebauthnData>, 440 headers: Headers, 441 conn: DbConn, 442 ) -> JsonResult { 443 let data = data.into_inner(); 444 let user = headers.user; 445 PasswordOrOtpData { 446 master_password_hash: Some(data.master_password_hash), 447 otp: None, 448 } 449 .validate(&user)?; 450 let cred = auth::get_reg_ceremonies() 451 .take( 452 &CollectedClientData::from_client_data_json_relaxed::<true>( 453 data.device_response.0.response().client_data_json(), 454 ) 455 .map_err(AggErr::SerdeJson)? 456 .challenge, 457 ) 458 .ok_or_else(|| Error::from(String::from("missing registration challenge")))? 459 .verify( 460 &config::get_config().rp_id, 461 &data.device_response.0, 462 auth::get_reg_options(), 463 ) 464 .map_err(AggErr::RegCeremony)?; 465 WebAuthn::new(&cred, user.uuid.clone(), data.id, data.name)? 466 .insert(&conn) 467 .await?; 468 let keys = WebAuthnInfo::get_all_by_user(user.uuid.as_str(), &conn).await?; 469 Ok(Json(json!({ 470 "enabled": !keys.is_empty(), 471 "keys": keys, 472 "object": "twoFactorWebAuthn" 473 }))) 474 } 475 476 #[put("/two-factor/webauthn", data = "<data>")] 477 async fn activate_webauthn_put( 478 data: Json<EnableWebauthnData>, 479 headers: Headers, 480 conn: DbConn, 481 ) -> JsonResult { 482 activate_webauthn(data, headers, conn).await 483 } 484 485 #[derive(Deserialize)] 486 #[serde(rename_all = "camelCase")] 487 struct DeleteU2FData { 488 id: i64, 489 master_password_hash: String, 490 } 491 492 #[delete("/two-factor/webauthn", data = "<data>")] 493 async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, conn: DbConn) -> JsonResult { 494 if !headers 495 .user 496 .check_valid_password(&data.master_password_hash) 497 { 498 err!("Invalid password"); 499 } 500 WebAuthn::delete_by_user_uuid_and_id(&headers.user.uuid, data.id, &conn).await?; 501 let keys = WebAuthnInfo::get_all_by_user(&headers.user.uuid, &conn).await?; 502 Ok(Json(json!({ 503 "enabled": !keys.is_empty(), 504 "keys": keys, 505 "object": "twoFactorWebAuthn" 506 }))) 507 } 508 509 pub async fn generate_webauthn_login(user_uuid: &str, conn: &DbConn) -> JsonResult { 510 let creds = WebAuthn::get_allowed_creds(user_uuid, conn).await?; 511 let (server, client) = 512 NonDiscoverableCredentialRequestOptions::second_factor(&config::get_config().rp_id, creds) 513 .map_err(AggErr::SecondFactor)? 514 .start_ceremony() 515 .map_err(AggErr::RequestOptions)?; 516 match auth::get_auth_ceremonies().insert_or_replace_all_expired(server) { 517 InsertResult::Success => Ok(Json(serde_json::to_value(client)?)), 518 InsertResult::CapacityFull => Err(Error::from(String::from( 519 "too many active ceremonies. try again later", 520 ))), 521 InsertResult::Duplicate => Err(Error::from(String::from("duplicate webauthn challenge"))), 522 } 523 } 524 struct AuthenticationWrapper(NonDiscoverableAuthentication16); 525 impl<'de> Deserialize<'de> for AuthenticationWrapper { 526 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 527 where 528 D: Deserializer<'de>, 529 { 530 struct AuthenticationVisitor; 531 impl<'d> Visitor<'d> for AuthenticationVisitor { 532 type Value = AuthenticationWrapper; 533 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 534 formatter.write_str("AuthenticationWrapper") 535 } 536 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 537 where 538 A: MapAccess<'d>, 539 { 540 enum Field { 541 Id, 542 RawId, 543 Response, 544 Extensions, 545 Type, 546 } 547 impl<'e> Deserialize<'e> for Field { 548 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 549 where 550 D: Deserializer<'e>, 551 { 552 struct FieldVisitor; 553 impl Visitor<'_> for FieldVisitor { 554 type Value = Field; 555 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 556 write!( 557 formatter, 558 "'{ID}', '{RAW_ID}', '{RESPONSE}', '{EXTENSIONS}', or '{TYPE}'" 559 ) 560 } 561 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 562 where 563 E: SerdeErr, 564 { 565 match v { 566 ID => Ok(Field::Id), 567 RAW_ID => Ok(Field::RawId), 568 RESPONSE => Ok(Field::Response), 569 EXTENSIONS => Ok(Field::Extensions), 570 TYPE => Ok(Field::Type), 571 _ => Err(E::unknown_field(v, FIELDS)), 572 } 573 } 574 } 575 deserializer.deserialize_identifier(FieldVisitor) 576 } 577 } 578 struct Extensions; 579 impl<'e> Deserialize<'e> for Extensions { 580 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 581 where 582 D: Deserializer<'e>, 583 { 584 struct ExtensionsVisitor; 585 impl<'f> Visitor<'f> for ExtensionsVisitor { 586 type Value = Extensions; 587 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 588 formatter.write_str("Extensions") 589 } 590 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 591 where 592 A: MapAccess<'f>, 593 { 594 struct Field; 595 impl<'g> Deserialize<'g> for Field { 596 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 597 where 598 D: Deserializer<'g>, 599 { 600 struct FieldVisitor; 601 impl Visitor<'_> for FieldVisitor { 602 type Value = Field; 603 fn expecting( 604 &self, 605 formatter: &mut Formatter<'_>, 606 ) -> fmt::Result 607 { 608 write!(formatter, "'{APPID}'") 609 } 610 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 611 where 612 E: SerdeErr, 613 { 614 if v == APPID { 615 Ok(Field) 616 } else { 617 Err(E::unknown_field(v, FIELDS)) 618 } 619 } 620 } 621 deserializer.deserialize_identifier(FieldVisitor) 622 } 623 } 624 let mut appid = false; 625 while map.next_key::<Field>()?.is_some() { 626 if appid { 627 return Err(SerdeErr::duplicate_field(APPID)); 628 } 629 appid = map.next_value::<bool>().and_then(|v| { 630 if v { 631 Err(SerdeErr::invalid_value( 632 Unexpected::Bool(true), 633 &"appid to be false", 634 )) 635 } else { 636 Ok(true) 637 } 638 })?; 639 } 640 Ok(Extensions) 641 } 642 } 643 const APPID: &str = "appid"; 644 const FIELDS: &[&str; 1] = &[APPID]; 645 deserializer.deserialize_struct( 646 "EmptyExtensions", 647 FIELDS, 648 ExtensionsVisitor, 649 ) 650 } 651 } 652 let mut id = None; 653 let mut raw_id = None; 654 let mut response = None; 655 let mut extensions = false; 656 let mut typ = false; 657 while let Some(key) = map.next_key()? { 658 match key { 659 Field::Id => { 660 if id.is_some() { 661 return Err(SerdeErr::duplicate_field(ID)); 662 } 663 id = map.next_value::<CredentialId<Vec<u8>>>().map(Some)?; 664 } 665 Field::RawId => { 666 if raw_id.is_some() { 667 return Err(SerdeErr::duplicate_field(RAW_ID)); 668 } 669 raw_id = map.next_value::<CredentialId<Vec<u8>>>().map(Some)?; 670 } 671 Field::Response => { 672 if response.is_some() { 673 return Err(SerdeErr::duplicate_field(RESPONSE)); 674 } 675 response = map.next_value().map(Some)?; 676 } 677 Field::Extensions => { 678 if extensions { 679 return Err(SerdeErr::duplicate_field(EXTENSIONS)); 680 } 681 extensions = map.next_value::<Extensions>().map(|_| true)?; 682 } 683 Field::Type => { 684 if typ { 685 return Err(SerdeErr::duplicate_field(TYPE)); 686 } 687 typ = map.next_value::<Type>().map(|_| true)?; 688 } 689 } 690 } 691 id.ok_or_else(|| SerdeErr::missing_field(ID)).and_then(|i| { 692 raw_id 693 .ok_or_else(|| SerdeErr::missing_field(RAW_ID)) 694 .and_then(|r| { 695 if i == r { 696 response 697 .ok_or_else(|| SerdeErr::missing_field(RESPONSE)) 698 .and_then(|resp| { 699 if extensions { 700 if typ { 701 Ok(AuthenticationWrapper( 702 NonDiscoverableAuthentication16::new( 703 r, 704 resp, 705 AuthenticatorAttachment::None, 706 ), 707 )) 708 } else { 709 Err(SerdeErr::missing_field(TYPE)) 710 } 711 } else { 712 Err(SerdeErr::missing_field(EXTENSIONS)) 713 } 714 }) 715 } else { 716 Err(SerdeErr::invalid_value( 717 Unexpected::Bytes(r.as_ref()), 718 &format!("id: {:?} to match rawId", i.as_ref()).as_str(), 719 )) 720 } 721 }) 722 }) 723 } 724 } 725 const ID: &str = "id"; 726 const RAW_ID: &str = "rawId"; 727 const RESPONSE: &str = "response"; 728 const EXTENSIONS: &str = "extensions"; 729 const TYPE: &str = "type"; 730 const FIELDS: &[&str; 5] = &[ID, RAW_ID, RESPONSE, EXTENSIONS, TYPE]; 731 deserializer.deserialize_struct("RegistrationWrapper", FIELDS, AuthenticationVisitor) 732 } 733 } 734 pub async fn validate_webauthn_login( 735 user_uuid: &str, 736 response: &str, 737 conn: &DbConn, 738 ) -> EmptyResult { 739 let auth = serde_json::from_str::<AuthenticationWrapper>(response)?.0; 740 let uuid = Uuid::parse_str(user_uuid) 741 .map_err(|e| Error::from(e.to_string()))? 742 .into_bytes(); 743 let user_handle = UserHandle16::from(uuid); 744 let mut cred = WebAuthn::get_credential(auth.raw_id(), user_uuid, &user_handle, conn) 745 .await? 746 .ok_or_else(|| Error::from(String::from("credential does not exist")))?; 747 if auth::get_auth_ceremonies() 748 .take( 749 &CollectedClientData::from_client_data_json_relaxed::<false>( 750 auth.response().client_data_json(), 751 ) 752 .map_err(AggErr::SerdeJson)? 753 .challenge, 754 ) 755 .ok_or_else(|| Error::from(String::from("no authentication challenge")))? 756 .verify( 757 &config::get_config().rp_id, 758 &auth, 759 &mut cred, 760 auth::get_auth_options(), 761 ) 762 .map_err(AggErr::AuthCeremony)? 763 { 764 WebAuthn::update(auth.raw_id(), cred.dynamic_state(), conn).await 765 } else { 766 Ok(()) 767 } 768 }