diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs index eb17a8b1..3a503a23 100644 --- a/src/api/core/two_factor/mod.rs +++ b/src/api/core/two_factor/mod.rs @@ -1,5 +1,6 @@ use chrono::{TimeDelta, Utc}; use data_encoding::BASE32; +use num_traits::FromPrimitive; use rocket::serde::json::Json; use rocket::Route; use serde::Deserialize; @@ -36,7 +37,7 @@ fn has_global_duo_credentials() -> bool { CONFIG._enable_duo() && CONFIG.duo_host().is_some() && CONFIG.duo_ikey().is_some() && CONFIG.duo_skey().is_some() } -pub fn is_twofactor_provider_usable(provider_type: i32, provider_data: Option<&str>) -> bool { +pub fn is_twofactor_provider_usable(provider_type: TwoFactorType, provider_data: Option<&str>) -> bool { #[derive(Deserialize)] struct DuoProviderData { host: String, @@ -45,21 +46,27 @@ pub fn is_twofactor_provider_usable(provider_type: i32, provider_data: Option<&s } match provider_type { - x if x == TwoFactorType::Authenticator as i32 => true, - x if x == TwoFactorType::Email as i32 => CONFIG._enable_email_2fa(), - x if x == TwoFactorType::Duo as i32 || x == TwoFactorType::OrganizationDuo as i32 => { + TwoFactorType::Authenticator => true, + TwoFactorType::Email => CONFIG._enable_email_2fa(), + TwoFactorType::Duo | TwoFactorType::OrganizationDuo => { provider_data .and_then(|raw| serde_json::from_str::(raw).ok()) .is_some_and(|duo| !duo.host.is_empty() && !duo.ik.is_empty() && !duo.sk.is_empty()) || has_global_duo_credentials() } - x if x == TwoFactorType::YubiKey as i32 => { + TwoFactorType::YubiKey => { CONFIG._enable_yubico() && CONFIG.yubico_client_id().is_some() && CONFIG.yubico_secret_key().is_some() } - x if x == TwoFactorType::Webauthn as i32 => CONFIG.is_webauthn_2fa_supported(), - x if x == TwoFactorType::Remember as i32 => !CONFIG.disable_2fa_remember(), - x if x == TwoFactorType::RecoveryCode as i32 => true, - _ => false, + TwoFactorType::Webauthn => CONFIG.is_webauthn_2fa_supported(), + TwoFactorType::Remember => !CONFIG.disable_2fa_remember(), + TwoFactorType::RecoveryCode => true, + TwoFactorType::U2f + | TwoFactorType::U2fRegisterChallenge + | TwoFactorType::U2fLoginChallenge + | TwoFactorType::EmailVerificationChallenge + | TwoFactorType::WebauthnRegisterChallenge + | TwoFactorType::WebauthnLoginChallenge + | TwoFactorType::ProtectedActions => false, } } @@ -87,8 +94,10 @@ async fn get_twofactor(headers: Headers, conn: DbConn) -> Json { let twofactors = TwoFactor::find_by_user(&headers.user.uuid, &conn).await; let twofactors_json: Vec = twofactors .iter() - .filter(|tf| is_twofactor_provider_usable(tf.atype, Some(&tf.data))) - .map(TwoFactor::to_json_provider) + .filter_map(|tf| { + let provider_type = TwoFactorType::from_i32(tf.atype)?; + is_twofactor_provider_usable(provider_type, Some(&tf.data)).then(|| TwoFactor::to_json_provider(tf)) + }) .collect(); Json(json!({ diff --git a/src/api/identity.rs b/src/api/identity.rs index 10045d3d..b9a753b9 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -15,7 +15,8 @@ use crate::{ accounts::{PreloginData, RegisterData, _prelogin, _register, kdf_upgrade}, log_user_event, two_factor::{ - authenticator, duo, duo_oidc, email, enforce_2fa_policy, is_twofactor_provider_usable, webauthn, yubikey, + authenticator, duo, duo_oidc, email, enforce_2fa_policy, is_twofactor_provider_usable, webauthn, + yubikey, }, }, master_password_policy, @@ -743,8 +744,10 @@ async fn twofactor_auth( let twofactor_ids: Vec<_> = twofactors .iter() - .filter(|tf| tf.enabled && is_twofactor_provider_usable(tf.atype, Some(&tf.data))) - .map(|tf| tf.atype) + .filter_map(|tf| { + let provider_type = TwoFactorType::from_i32(tf.atype)?; + (tf.enabled && is_twofactor_provider_usable(provider_type, Some(&tf.data))).then_some(tf.atype) + }) .collect(); if twofactor_ids.is_empty() { err!("No enabled and usable two factor providers are available for this account")