first
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""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,
|
||||
)
|
||||
Reference in New Issue
Block a user