diff --git a/app/crypto.py b/app/crypto.py index 8ea2b27..3a59c05 100644 --- a/app/crypto.py +++ b/app/crypto.py @@ -39,6 +39,28 @@ def reset_cache() -> None: _fernet.cache_clear() +def validate_creds_key() -> None: + """Fail-fast la startup: o cheie `creds_key` setata DAR invalida trebuie sa + opreasca pornirea, nu sa explodeze abia la primul POST /v1/prezentari (500 + brut, fara mesaj util pentru client — cazul real reprodus din ROAAUTO/VFP). + + Cheie nesetata = OK (modelul efemer, vezi _fernet). Cheie setata si invalida + (lungime/padding gresit) -> RuntimeError cu instructiunea de generare. + """ + key = get_settings().creds_key + if not key: + return + try: + Fernet(key.encode() if isinstance(key, str) else key) + except (ValueError, TypeError) as exc: + raise RuntimeError( + "AUTOPASS_CREDS_KEY este setata dar invalida (Fernet cere 32 bytes " + "url-safe base64, 44 caractere terminate in '='). Genereaza una cu:\n" + " python3 -c \"from cryptography.fernet import Fernet; " + "print(Fernet.generate_key().decode())\"" + ) from exc + + def encrypt_creds(creds: dict) -> str: """Cripteaza un dict de creds -> token Fernet (str). Compact, fara spatii.""" blob = json.dumps(creds, separators=(",", ":"), ensure_ascii=False).encode("utf-8") diff --git a/app/main.py b/app/main.py index 4068f59..dbc2ec2 100644 --- a/app/main.py +++ b/app/main.py @@ -25,6 +25,7 @@ from .api.v1.import_router import router as import_v1_router from .api.v1.integrare_router import router as integrare_v1_router from .api.v1.router import router as api_v1_router from .config import get_settings +from .crypto import validate_creds_key from .db import get_connection, init_db, queue_depth, read_heartbeat from .security import install_log_redaction from .web.routes import router as web_router @@ -37,6 +38,9 @@ from .web.session import AdminRequired, LoginRequired @asynccontextmanager async def lifespan(app: FastAPI): install_log_redaction() + # Fail-fast: o cheie Fernet setata dar invalida opreste pornirea cu mesaj clar, + # in loc de 500 brut la primul POST /v1/prezentari (cazul reprodus din VFP). + validate_creds_key() init_db() yield