feat: move user management to protected config file
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user