"""Shared dependency utilities — request parsing helpers used across all API routers.""" from __future__ import annotations import ipaddress import uuid from typing import Optional from fastapi import HTTPException, Request _TRUSTED_PROXY_NETS = [ ipaddress.ip_network("127.0.0.0/8"), ipaddress.ip_network("172.16.0.0/12"), ipaddress.ip_network("192.168.0.0/16"), ipaddress.ip_network("::1/128"), ] def _is_trusted_proxy(host: str) -> bool: try: addr = ipaddress.ip_address(host) return any(addr in net for net in _TRUSTED_PROXY_NETS) except ValueError: return False def get_client_ip(request: Request) -> Optional[str]: """Extract best-effort client IP from request for audit logging (D-11 — trusted-proxy CIDR check). Only honours X-Forwarded-For when the direct peer is a known trusted proxy (RFC-1918 / loopback). Untrusted direct peers always return their own address, preventing XFF spoofing by external callers. TRUST BOUNDARY: this value is used for forensic audit logging only — not for authentication or access control decisions. """ direct_peer = request.client.host if request.client else None if direct_peer and _is_trusted_proxy(direct_peer): xff = request.headers.get("X-Forwarded-For") if xff: return xff.split(",")[0].strip() return direct_peer def parse_uuid(value: str, detail: str = "Not found") -> uuid.UUID: """Parse *value* as a UUID, raising HTTP 404 with *detail* on failure. Use at API boundaries to convert path/body string IDs to UUID objects. Returns the parsed UUID so callers can use it directly without a try/except. """ try: return uuid.UUID(value) except ValueError: raise HTTPException(status_code=404, detail=detail)