add auth support

This commit is contained in:
Mateusz Gruszczyński
2026-05-06 08:38:07 +02:00
parent aea3c92830
commit dc1cac4e6f
20 changed files with 1185 additions and 220 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import os
import secrets
from pathlib import Path
from dotenv import load_dotenv
@@ -15,7 +16,8 @@ def _env_bool(name: str, default: bool = False) -> bool:
return value.strip().lower() in {"1", "true", "yes", "on"}
SECRET_KEY = os.getenv("PYTORRENT_SECRET_KEY", "dev-change-me")
_SECRET_KEY_ENV = os.getenv("PYTORRENT_SECRET_KEY")
SECRET_KEY = _SECRET_KEY_ENV or "dev-change-me"
DB_PATH = Path(os.getenv("PYTORRENT_DB_PATH", str(BASE_DIR / "data" / "pytorrent.sqlite3")))
if not DB_PATH.is_absolute():
DB_PATH = BASE_DIR / DB_PATH
@@ -23,6 +25,18 @@ if not DB_PATH.is_absolute():
HOST = os.getenv("PYTORRENT_HOST", "0.0.0.0")
PORT = int(os.getenv("PYTORRENT_PORT", "8090"))
DEBUG = _env_bool("PYTORRENT_DEBUG", False)
# Note: Optional authentication remains disabled unless explicitly enabled in .env.
AUTH_ENABLE = _env_bool("PYTORRENT_AUTH_ENABLE", False)
if AUTH_ENABLE and (not _SECRET_KEY_ENV or SECRET_KEY == "dev-change-me"):
# Note: Auth mode cannot use Flask's development secret; persist a local random session key instead.
_secret_file = BASE_DIR / "data" / ".session_secret"
_secret_file.parent.mkdir(parents=True, exist_ok=True)
if _secret_file.exists():
SECRET_KEY = _secret_file.read_text(encoding="utf-8").strip()
if not SECRET_KEY or SECRET_KEY == "dev-change-me":
SECRET_KEY = secrets.token_urlsafe(48)
_secret_file.write_text(SECRET_KEY, encoding="utf-8")
SESSION_COOKIE_SECURE = _env_bool("PYTORRENT_SESSION_COOKIE_SECURE", False)
# Note: Keep Werkzeug opt-in only for explicit local/dev use, never by default in services.
ALLOW_UNSAFE_WERKZEUG = _env_bool("PYTORRENT_ALLOW_UNSAFE_WERKZEUG", DEBUG)
POLL_INTERVAL = float(os.getenv("PYTORRENT_POLL_INTERVAL", "1.0"))
@@ -39,6 +53,17 @@ def _env_int(name: str, default: int, minimum: int = 0) -> int:
return default
PROXY_FIX_ENABLE = _env_bool("PYTORRENT_PROXY_FIX_ENABLE", False)
PROXY_FIX_X_FOR = _env_int("PYTORRENT_PROXY_FIX_X_FOR", 1, 0)
PROXY_FIX_X_PROTO = _env_int("PYTORRENT_PROXY_FIX_X_PROTO", 1, 0)
PROXY_FIX_X_HOST = _env_int("PYTORRENT_PROXY_FIX_X_HOST", 1, 0)
PROXY_FIX_X_PORT = _env_int("PYTORRENT_PROXY_FIX_X_PORT", 1, 0)
PROXY_FIX_X_PREFIX = _env_int("PYTORRENT_PROXY_FIX_X_PREFIX", 1, 0)
_SOCKETIO_CORS = os.getenv("PYTORRENT_SOCKETIO_CORS_ALLOWED_ORIGINS", "").strip()
SOCKETIO_CORS_ALLOWED_ORIGINS = None if not _SOCKETIO_CORS else [item.strip() for item in _SOCKETIO_CORS.split(",") if item.strip()]
TRAFFIC_HISTORY_RETENTION_DAYS = _env_int("PYTORRENT_TRAFFIC_HISTORY_RETENTION_DAYS", 90, 1)
JOBS_RETENTION_DAYS = _env_int("PYTORRENT_JOBS_RETENTION_DAYS", 30, 1)
SMART_QUEUE_HISTORY_RETENTION_DAYS = _env_int("PYTORRENT_SMART_QUEUE_HISTORY_RETENTION_DAYS", 30, 1)