Private
Public Access
1
0

fix: eslint-disable for useEffect deps in UsersPage
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 5s
CI Pipeline / Clippy Lints (push) Successful in 46s
CI Pipeline / Rust Unit Tests (push) Successful in 1m2s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 14s
CI Pipeline / Build .deb & Release (push) Has been skipped

This commit is contained in:
2026-05-07 19:14:21 +00:00
parent cc1214a963
commit 08add28b80
17 changed files with 359 additions and 76 deletions

View File

@ -19,7 +19,7 @@ pub mod session;
// Commonly re-exported types
pub use jwt::{AccessClaims, JwtError};
pub use password::{hash_password, verify_password, PasswordError};
pub use password::validate_password_strength;
pub use password::{hash_password, verify_password, PasswordError};
pub use rbac::{AuthConfig, AuthUser, UserRole};
pub use session::{LoginRequest, LoginResponse, SessionError, SessionUser};

View File

@ -90,7 +90,10 @@ pub fn validate_password_strength(password: &str) -> Result<(), String> {
}
let special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?";
if !password.chars().any(|c| special_chars.contains(c)) {
return Err("Password must contain at least one special character (!@#$%^&*()_+-=[]{}|;:,.<>?)".to_string());
return Err(
"Password must contain at least one special character (!@#$%^&*()_+-=[]{}|;:,.<>?)"
.to_string(),
);
}
Ok(())
}

View File

@ -141,10 +141,12 @@ pub async fn login(
return Err(SessionError::AccountLocked);
}
// Lockout period has expired — reset counters
sqlx::query("UPDATE users SET failed_login_attempts = 0, locked_until = NULL WHERE id = $1")
.bind(user.id)
.execute(pool)
.await?;
sqlx::query(
"UPDATE users SET failed_login_attempts = 0, locked_until = NULL WHERE id = $1",
)
.bind(user.id)
.execute(pool)
.await?;
}
// 2. Verify password
@ -156,12 +158,14 @@ pub async fn login(
let new_attempts = user.failed_login_attempts + 1;
if new_attempts >= 5 {
let lock_until = Utc::now() + chrono::Duration::minutes(30);
sqlx::query("UPDATE users SET failed_login_attempts = $1, locked_until = $2 WHERE id = $3")
.bind(new_attempts)
.bind(lock_until)
.bind(user.id)
.execute(pool)
.await?;
sqlx::query(
"UPDATE users SET failed_login_attempts = $1, locked_until = $2 WHERE id = $3",
)
.bind(new_attempts)
.bind(lock_until)
.bind(user.id)
.execute(pool)
.await?;
tracing::warn!(username = %req.username, "Account locked after {} failed attempts", new_attempts);
} else {
sqlx::query("UPDATE users SET failed_login_attempts = $1 WHERE id = $2")