feat: move user management to protected config file

This commit is contained in:
2026-07-28 13:46:05 +02:00
parent 2276a124b8
commit 3b54f5ecc0
6 changed files with 368 additions and 86 deletions
+54 -10
View File
@@ -43,7 +43,7 @@ If port `5000` is already occupied, start through Flask's CLI without changing f
flask --app app run --host 127.0.0.1 --port 5001
```
The app uses HTTP Basic Auth. Current users are defined in `BETA_USERS` in `app.py` with Werkzeug password hashes.
The app uses HTTP Basic Auth. Current users are defined in a local deployment file, `config/users.json`, with Werkzeug password hashes. This file is intentionally not versioned.
## Project Layout
@@ -100,23 +100,57 @@ Implemented routes:
| `/api/health` | `GET` | Basic Auth | Returns app health and version. |
| `/api/user` | `GET` | Basic Auth | Returns current authenticated user info. |
Authentication is implemented with `Flask-HTTPAuth`. The current code checks `BETA_USERS` with `werkzeug.security.check_password_hash`; plaintext passwords are not stored in the application.
Authentication is implemented with `Flask-HTTPAuth`. The current code loads the local `config/users.json` deployment file and checks password hashes with `werkzeug.security.check_password_hash`; plaintext passwords are not stored in the application.
Generate a password hash or user entry with:
## User Management
Manage users with the interactive CLI:
```bash
python scripts/manage_users.py username
python scripts/manage_users.py username --json
python3 scripts/manage_users.py
```
For non-interactive local maintenance only:
The menu supports:
```bash
python scripts/manage_users.py username --password 'new-password'
- List users
- Create user
- Change password
- Delete user
User data is stored in:
```text
config/users.json
```
`config/users.json` is local deployment data and is ignored by Git. The versioned file `config/users.example.json` documents the format only and must not contain real usernames, hashes, or passwords.
The file contains only username-to-password-hash mappings:
```json
{
"username": "<hash>"
}
```
Passwords are entered with `getpass`, are never echoed, and are never stored in plaintext. New and changed passwords use the existing RollCalc hash method:
```text
pbkdf2:sha256:600000
```
Do not commit real passwords or print them in logs.
On a server, ensure that the process running RollCalc can read `config/users.json`. A suitable deployment setup can be:
```text
owner: martin
group: www-data
mode: 640
```
The exact owner and group depend on the deployment. Do not hard-code them in the application. Before deploying or replacing a server instance, back up the productive `config/users.json` file.
Access logging is handled by `log_access()`, which reads `access_log.json`, appends a record, and writes the whole file back.
## Help and User Manual
@@ -180,6 +214,16 @@ static/recent_changes.json
Keep `docs/de/recent_changes.md` as the complete release-note source and `static/recent_changes.json` as the short 3-5 item summary for the startup dialog.
## User Manual PDF Export
Generate the current PDF version of the German user manual with:
```bash
./scripts/build_user_manual_pdf.sh
```
The script renders `docs/de/user_manual.md` to `docs/de/user_manual.pdf` with Pandoc. The Markdown file remains the leading source.
## Frontend Entry Point
The active UI is `templates/roll_calculator.html`.
@@ -373,11 +417,11 @@ Utility script that updates relative frontend fetch/register paths to Flask-styl
- There are duplicated or legacy-looking files with similar names. Before editing JavaScript under `static/`, confirm it is actually referenced by the active template.
- The documentation under `docs/` contains deployment and feature notes, but some filenames and route assumptions may not match the current app exactly.
- The Flask dev server is used for local development only. Production should use a WSGI server.
- Use `scripts/manage_users.py` to create password hashes when adding or rotating Basic Auth users.
- Use `scripts/manage_users.py` to add users, rotate passwords, or delete users.
## Known Risks and Maintenance Items
- Password hashes are currently configured in `app.py`; user configuration should eventually move to environment variables, a protected config file, or a secrets manager.
- Password hashes are currently stored in `config/users.json`; a secrets manager or protected deployment-specific config would be more robust for production.
- `access_log.json` is not safe for concurrent writes.
- `access_log.json` grows without rotation or retention limits.
- The custom `/static/<path:filename>` route is intended to protect static files, but Flask also creates a default static route unless disabled. Verify effective route behavior before relying on static-file protection.