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>
18 lines
776 B
Plaintext
18 lines
776 B
Plaintext
# Realtime Socket.IO server running on ASGI (uvicorn).
|
|
python-socketio>=5.11
|
|
python-engineio>=4.9
|
|
uvicorn>=0.30
|
|
|
|
# Persistence layer (history + TOTP auth).
|
|
SQLAlchemy[asyncio]>=2.0
|
|
aiosqlite>=0.20 # dev / default DATABASE_URL
|
|
asyncpg>=0.29 # production (PostgreSQL)
|
|
pyotp>=2.9 # TOTP login
|
|
cryptography>=42 # Fernet encryption for Player.totp_secret at rest
|
|
user-agents>=2.2 # parse User-Agent for /track (self-hosted analytics)
|
|
geoip2>=4.8 # resolve IP -> country from a local .mmdb file (no external calls)
|
|
|
|
# NOTE: the legacy Flask/Jinja HTTP UI (api/routes.py, api/forms.py,
|
|
# api/templates/) is dormant and its dependencies (Flask, Flask-WTF, etc.)
|
|
# were removed during the ASGI migration. Re-add them only if that UI is revived.
|