1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt, ' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety; zakresy 0–5 i A–Z na dywiz. Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach, czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu, tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana. Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie). Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika to zero zmiany. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46 lines
1.7 KiB
Python
46 lines
1.7 KiB
Python
"""API key authentication.
|
|
|
|
Klucz przyjmowany z header `X-API-Key` lub `Authorization: Bearer <key>`.
|
|
Gdy `settings.api_keys` jest puste, auth jest wyłączony (dev mode).
|
|
|
|
Dodatkowo (anti-tamper): gdy `ALLOWED_APP_SIG_HASH` jest ustawione, każdy request
|
|
musi zawierać `X-App-Signature` z SHA256 (hex) signing certu APK. Mismatch → 403.
|
|
Re-packaging APK innym keystorem (debug → release) wykryty natychmiast.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import Header, HTTPException, status
|
|
|
|
from app.config import get_settings
|
|
|
|
|
|
def require_api_key(
|
|
x_api_key: str | None = Header(default=None, alias="X-API-Key"),
|
|
authorization: str | None = Header(default=None),
|
|
x_app_signature: str | None = Header(default=None, alias="X-App-Signature"),
|
|
) -> None:
|
|
settings = get_settings()
|
|
|
|
if settings.app_sig_check_enabled:
|
|
sig = (x_app_signature or "").strip().lower().replace(":", "")
|
|
if not sig or sig not in settings.allowed_app_sig_hashes:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="invalid or missing app signature",
|
|
)
|
|
|
|
if not settings.auth_enabled:
|
|
return # local/dev, wszystko otwarte
|
|
|
|
candidate: str | None = None
|
|
if x_api_key:
|
|
candidate = x_api_key.strip()
|
|
elif authorization and authorization.lower().startswith("bearer "):
|
|
candidate = authorization[7:].strip()
|
|
|
|
if not candidate or candidate not in settings.api_keys:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="invalid or missing API key",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|