"""Identification du client : X-Forwarded-For n'est cru que sur demande.""" from __future__ import annotations from starlette.datastructures import Headers from starlette.requests import Request from app.services.client_ip import resolve_client_ip def _request(headers: dict[str, str], peer: str | None = "203.0.113.9") -> Request: scope = { "type": "http", "method": "GET", "path": "/api/shares", "headers": Headers(headers).raw, "client": (peer, 12345) if peer else None, } return Request(scope) def test_proxy_headers_are_ignored_by_default() -> None: request = _request({"x-forwarded-for": "1.2.3.4"}) assert resolve_client_ip(request, trust_proxy_headers=False) == "203.0.113.9" def test_forged_header_cannot_change_identity() -> None: """Sans confiance explicite, un client direct ne peut pas se demultiplier.""" seen = { resolve_client_ip(_request({"x-forwarded-for": f"10.0.0.{i}"}), trust_proxy_headers=False) for i in range(20) } assert seen == {"203.0.113.9"} def test_trusted_proxy_uses_the_last_forwarded_value() -> None: # Le client a forge "9.9.9.9" ; le proxy a ajoute l'adresse reellement vue. request = _request({"x-forwarded-for": "9.9.9.9, 198.51.100.7"}) assert resolve_client_ip(request, trust_proxy_headers=True) == "198.51.100.7" def test_trusted_proxy_falls_back_to_real_ip() -> None: request = _request({"x-real-ip": "198.51.100.8"}) assert resolve_client_ip(request, trust_proxy_headers=True) == "198.51.100.8" def test_falls_back_to_peer_without_headers() -> None: assert resolve_client_ip(_request({}), trust_proxy_headers=True) == "203.0.113.9" def test_unknown_client_is_handled() -> None: assert resolve_client_ip(_request({}, peer=None), trust_proxy_headers=False) == "unknown"