fix: restore Instant for rate limiters, keep SystemTime for sessions
Rate limiters correctly use monotonic Instant. Session TTL uses SystemTime for wall-clock accuracy across sleep/hibernate. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0b3bf5b635
commit
979e1c7411
@ -2,7 +2,7 @@ use sha2::{Digest, Sha256};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::SystemTime;
|
use std::time::{Instant, SystemTime};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ impl LoginRateLimiter {
|
|||||||
|
|
||||||
pub async fn check(&self, ip: IpAddr) -> bool {
|
pub async fn check(&self, ip: IpAddr) -> bool {
|
||||||
let mut attempts = self.attempts.write().await;
|
let mut attempts = self.attempts.write().await;
|
||||||
let now = SystemTime::now();
|
let now = Instant::now();
|
||||||
let entry = attempts.entry(ip).or_default();
|
let entry = attempts.entry(ip).or_default();
|
||||||
entry.retain(|t| now.duration_since(*t).as_secs() < WINDOW_SECS);
|
entry.retain(|t| now.duration_since(*t).as_secs() < WINDOW_SECS);
|
||||||
entry.len() < MAX_ATTEMPTS
|
entry.len() < MAX_ATTEMPTS
|
||||||
@ -271,7 +271,7 @@ impl LoginRateLimiter {
|
|||||||
pub async fn record_failure(&self, ip: IpAddr) {
|
pub async fn record_failure(&self, ip: IpAddr) {
|
||||||
let mut attempts = self.attempts.write().await;
|
let mut attempts = self.attempts.write().await;
|
||||||
let entry = attempts.entry(ip).or_default();
|
let entry = attempts.entry(ip).or_default();
|
||||||
entry.push(SystemTime::now());
|
entry.push(Instant::now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ impl LoginRateLimiter {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EndpointRateLimiter {
|
pub struct EndpointRateLimiter {
|
||||||
/// Map of (method, ip) -> list of request timestamps
|
/// Map of (method, ip) -> list of request timestamps
|
||||||
requests: Arc<RwLock<HashMap<(String, IpAddr), Vec<Instant>>>>,
|
requests: Arc<RwLock<HashMap<(String, IpAddr), Vec<Instant>>>>, // Instant for monotonic rate limiting
|
||||||
/// Per-method configuration: (max_requests, window_secs)
|
/// Per-method configuration: (max_requests, window_secs)
|
||||||
limits: Arc<HashMap<String, (usize, u64)>>,
|
limits: Arc<HashMap<String, (usize, u64)>>,
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ impl EndpointRateLimiter {
|
|||||||
|
|
||||||
let key = (method.to_string(), ip);
|
let key = (method.to_string(), ip);
|
||||||
let mut requests = self.requests.write().await;
|
let mut requests = self.requests.write().await;
|
||||||
let now = SystemTime::now();
|
let now = Instant::now();
|
||||||
let entry = requests.entry(key).or_default();
|
let entry = requests.entry(key).or_default();
|
||||||
entry.retain(|t| now.duration_since(*t).as_secs() < window);
|
entry.retain(|t| now.duration_since(*t).as_secs() < window);
|
||||||
entry.len() < max_req
|
entry.len() < max_req
|
||||||
@ -352,13 +352,13 @@ impl EndpointRateLimiter {
|
|||||||
let key = (method.to_string(), ip);
|
let key = (method.to_string(), ip);
|
||||||
let mut requests = self.requests.write().await;
|
let mut requests = self.requests.write().await;
|
||||||
let entry = requests.entry(key).or_default();
|
let entry = requests.entry(key).or_default();
|
||||||
entry.push(SystemTime::now());
|
entry.push(Instant::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Periodic cleanup of expired entries.
|
/// Periodic cleanup of expired entries.
|
||||||
pub async fn cleanup(&self) {
|
pub async fn cleanup(&self) {
|
||||||
let mut requests = self.requests.write().await;
|
let mut requests = self.requests.write().await;
|
||||||
let now = SystemTime::now();
|
let now = Instant::now();
|
||||||
requests.retain(|(method, _), timestamps| {
|
requests.retain(|(method, _), timestamps| {
|
||||||
let window = self
|
let window = self
|
||||||
.limits
|
.limits
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user