81 lines
2.7 KiB
Python
81 lines
2.7 KiB
Python
"""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,
|
|
)
|