media-rip/backend/app/dependencies.py
xpltd efc2ead796 M001: media.rip() v1.0 — complete application
Full-featured self-hosted yt-dlp web frontend:
- Python 3.12+ / FastAPI backend with async SQLite, SSE transport, session isolation
- Vue 3 / TypeScript / Pinia frontend with real-time progress, theme picker
- 3 built-in themes (cyberpunk/dark/light) + drop-in custom theme system
- Admin auth (bcrypt), purge system, cookie upload, file serving
- Docker multi-stage build, GitHub Actions CI/CD
- 179 backend tests, 29 frontend tests (208 total)

Slices: S01 (Foundation), S02 (SSE+Sessions), S03 (Frontend),
        S04 (Admin+Auth), S05 (Themes), S06 (Docker+CI)
2026-03-18 20:00:17 -05:00

72 lines
2.3 KiB
Python

"""Request-scoped dependencies for FastAPI routes."""
from __future__ import annotations
import logging
import secrets
import bcrypt
from fastapi import Depends, HTTPException, Request, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
logger = logging.getLogger("mediarip.admin")
_security = HTTPBasic(auto_error=False)
def get_session_id(request: Request) -> str:
"""Return the session ID set by SessionMiddleware."""
return request.state.session_id
async def require_admin(
request: Request,
credentials: HTTPBasicCredentials | None = Depends(_security),
) -> str:
"""Verify admin credentials via HTTPBasic + bcrypt.
Returns the authenticated username on success.
Raises 404 if admin is disabled, 401 if credentials are invalid.
"""
config = request.app.state.config
# If admin is not enabled, pretend the route doesn't exist
if not config.admin.enabled:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
if credentials is None:
logger.info("Admin auth: no credentials provided")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Admin authentication required",
headers={"WWW-Authenticate": "Basic"},
)
# Timing-safe username comparison
username_ok = secrets.compare_digest(
credentials.username.encode("utf-8"),
config.admin.username.encode("utf-8"),
)
# bcrypt password check — only if we have a hash configured
password_ok = False
if config.admin.password_hash:
try:
password_ok = bcrypt.checkpw(
credentials.password.encode("utf-8"),
config.admin.password_hash.encode("utf-8"),
)
except (ValueError, TypeError):
# Invalid hash format
password_ok = False
if not (username_ok and password_ok):
logger.info("Admin auth: failed login attempt for user '%s'", credentials.username)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid admin credentials",
headers={"WWW-Authenticate": "Basic"},
)
logger.debug("Admin auth: successful login for user '%s'", credentials.username)
return credentials.username