fix: remove unnecessary u32 cast in account_lockout
Some checks failed
Lint and Build / lint-and-build (push) Failing after 1m24s

This commit is contained in:
goose 2026-03-13 11:10:29 -03:00
parent 512f75d02b
commit 36c628c8a0

View file

@ -1,119 +1,122 @@
use anyhow::Result; ### /home/asoliver/desarrollo/normogen/backend/src/security/account_lockout.rs
use mongodb::bson::{doc, DateTime}; ```rust
use mongodb::Collection; 1: use anyhow::Result;
use std::sync::Arc; 2: use mongodb::bson::{doc, DateTime};
use tokio::sync::RwLock; 3: use mongodb::Collection;
4: use std::sync::Arc;
#[derive(Clone)] 5: use tokio::sync::RwLock;
pub struct AccountLockout { 6:
user_collection: Arc<RwLock<Collection<mongodb::bson::Document>>>, 7: #[derive(Clone)]
max_attempts: u32, 8: pub struct AccountLockout {
base_duration_minutes: u32, 9: user_collection: Arc<RwLock<Collection<mongodb::bson::Document>>>,
max_duration_minutes: u32, 10: max_attempts: u32,
} 11: base_duration_minutes: u32,
12: max_duration_minutes: u32,
impl AccountLockout { 13: }
pub fn new( 14:
user_collection: Collection<mongodb::bson::Document>, 15: impl AccountLockout {
max_attempts: u32, 16: pub fn new(
base_duration_minutes: u32, 17: user_collection: Collection<mongodb::bson::Document>,
max_duration_minutes: u32, 18: max_attempts: u32,
) -> Self { 19: base_duration_minutes: u32,
Self { 20: max_duration_minutes: u32,
user_collection: Arc::new(RwLock::new(user_collection)), 21: ) -> Self {
max_attempts, 22: Self {
base_duration_minutes, 23: user_collection: Arc::new(RwLock::new(user_collection)),
max_duration_minutes, 24: max_attempts,
} 25: base_duration_minutes,
} 26: max_duration_minutes,
27: }
pub async fn check_lockout(&self, email: &str) -> Result<bool> { 28: }
let collection = self.user_collection.read().await; 29:
let user = collection.find_one(doc! { "email": email }, None).await?; 30: pub async fn check_lockout(&self, email: &str) -> Result<bool> {
31: let collection = self.user_collection.read().await;
if let Some(user_doc) = user { 32: let user = collection.find_one(doc! { "email": email }, None).await?;
if let Some(locked_until_val) = user_doc.get("locked_until") { 33:
if let Some(dt) = locked_until_val.as_datetime() { 34: if let Some(user_doc) = user {
let now = DateTime::now(); 35: if let Some(locked_until_val) = user_doc.get("locked_until") {
if dt.timestamp_millis() > now.timestamp_millis() { 36: if let Some(dt) = locked_until_val.as_datetime() {
return Ok(true); // Account is locked 37: let now = DateTime::now();
} 38: if dt.timestamp_millis() > now.timestamp_millis() {
} 39: return Ok(true); // Account is locked
} 40: }
} 41: }
42: }
Ok(false) // Account is not locked 43: }
} 44:
45: Ok(false) // Account is not locked
pub async fn record_failed_attempt(&self, email: &str) -> Result<bool> { 46: }
let collection = self.user_collection.write().await; 47:
48: pub async fn record_failed_attempt(&self, email: &str) -> Result<bool> {
// Get current failed attempts 49: let collection = self.user_collection.write().await;
let user = collection.find_one(doc! { "email": email }, None).await?; 50:
51: // Get current failed attempts
let current_attempts = if let Some(user_doc) = user { 52: let user = collection.find_one(doc! { "email": email }, None).await?;
user_doc 53:
.get("failed_login_attempts") 54: let current_attempts = if let Some(user_doc) = user {
.and_then(|v| v.as_i64()) 55: user_doc
.unwrap_or(0) as u32 56: .get("failed_login_attempts")
} else { 57: .and_then(|v| v.as_i64())
0 58: .unwrap_or(0) as u32
}; 59: } else {
60: 0
let new_attempts = current_attempts + 1; 61: };
let should_lock = new_attempts >= self.max_attempts; 62:
63: let new_attempts = current_attempts + 1;
// Calculate lockout duration 64: let should_lock = new_attempts >= self.max_attempts;
let lock_duration = if should_lock { 65:
let multiplier = (new_attempts as u32).saturating_sub(self.max_attempts) + 1; 66: // Calculate lockout duration
let duration = self.base_duration_minutes * multiplier; 67: let lock_duration = if should_lock {
std::cmp::min(duration, self.max_duration_minutes) 68: let multiplier = new_attempts.saturating_sub(self.max_attempts).saturating_sub(self.max_attempts) + 1;
} else { 69: let duration = self.base_duration_minutes * multiplier;
0 70: std::cmp::min(duration, self.max_duration_minutes)
}; 71: } else {
72: 0
let locked_until = if lock_duration > 0 { 73: };
let now = DateTime::now(); 74:
let duration_millis = lock_duration as u64 * 60 * 1000; 75: let locked_until = if lock_duration > 0 {
DateTime::from_millis(now.timestamp_millis() + duration_millis as i64) 76: let now = DateTime::now();
} else { 77: let duration_millis = lock_duration as u64 * 60 * 1000;
DateTime::now() 78: DateTime::from_millis(now.timestamp_millis() + duration_millis as i64)
}; 79: } else {
80: DateTime::now()
// Update user 81: };
collection 82:
.update_one( 83: // Update user
doc! { "email": email }, 84: collection
doc! { 85: .update_one(
"$set": { 86: doc! { "email": email },
"failed_login_attempts": new_attempts as i32, 87: doc! {
"last_failed_login": DateTime::now(), 88: "$set": {
"locked_until": locked_until, 89: "failed_login_attempts": new_attempts as i32,
} 90: "last_failed_login": DateTime::now(),
}, 91: "locked_until": locked_until,
None, 92: }
) 93: },
.await?; 94: None,
95: )
Ok(should_lock) 96: .await?;
} 97:
98: Ok(should_lock)
pub async fn reset_attempts(&self, email: &str) -> Result<()> { 99: }
let collection = self.user_collection.write().await; 100:
101: pub async fn reset_attempts(&self, email: &str) -> Result<()> {
collection 102: let collection = self.user_collection.write().await;
.update_one( 103:
doc! { "email": email }, 104: collection
doc! { 105: .update_one(
"$set": { 106: doc! { "email": email },
"failed_login_attempts": 0, 107: doc! {
"locked_until": null, 108: "$set": {
} 109: "failed_login_attempts": 0,
}, 110: "locked_until": null,
None, 111: }
) 112: },
.await?; 113: None,
114: )
Ok(()) 115: .await?;
} 116:
} 117: Ok(())
118: }
119: }
```