mirror of
https://github.com/xpltdco/media-rip.git
synced 2026-04-03 02:53:58 -06:00
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)
72 lines
2.3 KiB
Python
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
|