Per-username lockout (5 failed TOTP attempts / 5 min) stops account-targeted brute force regardless of source IP. Player.totp_secret is now Fernet- encrypted (ENCRYPTION_KEY env, db/crypto.py) instead of stored in plaintext, and auth_token is stored as a SHA-256 hash rather than the raw session token. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
57 lines
1.7 KiB
YAML
57 lines
1.7 KiB
YAML
services:
|
|
db:
|
|
image: postgres:18-alpine
|
|
environment:
|
|
POSTGRES_USER: bridzik
|
|
POSTGRES_PASSWORD: bridzik
|
|
POSTGRES_DB: bridzik
|
|
ports:
|
|
- "5432:5432"
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U bridzik -d bridzik"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
backend:
|
|
build: .
|
|
environment:
|
|
# Async SQLAlchemy URL -> the Postgres service above (asyncpg driver).
|
|
DATABASE_URL: postgresql+asyncpg://bridzik:bridzik@db:5432/bridzik
|
|
# Shared secret for the self-hosted /api/admin/* stats endpoints.
|
|
ADMIN_TOKEN: tajneheslo
|
|
# Dev-only Fernet key encrypting Player.totp_secret -- fine to hardcode
|
|
# here since the dev DB is disposable (docker-compose down -v).
|
|
ENCRYPTION_KEY: FAMD5i_Pc-Ursu_Bi49ZYMN2ehhfBkjjehxTOFvNrBU=
|
|
# Optional: IP -> country for /api/track. Drop a .mmdb file (GeoLite2 or
|
|
# a DB-IP/IP2Location Lite equivalent) at ./geoip/ -- it's already inside
|
|
# the ./:/app bind mount below, no extra volume entry needed. Missing
|
|
# file -> country is just recorded as "" (see api/stats.py:_country_for_ip).
|
|
GEOIP_DB_PATH: /app/geoip/GeoLite2-Country.mmdb
|
|
ports:
|
|
- "5000:5000"
|
|
volumes:
|
|
- ./:/app
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
frontend:
|
|
image: node:22-alpine
|
|
working_dir: /app
|
|
environment:
|
|
# Inside the compose network the backend is reachable as `backend`.
|
|
VITE_BACKEND_URL: http://backend:5000
|
|
volumes:
|
|
- ./frontend:/app
|
|
ports:
|
|
- "5173:5173"
|
|
command: sh -c "npm install && npm run dev -- --host"
|
|
depends_on:
|
|
- backend
|
|
|
|
volumes:
|
|
pgdata:
|