51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
"""
|
|
app/config.py
|
|
=============
|
|
Central configuration and the path-jail helper used by every other module.
|
|
|
|
All tuneable values can be overridden via environment variables:
|
|
|
|
MEDIA_ROOT Root directory the application may read/write (default: /media)
|
|
DB_PATH Path to the SQLite database file (default: <project>/videopress.db)
|
|
PORT TCP port Gunicorn listens on (default: 8080)
|
|
LOG_LEVEL Gunicorn log verbosity (default: info)
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Paths
|
|
# ---------------------------------------------------------------------------
|
|
|
|
PACKAGE_DIR = Path(__file__).resolve().parent # …/app/
|
|
BASE_DIR = PACKAGE_DIR.parent # …/videocompressor/
|
|
|
|
# Every file-system operation in the application is restricted to MEDIA_ROOT.
|
|
MEDIA_ROOT = Path(os.environ.get('MEDIA_ROOT', '/media')).resolve()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Path-jail helper
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def safe_path(raw: str) -> Path:
|
|
"""
|
|
Resolve *raw* to an absolute path and assert it is inside MEDIA_ROOT.
|
|
|
|
Returns the resolved Path on success.
|
|
Raises PermissionError if the path would escape MEDIA_ROOT (including
|
|
symlink traversal and ../../ attacks).
|
|
"""
|
|
try:
|
|
resolved = Path(raw).resolve()
|
|
except Exception:
|
|
raise PermissionError(f"Invalid path: {raw!r}")
|
|
|
|
root_str = str(MEDIA_ROOT)
|
|
path_str = str(resolved)
|
|
if path_str != root_str and not path_str.startswith(root_str + os.sep):
|
|
raise PermissionError(
|
|
f"Access denied: '{resolved}' is outside the allowed "
|
|
f"media root ({MEDIA_ROOT})."
|
|
)
|
|
return resolved
|