diff --git a/apps/employees/src/handlers/auth.rs b/apps/employees/src/handlers/auth.rs index 5d38ec4..3d8872e 100644 --- a/apps/employees/src/handlers/auth.rs +++ b/apps/employees/src/handlers/auth.rs @@ -54,7 +54,12 @@ async fn login( Json(payload): Json, ) -> Result)> { let email = payload.email.to_lowercase(); - + let mut redis = state.redis.clone(); + + if !cache::rate_limit::check_admin_login(&mut redis, &email).await.unwrap_or(true) { + return Err(err(StatusCode::TOO_MANY_REQUESTS, "Too many login attempts. Try again in 15 minutes.", "RATE_LIMITED")); + } + let employee = EmployeeRepository::get_by_email(&state.pool, &email) .await .map_err(|_| err(StatusCode::INTERNAL_SERVER_ERROR, "DB error", "DB_ERROR"))? diff --git a/crates/cache/src/rate_limit.rs b/crates/cache/src/rate_limit.rs index 2416d03..9028b8b 100644 --- a/crates/cache/src/rate_limit.rs +++ b/crates/cache/src/rate_limit.rs @@ -41,6 +41,12 @@ pub async fn check_login(redis: &mut RedisPool, email: &str) -> Result Result { + check(redis, "admin_login", email, 5, 900).await +} + /// Lead request: max 5 per hour per professional pub async fn check_lead(redis: &mut RedisPool, professional_id: &str) -> Result { check(redis, "lead", professional_id, 5, 3_600).await