feat: Phase 1 - user/password API extensions and auth route fix
Some checks failed
CI Pipeline / Rust Format Check (push) Failing after 5s
CI Pipeline / Clippy Lints (push) Successful in 46s
CI Pipeline / Rust Unit Tests (push) Successful in 1m1s
CI Pipeline / Security Audit (push) Successful in 5s
CI Pipeline / Frontend Lint & Type Check (push) Failing after 10s
CI Pipeline / Build .deb & Release (push) Has been skipped
Some checks failed
CI Pipeline / Rust Format Check (push) Failing after 5s
CI Pipeline / Clippy Lints (push) Successful in 46s
CI Pipeline / Rust Unit Tests (push) Successful in 1m1s
CI Pipeline / Security Audit (push) Successful in 5s
CI Pipeline / Frontend Lint & Type Check (push) Failing after 10s
CI Pipeline / Build .deb & Release (push) Has been skipped
This commit is contained in:
@ -24,6 +24,8 @@ pub enum SessionError {
|
||||
InvalidCredentials,
|
||||
#[error("Account is disabled")]
|
||||
AccountDisabled,
|
||||
#[error("Password reset required")]
|
||||
PasswordResetRequired,
|
||||
#[error("MFA required")]
|
||||
MfaRequired,
|
||||
#[error("Invalid MFA code")]
|
||||
@ -75,6 +77,7 @@ struct DbUser {
|
||||
totp_secret: Option<String>,
|
||||
mfa_enabled: bool,
|
||||
is_active: bool,
|
||||
force_password_reset: bool,
|
||||
}
|
||||
|
||||
/// Login request payload.
|
||||
@ -107,7 +110,7 @@ pub async fn login(
|
||||
let user: Option<DbUser> = sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, username, display_name, role, auth_provider,
|
||||
password_hash, totp_secret, mfa_enabled, is_active
|
||||
password_hash, totp_secret, mfa_enabled, is_active, force_password_reset
|
||||
FROM users
|
||||
WHERE username = $1 AND auth_provider = 'local'
|
||||
"#,
|
||||
@ -141,6 +144,12 @@ pub async fn login(
|
||||
return Err(SessionError::AccountDisabled);
|
||||
}
|
||||
|
||||
// 3b. Check if password reset is required
|
||||
if user.force_password_reset {
|
||||
tracing::warn!(username = %req.username, "Login blocked: password reset required");
|
||||
return Err(SessionError::PasswordResetRequired);
|
||||
}
|
||||
|
||||
// 4. MFA check
|
||||
if user.mfa_enabled {
|
||||
let code = req.totp_code.as_deref().ok_or(SessionError::MfaRequired)?;
|
||||
@ -207,7 +216,7 @@ pub async fn refresh_session(
|
||||
let user: DbUser = sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, username, display_name, role, auth_provider,
|
||||
password_hash, totp_secret, mfa_enabled, is_active
|
||||
password_hash, totp_secret, mfa_enabled, is_active, force_password_reset
|
||||
FROM users WHERE id = $1
|
||||
"#,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user