mirror of
https://github.com/xpltdco/media-rip.git
synced 2026-04-02 18:43:59 -06:00
Accept plaintext admin password — hash on startup, clear from memory
- New MEDIARIP__ADMIN__PASSWORD env var accepts plaintext password - Hashed via bcrypt on startup, plaintext cleared from memory immediately - PASSWORD_HASH still works for backward compatibility (takes precedence) - Removes the 'docker run python bcrypt' ceremony from setup flow - Updated README, docker-compose, .env.example to use plaintext
This commit is contained in:
parent
bfc7eba03f
commit
2bb97a0b30
6 changed files with 30 additions and 22 deletions
|
|
@ -7,13 +7,8 @@
|
||||||
DOMAIN=media.example.com
|
DOMAIN=media.example.com
|
||||||
|
|
||||||
# ── Admin credentials ──
|
# ── Admin credentials ──
|
||||||
# Username for the admin panel
|
|
||||||
ADMIN_USERNAME=admin
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=changeme
|
||||||
# Bcrypt password hash — generate with:
|
|
||||||
# docker run --rm python:3.12-slim python -c \
|
|
||||||
# "import bcrypt; print(bcrypt.hashpw(b'YOUR_PASSWORD', bcrypt.gensalt()).decode())"
|
|
||||||
ADMIN_PASSWORD_HASH=
|
|
||||||
|
|
||||||
# ── Session mode (optional) ──
|
# ── Session mode (optional) ──
|
||||||
# isolated = each browser has its own queue (default)
|
# isolated = each browser has its own queue (default)
|
||||||
|
|
|
||||||
23
README.md
23
README.md
|
|
@ -53,7 +53,7 @@ These are the knobs most operators actually touch — all shown commented out in
|
||||||
| `MEDIARIP__SESSION__MODE` | `isolated` | Set to `shared` for family/team use, `open` to disable sessions entirely |
|
| `MEDIARIP__SESSION__MODE` | `isolated` | Set to `shared` for family/team use, `open` to disable sessions entirely |
|
||||||
| `MEDIARIP__DOWNLOADS__MAX_CONCURRENT` | `3` | Increase for faster connections, decrease on low-spec hardware |
|
| `MEDIARIP__DOWNLOADS__MAX_CONCURRENT` | `3` | Increase for faster connections, decrease on low-spec hardware |
|
||||||
| `MEDIARIP__PURGE__MAX_AGE_MINUTES` | `1440` | Raise for longer retention, or set `PURGE__ENABLED=false` to keep forever |
|
| `MEDIARIP__PURGE__MAX_AGE_MINUTES` | `1440` | Raise for longer retention, or set `PURGE__ENABLED=false` to keep forever |
|
||||||
| `MEDIARIP__ADMIN__PASSWORD_HASH` | _(empty)_ | Pre-set to skip the first-run wizard (useful for automated deployments) |
|
| `MEDIARIP__ADMIN__PASSWORD` | _(empty)_ | Pre-set to skip the first-run wizard (useful for automated deployments) |
|
||||||
|
|
||||||
### All Settings
|
### All Settings
|
||||||
|
|
||||||
|
|
@ -76,7 +76,8 @@ These are the knobs most operators actually touch — all shown commented out in
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `MEDIARIP__ADMIN__ENABLED` | `true` | Enable admin panel |
|
| `MEDIARIP__ADMIN__ENABLED` | `true` | Enable admin panel |
|
||||||
| `MEDIARIP__ADMIN__USERNAME` | `admin` | Admin username |
|
| `MEDIARIP__ADMIN__USERNAME` | `admin` | Admin username |
|
||||||
| `MEDIARIP__ADMIN__PASSWORD_HASH` | _(empty)_ | Bcrypt hash of admin password |
|
| `MEDIARIP__ADMIN__PASSWORD` | _(empty)_ | Admin password (plaintext — hashed on startup, never stored) |
|
||||||
|
| `MEDIARIP__ADMIN__PASSWORD_HASH` | _(empty)_ | Bcrypt hash (alternative to plaintext — for advanced users) |
|
||||||
|
|
||||||
#### Purge
|
#### Purge
|
||||||
|
|
||||||
|
|
@ -115,17 +116,21 @@ These are the knobs most operators actually touch — all shown commented out in
|
||||||
|
|
||||||
Enabled by default. On first run, you'll be prompted to set a password in the browser.
|
Enabled by default. On first run, you'll be prompted to set a password in the browser.
|
||||||
|
|
||||||
To pre-configure for automated deployments (skip the wizard):
|
To pre-configure for automated deployments (skip the wizard), set the password via environment variable or `.env` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
environment:
|
||||||
|
- MEDIARIP__ADMIN__PASSWORD=your-password-here
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generate a bcrypt hash
|
# Or in .env file
|
||||||
docker run --rm python:3.12-slim python -c \
|
MEDIARIP__ADMIN__PASSWORD=your-password-here
|
||||||
"import bcrypt; print(bcrypt.hashpw(b'YOUR_PASSWORD', bcrypt.gensalt()).decode())"
|
|
||||||
|
|
||||||
# Then set in docker-compose.yml:
|
|
||||||
# MEDIARIP__ADMIN__PASSWORD_HASH=$2b$12$...your.hash...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The plaintext password is hashed on startup and cleared from memory — it's never stored or logged.
|
||||||
|
|
||||||
### Troubleshooting: YouTube 403 Errors
|
### Troubleshooting: YouTube 403 Errors
|
||||||
|
|
||||||
YouTube downloads work out of the box — yt-dlp automatically selects the right player clients. If you do hit HTTP 403 errors, it's usually one of:
|
YouTube downloads work out of the box — yt-dlp automatically selects the right player clients. If you do hit HTTP 403 errors, it's usually one of:
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,8 @@ class AdminConfig(BaseModel):
|
||||||
|
|
||||||
enabled: bool = True
|
enabled: bool = True
|
||||||
username: str = "admin"
|
username: str = "admin"
|
||||||
password_hash: str = ""
|
password: str = "" # Plaintext — hashed on startup, never stored
|
||||||
|
password_hash: str = "" # Bcrypt hash — set directly or derived from password
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,17 @@ async def lifespan(app: FastAPI):
|
||||||
config = AppConfig()
|
config = AppConfig()
|
||||||
logger.info("Config loaded from defaults + env vars (no YAML file)")
|
logger.info("Config loaded from defaults + env vars (no YAML file)")
|
||||||
|
|
||||||
|
# --- Derive password hash from plaintext if provided ---
|
||||||
|
if config.admin.password and not config.admin.password_hash:
|
||||||
|
import bcrypt
|
||||||
|
config.admin.password_hash = bcrypt.hashpw(
|
||||||
|
config.admin.password.encode("utf-8"),
|
||||||
|
bcrypt.gensalt(),
|
||||||
|
).decode("utf-8")
|
||||||
|
logger.info("Admin password hashed from plaintext config")
|
||||||
|
# Clear plaintext from memory — only the hash is needed at runtime
|
||||||
|
config.admin.password = ""
|
||||||
|
|
||||||
# --- TLS warning ---
|
# --- TLS warning ---
|
||||||
if config.admin.enabled and config.admin.password_hash:
|
if config.admin.enabled and config.admin.password_hash:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,6 @@
|
||||||
# Setup:
|
# Setup:
|
||||||
# 1. Copy .env.example to .env and fill in your values
|
# 1. Copy .env.example to .env and fill in your values
|
||||||
# 2. Run: docker compose -f docker-compose.example.yml up -d
|
# 2. Run: docker compose -f docker-compose.example.yml up -d
|
||||||
#
|
|
||||||
# Generate a bcrypt password hash:
|
|
||||||
# docker run --rm python:3.12-slim python -c \
|
|
||||||
# "import bcrypt; print(bcrypt.hashpw(b'YOUR_PASSWORD', bcrypt.gensalt()).decode())"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
media-rip:
|
media-rip:
|
||||||
|
|
@ -25,7 +21,7 @@ services:
|
||||||
# Admin panel
|
# Admin panel
|
||||||
MEDIARIP__ADMIN__ENABLED: "true"
|
MEDIARIP__ADMIN__ENABLED: "true"
|
||||||
MEDIARIP__ADMIN__USERNAME: "${ADMIN_USERNAME:-admin}"
|
MEDIARIP__ADMIN__USERNAME: "${ADMIN_USERNAME:-admin}"
|
||||||
MEDIARIP__ADMIN__PASSWORD_HASH: "${ADMIN_PASSWORD_HASH}"
|
MEDIARIP__ADMIN__PASSWORD: "${ADMIN_PASSWORD}"
|
||||||
# Session mode: isolated (default), shared, or open
|
# Session mode: isolated (default), shared, or open
|
||||||
MEDIARIP__SESSION__MODE: "${SESSION_MODE:-isolated}"
|
MEDIARIP__SESSION__MODE: "${SESSION_MODE:-isolated}"
|
||||||
expose:
|
expose:
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ services:
|
||||||
# - MEDIARIP__PURGE__MAX_AGE_MINUTES=1440
|
# - MEDIARIP__PURGE__MAX_AGE_MINUTES=1440
|
||||||
#
|
#
|
||||||
## Pre-set admin password (skip first-run wizard):
|
## Pre-set admin password (skip first-run wizard):
|
||||||
# - MEDIARIP__ADMIN__PASSWORD_HASH=$2b$12$...
|
# - MEDIARIP__ADMIN__PASSWORD=changeme
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue