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