- sanitizer XSS serveur (markdown + page de partage) [BUG-021/022] - rate-limit/lockout MFA [BUG-023] - isolation vaults par segments [BUG-024] - caps regex ReDoS [BUG-025] - SSRF webhooks + secrets externalises [BUG-026] - rotation/revocation des jetons [BUG-027] - politique de mot de passe + invalidation sessions [BUG-028] - verrous users.json [BUG-029] - IP reelle dans les audits [BUG-030] - rate-limit par compte [BUG-031] - symlinks hors vault ignores [BUG-032] - recherche simple via inverted index [BUG-033] - token en memoire + cookie HttpOnly, CSP durcie [BUG-034] Tests: pytest 961 passed / 6 skipped, ruff 0, mypy 0, frontend vert.
35 lines
1.1 KiB
Python
35 lines
1.1 KiB
Python
"""Network helpers shared by the auth middleware and rate limiter."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from fastapi import Request
|
|
|
|
__all__ = ["get_client_ip", "is_trusted_proxy"]
|
|
|
|
|
|
def is_trusted_proxy() -> bool:
|
|
"""Whether ``X-Forwarded-For`` should be trusted (reverse proxy in front)."""
|
|
return os.environ.get("OBSIGATE_TRUST_PROXY", "false").lower() == "true"
|
|
|
|
|
|
def get_client_ip(request: Request) -> str:
|
|
"""Return the best-known client IP for *request*.
|
|
|
|
When ``OBSIGATE_TRUST_PROXY=true`` the left-most ``X-Forwarded-For`` entry
|
|
is used (the original client behind the proxy). Otherwise the socket peer
|
|
address is returned. BUG-030: this value feeds the audit log so attacks
|
|
remain traceable.
|
|
"""
|
|
if is_trusted_proxy():
|
|
forwarded = request.headers.get("x-forwarded-for")
|
|
if forwarded:
|
|
first = forwarded.split(",")[0].strip()
|
|
if first:
|
|
return first
|
|
real_ip = request.headers.get("x-real-ip")
|
|
if real_ip:
|
|
return real_ip.strip()
|
|
return request.client.host if request.client else "unknown"
|