use std::sync::Arc; use actix_web::web; use webauthn_rs::{RegistrationState, Webauthn, WebauthnConfig}; use webauthn_rs::proto::CreationChallengeResponse; use crate::constants::APP_NAME; use crate::data::app_config::AppConfig; use crate::data::crypto_wrapper::CryptoWrapper; use crate::data::user::{User, UserID}; use crate::utils::err::Res; #[derive(Debug)] struct WebAuthnAppConfig { origin: url::Url, relying_party_id: String, } impl WebauthnConfig for WebAuthnAppConfig { fn get_relying_party_name(&self) -> &str { APP_NAME } fn get_origin(&self) -> &url::Url { &self.origin } fn get_relying_party_id(&self) -> &str { &self.relying_party_id } } pub struct RegisterKeyRequest { pub opaque_state: String, pub creation_challenge: CreationChallengeResponse, } #[derive(Debug, serde::Serialize, serde::Deserialize)] struct RegisterKeyOpaqueData { registration_state: RegistrationState, user_id: UserID, } pub type WebAuthManagerReq = web::Data>; pub struct WebAuthManager { core: Webauthn, crypto_wrapper: CryptoWrapper, } impl WebAuthManager { pub fn init(conf: &AppConfig) -> Self { Self { core: Webauthn::new(WebAuthnAppConfig { origin: url::Url::parse(&conf.website_origin) .expect("Failed to parse configuration origin!"), relying_party_id: conf.domain_name().to_string(), }), crypto_wrapper: CryptoWrapper::new_random(), } } pub fn start_register(&self, user: &User) -> Res { let (creation_challenge, registration_state) = self.core.generate_challenge_register( &user.username, true, )?; Ok(RegisterKeyRequest { opaque_state: self.crypto_wrapper.encrypt(&RegisterKeyOpaqueData { registration_state, user_id: user.uid.clone(), })?, creation_challenge, }) } }