Dateien
AegisSight-Monitor/src/email_utils/rate_limiter.py
Claude Dev 8f1a45c1a9 Auth: Nur noch Magic Link, Code-Verifizierung entfernt
- /api/auth/verify-code Endpoint entfernt
- generate_magic_code() und VerifyCodeRequest entfernt
- VerifyCodeLimiter (Brute-Force-Schutz) entfernt (nicht mehr noetig)
- E-Mail-Template: Nur noch Anmelde-Link, kein 6-stelliger Code
- Login-Seite: Zeigt nach E-Mail-Eingabe Hinweis statt Code-Feld
- Magic Link Token-Verifikation via URL bleibt bestehen
2026-03-25 00:01:19 +01:00

56 Zeilen
1.9 KiB
Python

"""In-Memory Rate-Limiting fuer Magic-Link-Anfragen."""
import time
from collections import defaultdict
class RateLimiter:
"""Rate-Limiter mit zwei Ebenen: pro E-Mail und pro IP."""
def __init__(
self,
max_per_email: int = 3,
email_window_seconds: int = 900, # 15 Minuten
max_per_ip: int = 10,
ip_window_seconds: int = 3600, # 1 Stunde
):
self.max_per_email = max_per_email
self.email_window = email_window_seconds
self.max_per_ip = max_per_ip
self.ip_window = ip_window_seconds
self._email_requests: dict[str, list[float]] = defaultdict(list)
self._ip_requests: dict[str, list[float]] = defaultdict(list)
def _clean(self, entries: list[float], window: int) -> list[float]:
cutoff = time.time() - window
return [t for t in entries if t > cutoff]
def check(self, email: str, ip: str) -> tuple[bool, str]:
"""Prueft ob die Anfrage erlaubt ist.
Returns:
(erlaubt, grund) - True wenn OK, False mit Grund wenn blockiert.
"""
now = time.time()
# E-Mail-Limit
self._email_requests[email] = self._clean(self._email_requests[email], self.email_window)
if len(self._email_requests[email]) >= self.max_per_email:
return False, "Zu viele Anfragen fuer diese E-Mail-Adresse. Bitte warten."
# IP-Limit
self._ip_requests[ip] = self._clean(self._ip_requests[ip], self.ip_window)
if len(self._ip_requests[ip]) >= self.max_per_ip:
return False, "Zu viele Anfragen von dieser IP-Adresse. Bitte warten."
return True, ""
def record(self, email: str, ip: str):
"""Zeichnet eine erfolgreiche Anfrage auf."""
now = time.time()
self._email_requests[email].append(now)
self._ip_requests[ip].append(now)
# Singleton-Instanz
magic_link_limiter = RateLimiter()