Refactor configuration and security features for improved development experience
- Updated the .env.example file to reflect a development environment setup with enhanced secret key requirements and local host settings. - Modified the Docker Compose configuration to enhance security with read-only settings and no-new-privileges options. - Updated requirements.txt to pin package versions for better dependency management. - Enhanced the FastAPI application to include dynamic OpenAPI and documentation URLs based on the environment. - Implemented session versioning in JWT tokens to improve security and user session management. - Added new validation for user roles and password strength in schemas. - Improved email sending logic to handle recipient lists more robustly and added logging for SMTP operations. - Updated dashboard and profile templates to reflect new features and improve user experience.
This commit is contained in:
35
app/core/rate_limit.py
Normal file
35
app/core/rate_limit.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
from fastapi import HTTPException, Request, status
|
||||
|
||||
_WINDOW_SECONDS = 300
|
||||
_MAX_ATTEMPTS = 5
|
||||
_attempts: dict[str, list[float]] = defaultdict(list)
|
||||
|
||||
|
||||
def _client_key(request: Request, email: str) -> str:
|
||||
forwarded = request.headers.get("x-forwarded-for", "")
|
||||
ip = forwarded.split(",")[0].strip() if forwarded else (request.client.host if request.client else "unknown")
|
||||
return f"{ip}:{email.strip().lower()}"
|
||||
|
||||
|
||||
def check_login_rate_limit(request: Request, email: str) -> None:
|
||||
key = _client_key(request, email)
|
||||
now = time.monotonic()
|
||||
window_start = now - _WINDOW_SECONDS
|
||||
recent = [t for t in _attempts[key] if t >= window_start]
|
||||
_attempts[key] = recent
|
||||
if len(recent) >= _MAX_ATTEMPTS:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
||||
detail="Zu viele Anmeldeversuche. Bitte in einigen Minuten erneut versuchen.",
|
||||
)
|
||||
|
||||
|
||||
def record_failed_login(request: Request, email: str) -> None:
|
||||
_attempts[_client_key(request, email)].append(time.monotonic())
|
||||
|
||||
|
||||
def clear_login_attempts(request: Request, email: str) -> None:
|
||||
_attempts.pop(_client_key(request, email), None)
|
||||
Reference in New Issue
Block a user