"""Extrakce per-request přihlašovacích údajů z X- hlaviček. Secrets (ClientId/ClientSecret vydané PPL) chodí VÝHRADNĚ v hlavičkách, nikdy v těle requestu ani v URL. Nic se neukládá — služba je stateless; jedinou výjimkou je in-memory cache OAuth tokenů (viz token_cache.py), klíčovaná hashem údajů, protože PPL limituje vydávání tokenů na 12/min. """ import hashlib from dataclasses import dataclass from fastapi import Header from .config import CPL_DEFAULT_ENVIRONMENT, CPL_PRODUCTION_BASE_URL, CPL_TEST_BASE_URL from .errors import BadRequestError, CredentialsError _ENVIRONMENTS = ("production", "test") @dataclass class Credentials: client_id: str | None client_secret: str | None environment: str accept_language: str | None = None def require(self) -> None: if not self.client_id or not self.client_id.strip(): raise CredentialsError("Chybí hlavička X-Client-Id.") if not self.client_secret or not self.client_secret.strip(): raise CredentialsError("Chybí hlavička X-Client-Secret.") @property def base_url(self) -> str: if self.environment == "test": return CPL_TEST_BASE_URL return CPL_PRODUCTION_BASE_URL @property def cache_key(self) -> str: """Klíč do token cache — hash, aby se secrets nikde neobjevily v paměti navíc.""" raw = f"{self.client_id}|{self.client_secret}|{self.environment}" return hashlib.sha256(raw.encode("utf-8")).hexdigest() def get_credentials( x_client_id: str | None = Header( default=None, alias="X-Client-Id", description="PPL CPL ClientId (secret, přiděluje PPL).", ), x_client_secret: str | None = Header( default=None, alias="X-Client-Secret", description="PPL CPL ClientSecret (secret, přiděluje PPL).", ), x_environment: str | None = Header( default=None, alias="X-Environment", description=( "Cílové prostředí PPL: `production` nebo `test`. " f"Bez hlavičky se použije `{CPL_DEFAULT_ENVIRONMENT}`." ), ), accept_language: str | None = Header( default=None, alias="Accept-Language", description="Volitelný jazyk odpovědí PPL (např. `cs-CZ`). Předává se dál.", ), ) -> Credentials: environment = (x_environment or CPL_DEFAULT_ENVIRONMENT).strip().lower() if environment not in _ENVIRONMENTS: raise BadRequestError( f"Neplatná hodnota X-Environment '{environment}'. Povolené: production, test." ) return Credentials( client_id=x_client_id, client_secret=x_client_secret, environment=environment, accept_language=accept_language, )