campus-placement-engine / backend /app /api /auth /rate_limiter.py
deeep-sec's picture
feat: institutional campus placement eligibility & interview scheduling engine
788eab4 verified
Raw History Blame Contribute Delete
1.96 kB
"""
In-memory Rate Limiter for Authentication Endpoints.
Prevents brute-force credential stuffing and password guessing on college LAN.
"""
from __future__ import annotations
import collections
import datetime
import threading
class LoginRateLimiter:
"""Sliding-window rate limiter per identifier (IP or username)."""
def __init__(self, max_attempts: int = 5, window_seconds: int = 60) -> None:
self.max_attempts = max_attempts
self.window_seconds = window_seconds
self._attempts: dict[str, collections.deque[datetime.datetime]] = collections.defaultdict(collections.deque)
self._lock = threading.Lock()
def is_rate_limited(self, key: str) -> bool:
"""Returns True if the identifier has exceeded the maximum attempts in the window."""
with self._lock:
now = datetime.datetime.utcnow()
cutoff = now - datetime.timedelta(seconds=self.window_seconds)
history = self._attempts[key]
# Prune expired timestamps
while history and history[0] < cutoff:
history.popleft()
return len(history) >= self.max_attempts
def record_attempt(self, key: str) -> None:
"""Records a failed authentication attempt."""
with self._lock:
now = datetime.datetime.utcnow()
cutoff = now - datetime.timedelta(seconds=self.window_seconds)
history = self._attempts[key]
while history and history[0] < cutoff:
history.popleft()
history.append(now)
def reset(self, key: str) -> None:
"""Resets rate limiting history on successful authentication."""
with self._lock:
if key in self._attempts:
self._attempts[key].clear()
# Global login rate limiter instance
login_rate_limiter = LoginRateLimiter(max_attempts=5, window_seconds=60)