|
|
@ -1,5 +1,6 @@ |
|
|
use chrono::{TimeDelta, Utc}; |
|
|
use chrono::{TimeDelta, Utc}; |
|
|
use data_encoding::BASE32; |
|
|
use data_encoding::BASE32; |
|
|
|
|
|
use num_traits::FromPrimitive; |
|
|
use rocket::serde::json::Json; |
|
|
use rocket::serde::json::Json; |
|
|
use rocket::Route; |
|
|
use rocket::Route; |
|
|
use serde::Deserialize; |
|
|
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() |
|
|
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)] |
|
|
#[derive(Deserialize)] |
|
|
struct DuoProviderData { |
|
|
struct DuoProviderData { |
|
|
host: String, |
|
|
host: String, |
|
|
@ -45,21 +46,27 @@ pub fn is_twofactor_provider_usable(provider_type: i32, provider_data: Option<&s |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
match provider_type { |
|
|
match provider_type { |
|
|
x if x == TwoFactorType::Authenticator as i32 => true, |
|
|
TwoFactorType::Authenticator => true, |
|
|
x if x == TwoFactorType::Email as i32 => CONFIG._enable_email_2fa(), |
|
|
TwoFactorType::Email => CONFIG._enable_email_2fa(), |
|
|
x if x == TwoFactorType::Duo as i32 || x == TwoFactorType::OrganizationDuo as i32 => { |
|
|
TwoFactorType::Duo | TwoFactorType::OrganizationDuo => { |
|
|
provider_data |
|
|
provider_data |
|
|
.and_then(|raw| serde_json::from_str::<DuoProviderData>(raw).ok()) |
|
|
.and_then(|raw| serde_json::from_str::<DuoProviderData>(raw).ok()) |
|
|
.is_some_and(|duo| !duo.host.is_empty() && !duo.ik.is_empty() && !duo.sk.is_empty()) |
|
|
.is_some_and(|duo| !duo.host.is_empty() && !duo.ik.is_empty() && !duo.sk.is_empty()) |
|
|
|| has_global_duo_credentials() |
|
|
|| 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() |
|
|
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(), |
|
|
TwoFactorType::Webauthn => CONFIG.is_webauthn_2fa_supported(), |
|
|
x if x == TwoFactorType::Remember as i32 => !CONFIG.disable_2fa_remember(), |
|
|
TwoFactorType::Remember => !CONFIG.disable_2fa_remember(), |
|
|
x if x == TwoFactorType::RecoveryCode as i32 => true, |
|
|
TwoFactorType::RecoveryCode => true, |
|
|
_ => false, |
|
|
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<Value> { |
|
|
let twofactors = TwoFactor::find_by_user(&headers.user.uuid, &conn).await; |
|
|
let twofactors = TwoFactor::find_by_user(&headers.user.uuid, &conn).await; |
|
|
let twofactors_json: Vec<Value> = twofactors |
|
|
let twofactors_json: Vec<Value> = twofactors |
|
|
.iter() |
|
|
.iter() |
|
|
.filter(|tf| is_twofactor_provider_usable(tf.atype, Some(&tf.data))) |
|
|
.filter_map(|tf| { |
|
|
.map(TwoFactor::to_json_provider) |
|
|
let provider_type = TwoFactorType::from_i32(tf.atype)?; |
|
|
|
|
|
is_twofactor_provider_usable(provider_type, Some(&tf.data)).then(|| TwoFactor::to_json_provider(tf)) |
|
|
|
|
|
}) |
|
|
.collect(); |
|
|
.collect(); |
|
|
|
|
|
|
|
|
Json(json!({ |
|
|
Json(json!({ |
|
|
|