Browse Source

TwoFactor.find_by_user_and_type take enum parameter not i32

pull/7563/head
Timshel 1 week ago
parent
commit
4845b071bb
  1. 10
      src/api/core/two_factor/authenticator.rs
  2. 6
      src/api/core/two_factor/duo.rs
  3. 24
      src/api/core/two_factor/email.rs
  4. 5
      src/api/core/two_factor/protected_actions.rs
  5. 17
      src/api/core/two_factor/webauthn.rs
  6. 7
      src/api/core/two_factor/yubikey.rs
  7. 4
      src/api/identity.rs
  8. 4
      src/db/models/two_factor.rs

10
src/api/core/two_factor/authenticator.rs

@ -24,8 +24,7 @@ async fn generate_authenticator(data: Json<PasswordOrOtpData>, headers: Headers,
data.validate(&user, false, &conn).await?;
let type_ = TwoFactorType::Authenticator as i32;
let twofactor = TwoFactor::find_by_user_and_type(&user.uuid, type_, &conn).await;
let twofactor = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Authenticator, &conn).await;
let (enabled, key) = match twofactor {
Some(tf) => (true, tf.data),
@ -117,8 +116,7 @@ pub async fn validate_totp_code(
err!("Invalid TOTP secret")
};
let mut twofactor = match TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Authenticator as i32, conn).await
{
let mut twofactor = match TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Authenticator, conn).await {
Some(tf) => tf,
_ => TwoFactor::new(user_id.clone(), TwoFactorType::Authenticator, secret.to_owned()),
};
@ -185,9 +183,7 @@ async fn disable_authenticator(data: Json<DisableAuthenticatorData>, headers: He
two_factor::validate_authenticator(&data.user_verification_token, &user.uuid, &data.key, true)?;
if let Some(twofactor) =
TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Authenticator as i32, &conn).await
{
if let Some(twofactor) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Authenticator, &conn).await {
if twofactor.data == data.key {
twofactor.delete(&conn).await?;
log_user_event(EventType::UserDisabled2fa as i32, &user.uuid, headers.device.atype, &headers.ip.ip, &conn)

6
src/api/core/two_factor/duo.rs

@ -149,7 +149,7 @@ async fn activate_duo_put(data: Json<EnableDuoData>, headers: Headers, conn: DbC
async fn disable_duo(data: Json<VerificationTokenData>, headers: Headers, conn: DbConn) -> EmptyResult {
let user = headers.user;
if let Some(twofactor) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Duo as i32, &conn).await {
if let Some(twofactor) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Duo, &conn).await {
// Apply the same transformation than in `get_duo` to check we are disabling the correct one
let duo = match to_user_duo_data(&twofactor) {
DuoStatus::Global(_) => Some(DuoData::secret()),
@ -203,10 +203,8 @@ const DUO_PREFIX: &str = "TX";
const APP_PREFIX: &str = "APP";
async fn get_user_duo_data(user_id: &UserId, conn: &DbConn) -> DuoStatus {
let type_ = TwoFactorType::Duo as i32;
// If the user doesn't have an entry, disabled
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, type_, conn).await else {
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Duo, conn).await else {
return DuoStatus::Disabled(DuoData::global().is_some());
};

24
src/api/core/two_factor/email.rs

@ -110,8 +110,8 @@ async fn send_email_login(data: Json<SendEmailLoginData>, client_headers: Client
/// Generate the token, save the data for later verification and send email to user
pub async fn send_token(user_id: &UserId, conn: &DbConn) -> EmptyResult {
let type_ = TwoFactorType::Email as i32;
let mut twofactor = TwoFactor::find_by_user_and_type(user_id, type_, conn).await.map_res("Two factor not found")?;
let mut twofactor =
TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Email, conn).await.map_res("Two factor not found")?;
let generated_token = crypto::generate_email_token(CONFIG.email_token_size());
@ -134,7 +134,7 @@ async fn get_email(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn
data.validate(&user, false, &conn).await?;
let (enabled, mfa_email) =
if let Some(x) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Email as i32, &conn).await {
if let Some(x) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Email, &conn).await {
let twofactor_data = EmailTokenData::from_json(&x.data)?;
(true, Some(twofactor_data.email))
} else {
@ -170,9 +170,7 @@ async fn send_email(data: Json<SendEmailData>, headers: Headers, conn: DbConn) -
err!("Email 2FA is disabled")
}
let type_ = TwoFactorType::Email as i32;
if let Some(tf) = TwoFactor::find_by_user_and_type(&user.uuid, type_, &conn).await {
if let Some(tf) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Email, &conn).await {
tf.delete(&conn).await?;
}
@ -205,10 +203,9 @@ async fn email(data: Json<EmailData>, headers: Headers, conn: DbConn) -> JsonRes
two_factor::validate_email(&data.user_verification_token, &user.uuid, data.email, false)?;
let mut twofactor =
TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::EmailVerificationChallenge as i32, &conn)
.await
.map_res("Two factor not found")?;
let mut twofactor = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::EmailVerificationChallenge, &conn)
.await
.map_res("Two factor not found")?;
let mut email_data = EmailTokenData::from_json(&twofactor.data)?;
@ -236,7 +233,7 @@ async fn email(data: Json<EmailData>, headers: Headers, conn: DbConn) -> JsonRes
async fn disable_email(data: Json<VerificationTokenData>, headers: Headers, conn: DbConn) -> EmptyResult {
let user = headers.user;
if let Some(twofactor) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Email as i32, &conn).await {
if let Some(twofactor) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Email, &conn).await {
let twofactor_data = EmailTokenData::from_json(&twofactor.data)?;
two_factor::validate_email(&data.user_verification_token, &user.uuid, twofactor_data.email, true)?;
@ -261,9 +258,8 @@ pub async fn validate_email_code_str(
conn: &DbConn,
) -> EmptyResult {
let mut email_data = EmailTokenData::from_json(data)?;
let mut twofactor = TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Email as i32, conn)
.await
.map_res("Two factor not found")?;
let mut twofactor =
TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Email, conn).await.map_res("Two factor not found")?;
let Some(issued_token) = &email_data.last_token else {
err!(
format!("No token available! IP: {ip}"),

5
src/api/core/two_factor/protected_actions.rs

@ -72,8 +72,7 @@ async fn request_otp(headers: Headers, conn: DbConn) -> EmptyResult {
let user = headers.user;
// Only one Protected Action per user is allowed to take place, delete the previous one
if let Some(pa) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::ProtectedActions as i32, &conn).await
{
if let Some(pa) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::ProtectedActions, &conn).await {
let pa_data = ProtectedActionData::from_json(&pa.data)?;
let elapsed = pa_data.time_since_sent().num_seconds();
let delay = 30;
@ -125,7 +124,7 @@ pub async fn validate_protected_action_otp(
delete_if_valid: bool,
conn: &DbConn,
) -> EmptyResult {
let mut pa = TwoFactor::find_by_user_and_type(user_id, TwoFactorType::ProtectedActions as i32, conn)
let mut pa = TwoFactor::find_by_user_and_type(user_id, TwoFactorType::ProtectedActions, conn)
.await
.map_res("Protected action token not found, try sending the code again or restart the process")?;
let mut pa_data = ProtectedActionData::from_json(&pa.data)?;

17
src/api/core/two_factor/webauthn.rs

@ -269,8 +269,9 @@ async fn activate_webauthn(data: Json<EnableWebauthnData>, headers: Headers, con
two_factor::validate_webauthn(&data.user_verification_token, &user.uuid, &keys, false)?;
// Retrieve and delete the saved challenge state
let type_ = TwoFactorType::WebauthnRegisterChallenge as i32;
let state = if let Some(tf) = TwoFactor::find_by_user_and_type(&user.uuid, type_, &conn).await {
let state = if let Some(tf) =
TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::WebauthnRegisterChallenge, &conn).await
{
let state: PasskeyRegistration = serde_json::from_str(&tf.data)?;
tf.delete(&conn).await?;
state
@ -317,7 +318,7 @@ async fn activate_webauthn_put(data: Json<EnableWebauthnData>, headers: Headers,
async fn delete_webauthn(data: Json<VerificationTokenData>, headers: Headers, conn: DbConn) -> EmptyResult {
let user = headers.user;
let Some(tf) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Webauthn as i32, &conn).await else {
let Some(tf) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::Webauthn, &conn).await else {
err!("Webauthn data not found!")
};
@ -332,7 +333,7 @@ async fn delete_webauthn(data: Json<VerificationTokenData>, headers: Headers, co
let migrated: Vec<WebauthnRegistration> = removed.into_iter().filter(|r| r.migrated).collect();
// If entry is migrated from u2f, delete the u2f entry as well
if !migrated.is_empty()
&& let Some(mut u2f) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::U2f as i32, &conn).await
&& let Some(mut u2f) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::U2f, &conn).await
{
let Ok(mut data) = serde_json::from_str::<Vec<U2FRegistration>>(&u2f.data) else {
err!("Error parsing U2F data")
@ -360,8 +361,7 @@ pub async fn get_webauthn_registrations(
user_id: &UserId,
conn: &DbConn,
) -> Result<(bool, Vec<WebauthnRegistration>), Error> {
let type_ = TwoFactorType::Webauthn as i32;
match TwoFactor::find_by_user_and_type(user_id, type_, conn).await {
match TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Webauthn, conn).await {
Some(tf) => Ok((tf.enabled, serde_json::from_str(&tf.data)?)),
None => Ok((false, Vec::new())), // If no data, return empty list
}
@ -408,8 +408,9 @@ pub async fn generate_webauthn_login(user_id: &UserId, conn: &DbConn) -> JsonRes
}
pub async fn validate_webauthn_login(user_id: &UserId, response: &str, conn: &DbConn) -> EmptyResult {
let type_ = TwoFactorType::WebauthnLoginChallenge as i32;
let mut state = if let Some(tf) = TwoFactor::find_by_user_and_type(user_id, type_, conn).await {
let mut state = if let Some(tf) =
TwoFactor::find_by_user_and_type(user_id, TwoFactorType::WebauthnLoginChallenge, conn).await
{
let state: PasskeyAuthentication = serde_json::from_str(&tf.data)?;
tf.delete(conn).await?;
state

7
src/api/core/two_factor/yubikey.rs

@ -127,10 +127,9 @@ async fn generate_yubikey(data: Json<PasswordOrOtpData>, headers: Headers, conn:
data.validate(&user, false, &conn).await?;
let user_id = &user.uuid;
let yubikey_type = TwoFactorType::YubiKey as i32;
let (enabled, keys, yubikey_json) =
if let Some(r) = TwoFactor::find_by_user_and_type(user_id, yubikey_type, &conn).await {
if let Some(r) = TwoFactor::find_by_user_and_type(user_id, TwoFactorType::YubiKey, &conn).await {
let yubikey_metadata: YubikeyMetadata = serde_json::from_str(&r.data)?;
let enabled = !yubikey_metadata.keys.is_empty();
let mut result = jsonify_yubikeys(yubikey_metadata.keys.clone());
@ -160,7 +159,7 @@ async fn activate_yubikey(data: Json<EnableYubikeyData>, headers: Headers, conn:
// Check if we already have some data
let mut yubikey_data =
if let Some(yd) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::YubiKey as i32, &conn).await {
if let Some(yd) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::YubiKey, &conn).await {
let ym: YubikeyMetadata = serde_json::from_str(&yd.data)?;
two_factor::validate_yubikey(&data.user_verification_token, &user.uuid, &ym.keys, !ym.keys.is_empty())?;
yd
@ -207,7 +206,7 @@ async fn activate_yubikey_put(data: Json<EnableYubikeyData>, headers: Headers, c
async fn delete_yubikeys(data: Json<VerificationTokenData>, headers: Headers, conn: DbConn) -> EmptyResult {
let user = headers.user;
if let Some(r) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::YubiKey as i32, &conn).await {
if let Some(r) = TwoFactor::find_by_user_and_type(&user.uuid, TwoFactorType::YubiKey, &conn).await {
let yubikey_metadata: YubikeyMetadata = serde_json::from_str(&r.data)?;
two_factor::validate_yubikey(&data.user_verification_token, &user.uuid, &yubikey_metadata.keys, true)?;

4
src/api/identity.rs

@ -993,7 +993,7 @@ async fn json_err_twofactor(
}
Some(tf_type @ TwoFactorType::YubiKey) => {
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, tf_type as i32, conn).await else {
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, tf_type, conn).await else {
err!("No YubiKey devices registered")
};
@ -1005,7 +1005,7 @@ async fn json_err_twofactor(
}
Some(tf_type @ TwoFactorType::Email) => {
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, tf_type as i32, conn).await else {
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, tf_type, conn).await else {
err!("No twofactor email registered")
};

4
src/db/models/two_factor.rs

@ -137,11 +137,11 @@ impl TwoFactor {
.await
}
pub async fn find_by_user_and_type(user_uuid: &UserId, atype: i32, conn: &DbConn) -> Option<Self> {
pub async fn find_by_user_and_type(user_uuid: &UserId, atype: TwoFactorType, conn: &DbConn) -> Option<Self> {
conn.run(move |conn| {
twofactor::table
.filter(twofactor::user_uuid.eq(user_uuid))
.filter(twofactor::atype.eq(atype))
.filter(twofactor::atype.eq(atype as i32))
.first::<Self>(conn)
.ok()
})

Loading…
Cancel
Save