Updated backend
This commit is contained in:
@@ -134,6 +134,87 @@ API_CORS_ORIGINS = [
|
||||
if origin.strip()
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Authentication
|
||||
# ---------------------------------------------------------------------------
|
||||
# CORS above is not access control - browsers enforce it, and curl ignores it
|
||||
# entirely. These settings are what actually guards the write/compute endpoints
|
||||
# (catalog generation, ML training, uploads, chat).
|
||||
#
|
||||
# AUTH_ENABLED=false turns every guard off, restoring the old behaviour where
|
||||
# any caller could reach any endpoint. It exists so a fresh checkout still runs
|
||||
# without generating secrets first; app/infrastructure/security.py logs a
|
||||
# warning at import when it is off. Never deploy with it off.
|
||||
AUTH_ENABLED = _bool("AUTH_ENABLED", "true")
|
||||
|
||||
# Signs and verifies access tokens. Changing it invalidates every issued token,
|
||||
# which is the intended way to force everyone to sign in again. Generate with:
|
||||
# python scripts/make_auth_secrets.py
|
||||
AUTH_SECRET_KEY = (
|
||||
_require("AUTH_SECRET_KEY", feature_flag="AUTH_ENABLED")
|
||||
if AUTH_ENABLED
|
||||
else os.getenv("AUTH_SECRET_KEY", "")
|
||||
)
|
||||
|
||||
# How long an issued token stays valid. 12h by default: long enough that a
|
||||
# working day needs one sign-in, short enough that a leaked token expires.
|
||||
AUTH_TOKEN_TTL_MINUTES = int(os.getenv("AUTH_TOKEN_TTL_MINUTES", "720"))
|
||||
|
||||
# The two interactive accounts. Only PBKDF2 digests are stored - never a
|
||||
# password. `make_auth_secrets.py` prints both lines ready to paste.
|
||||
AUTH_ADMIN_USERNAME = os.getenv("AUTH_ADMIN_USERNAME", "admin")
|
||||
AUTH_ADMIN_PASSWORD_HASH = (
|
||||
_require("AUTH_ADMIN_PASSWORD_HASH", feature_flag="AUTH_ENABLED")
|
||||
if AUTH_ENABLED
|
||||
else os.getenv("AUTH_ADMIN_PASSWORD_HASH", "")
|
||||
)
|
||||
AUTH_USER_USERNAME = os.getenv("AUTH_USER_USERNAME", "user")
|
||||
AUTH_USER_PASSWORD_HASH = (
|
||||
_require("AUTH_USER_PASSWORD_HASH", feature_flag="AUTH_ENABLED")
|
||||
if AUTH_ENABLED
|
||||
else os.getenv("AUTH_USER_PASSWORD_HASH", "")
|
||||
)
|
||||
|
||||
# Failed-login throttle, applied per username+client-IP. Prevents an exposed
|
||||
# login endpoint from being a free password oracle.
|
||||
AUTH_MAX_LOGIN_ATTEMPTS = int(os.getenv("AUTH_MAX_LOGIN_ATTEMPTS", "10"))
|
||||
AUTH_LOCKOUT_SECONDS = int(os.getenv("AUTH_LOCKOUT_SECONDS", "300"))
|
||||
|
||||
|
||||
def _parse_api_keys(raw: str) -> dict:
|
||||
"""
|
||||
Parse ``API_KEYS`` - ``name:role:secret`` triples, comma-separated.
|
||||
|
||||
Keyed by secret because that is what an inbound request presents. One entry
|
||||
per consumer is the point: a shared key cannot be revoked for one caller
|
||||
without breaking all of them.
|
||||
"""
|
||||
parsed: dict = {}
|
||||
for entry in raw.split(","):
|
||||
entry = entry.strip()
|
||||
if not entry:
|
||||
continue
|
||||
parts = entry.split(":")
|
||||
if len(parts) != 3:
|
||||
raise RuntimeError(
|
||||
f"Malformed API_KEYS entry {entry!r}. Expected 'name:role:secret', "
|
||||
f"comma-separated between entries."
|
||||
)
|
||||
name, role, secret = (p.strip() for p in parts)
|
||||
if role not in {"admin", "user"}:
|
||||
raise RuntimeError(
|
||||
f"API_KEYS entry {name!r} has role {role!r}; expected 'admin' or 'user'."
|
||||
)
|
||||
if not secret:
|
||||
raise RuntimeError(f"API_KEYS entry {name!r} has an empty secret.")
|
||||
parsed[secret] = (name, role)
|
||||
return parsed
|
||||
|
||||
|
||||
# Machine consumers of api.<domain>. Empty by default - browser sessions go
|
||||
# through /api/auth/login instead, and a key that nobody needs is only risk.
|
||||
API_KEYS = _parse_api_keys(os.getenv("API_KEYS", ""))
|
||||
|
||||
# Default RAG behaviour
|
||||
RAG_DEFAULT_TOP_K = int(os.getenv("RAG_DEFAULT_TOP_K", "5"))
|
||||
RAG_MAX_TOP_K = int(os.getenv("RAG_MAX_TOP_K", "15"))
|
||||
|
||||
Reference in New Issue
Block a user