fix(clippy): remove unnecessary u32 cast (final take)
Some checks failed
Lint and Build / lint-and-build (push) Failing after 5m33s

This commit is contained in:
goose 2026-03-13 11:31:39 -03:00
parent 614039bfc9
commit bd34ee1618

View file

@ -1,122 +1,119 @@
### /home/asoliver/desarrollo/normogen/backend/src/security/account_lockout.rs
```rust
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<RwLock<Collection<mongodb::bson::Document>>>,
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<mongodb::bson::Document>,
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<bool> {
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<bool> {
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: }
```
use anyhow::Result;
use mongodb::bson::{doc, DateTime};
use mongodb::Collection;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Clone)]
pub struct AccountLockout {
user_collection: Arc<RwLock<Collection<mongodb::bson::Document>>>,
max_attempts: u32,
base_duration_minutes: u32,
max_duration_minutes: u32,
}
impl AccountLockout {
pub fn new(
user_collection: Collection<mongodb::bson::Document>,
max_attempts: u32,
base_duration_minutes: u32,
max_duration_minutes: u32,
) -> Self {
Self {
user_collection: Arc::new(RwLock::new(user_collection)),
max_attempts,
base_duration_minutes,
max_duration_minutes,
}
}
pub async fn check_lockout(&self, email: &str) -> Result<bool> {
let collection = self.user_collection.read().await;
let user = collection.find_one(doc! { "email": email }, None).await?;
if let Some(user_doc) = user {
if let Some(locked_until_val) = user_doc.get("locked_until") {
if let Some(dt) = locked_until_val.as_datetime() {
let now = DateTime::now();
if dt.timestamp_millis() > now.timestamp_millis() {
return Ok(true); // Account is locked
}
}
}
}
Ok(false) // Account is not locked
}
pub async fn record_failed_attempt(&self, email: &str) -> Result<bool> {
let collection = self.user_collection.write().await;
// Get current failed attempts
let user = collection.find_one(doc! { "email": email }, None).await?;
let current_attempts = if let Some(user_doc) = user {
user_doc
.get("failed_login_attempts")
.and_then(|v| v.as_i64())
.unwrap_or(0) as u32
} else {
0
};
let new_attempts = current_attempts + 1;
let should_lock = new_attempts >= self.max_attempts;
// Calculate lockout duration
let lock_duration = if should_lock {
let multiplier = new_attempts.saturating_sub(self.max_attempts) + 1;
let duration = self.base_duration_minutes * multiplier;
std::cmp::min(duration, self.max_duration_minutes)
} else {
0
};
let locked_until = if lock_duration > 0 {
let now = DateTime::now();
let duration_millis = lock_duration as u64 * 60 * 1000;
DateTime::from_millis(now.timestamp_millis() + duration_millis as i64)
} else {
DateTime::now()
};
// Update user
collection
.update_one(
doc! { "email": email },
doc! {
"$set": {
"failed_login_attempts": new_attempts as i32,
"last_failed_login": DateTime::now(),
"locked_until": locked_until,
}
},
None,
)
.await?;
Ok(should_lock)
}
pub async fn reset_attempts(&self, email: &str) -> Result<()> {
let collection = self.user_collection.write().await;
collection
.update_one(
doc! { "email": email },
doc! {
"$set": {
"failed_login_attempts": 0,
"locked_until": null,
}
},
None,
)
.await?;
Ok(())
}
}