fix(clippy): remove unnecessary u32 cast (final take)
Some checks failed
Lint and Build / lint-and-build (push) Failing after 5m33s
Some checks failed
Lint and Build / lint-and-build (push) Failing after 5m33s
This commit is contained in:
parent
614039bfc9
commit
bd34ee1618
1 changed files with 119 additions and 122 deletions
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue