fix email as 2fa for sso (#6495)

* fix email as 2fa for sso

* allow saving device without updating `updated_at`

* check if email is some

* allow device to be saved in postgresql

* use twofactor_incomplete table

* no need to update device.updated_at
This commit is contained in:
Stefan Melmuk
2025-12-06 22:22:33 +01:00
committed by GitHub
parent 8f689d8795
commit 4ad8baf7be
7 changed files with 94 additions and 61 deletions
+15 -9
View File
@@ -1,4 +1,4 @@
use chrono::{NaiveDateTime, Utc};
use chrono::Utc;
use num_traits::FromPrimitive;
use rocket::{
form::{Form, FromForm},
@@ -148,7 +148,7 @@ async fn _refresh_login(data: ConnectData, conn: &DbConn, ip: &ClientIp) -> Json
}
Ok((mut device, auth_tokens)) => {
// Save to update `device.updated_at` to track usage and toggle new status
device.save(conn).await?;
device.save(true, conn).await?;
let result = json!({
"refresh_token": auth_tokens.refresh_token(),
@@ -274,6 +274,7 @@ async fn _sso_login(
}
Some((mut user, sso_user)) => {
let mut device = get_device(&data, conn, &user).await?;
let twofactor_token = twofactor_auth(&mut user, &data, &mut device, ip, client_version, conn).await?;
if user.private_key.is_none() {
@@ -303,7 +304,7 @@ async fn _sso_login(
// We passed 2FA get auth tokens
let auth_tokens = sso::redeem(&device, &user, data.client_id, sso_user, sso_auth, user_infos, conn).await?;
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, &now, conn, ip).await
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, conn, ip).await
}
async fn _password_login(
@@ -425,7 +426,7 @@ async fn _password_login(
let auth_tokens = auth::AuthTokens::new(&device, &user, AuthMethod::Password, data.client_id);
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, &now, conn, ip).await
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, conn, ip).await
}
async fn authenticated_response(
@@ -433,12 +434,12 @@ async fn authenticated_response(
device: &mut Device,
auth_tokens: auth::AuthTokens,
twofactor_token: Option<String>,
now: &NaiveDateTime,
conn: &DbConn,
ip: &ClientIp,
) -> JsonResult {
if CONFIG.mail_enabled() && device.is_new() {
if let Err(e) = mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), now, device).await {
let now = Utc::now().naive_utc();
if let Err(e) = mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), &now, device).await {
error!("Error sending new device email: {e:#?}");
if CONFIG.require_device_email() {
@@ -458,7 +459,7 @@ async fn authenticated_response(
}
// Save to update `device.updated_at` to track usage and toggle new status
device.save(conn).await?;
device.save(true, conn).await?;
let master_password_policy = master_password_policy(user, conn).await;
@@ -575,7 +576,7 @@ async fn _user_api_key_login(
let access_claims = auth::LoginJwtClaims::default(&device, &user, &AuthMethod::UserApiKey, data.client_id);
// Save to update `device.updated_at` to track usage and toggle new status
device.save(conn).await?;
device.save(true, conn).await?;
info!("User {} logged in successfully via API key. IP: {}", user.email, ip.ip);
@@ -638,7 +639,12 @@ async fn get_device(data: &ConnectData, conn: &DbConn, user: &User) -> ApiResult
// Find device or create new
match Device::find_by_uuid_and_user(&device_id, &user.uuid, conn).await {
Some(device) => Ok(device),
None => Device::new(device_id, user.uuid.clone(), device_name, device_type, conn).await,
None => {
let mut device = Device::new(device_id, user.uuid.clone(), device_name, device_type);
// save device without updating `device.updated_at`
device.save(false, conn).await?;
Ok(device)
}
}
}