Refactor HTTP account system
CI / frontend (pull_request) Successful in 5m13s
CI / reuse (pull_request) Successful in 29s
CI / frontend (push) Successful in 4m15s
CI / reuse (push) Successful in 5s
CI / lint (pull_request) Successful in 2m25s
CI / test (pull_request) Successful in 9m24s
CI / lint (push) Successful in 2m23s
CI / test (push) Successful in 8m19s
CI / frontend (pull_request) Successful in 5m13s
CI / reuse (pull_request) Successful in 29s
CI / frontend (push) Successful in 4m15s
CI / reuse (push) Successful in 5s
CI / lint (pull_request) Successful in 2m25s
CI / test (pull_request) Successful in 9m24s
CI / lint (push) Successful in 2m23s
CI / test (push) Successful in 8m19s
This commit was merged in pull request #61.
This commit is contained in:
+27
-23
@@ -66,8 +66,7 @@ both:
|
||||
|------------|----------|----------|
|
||||
| `[listen.auth].tokens` | `tokens_file` | one token per line |
|
||||
| `[[remotes]].auth.token` | `token_file` | the token |
|
||||
| `[frontends.http.auth].rx_passphrase` | `rx_passphrase_file` | the passphrase |
|
||||
| `[frontends.http.auth].control_passphrase` | `control_passphrase_file` | the passphrase |
|
||||
| `[frontends.http.auth].bootstrap_admin_password` | `bootstrap_admin_password_file` | the initial administrator password |
|
||||
| `[frontends.http_json.auth].tokens` | `tokens_file` | one token per line |
|
||||
|
||||
Blank lines and `#` comments are ignored in the list files. A config that holds
|
||||
@@ -350,17 +349,17 @@ A name in any of those maps that no remote answers to is a config error.
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `enabled` | bool | `false` | Require a passphrase |
|
||||
| `rx_passphrase` | string | — | Passphrase granting receive-only access |
|
||||
| `rx_passphrase_file` | string | — | Read it from this file instead |
|
||||
| `control_passphrase` | string | — | Passphrase granting full control |
|
||||
| `control_passphrase_file` | string | — | Read it from this file instead |
|
||||
| `tx_access_control_enabled` | bool | `true` | Hide TX from unauthenticated users |
|
||||
| `enabled` | bool | `false` | Enable the user/password ACL |
|
||||
| `users_file` | string | `"trx-http-users.json"` | Persistent managed user database |
|
||||
| `bootstrap_admin_username` | string | — | First administrator, used only if the database is absent |
|
||||
| `bootstrap_admin_password` | string | — | First administrator password |
|
||||
| `bootstrap_admin_password_file` | string | — | Read the bootstrap password from this file instead |
|
||||
| `session_ttl_min` | u64 | `480` | Session lifetime |
|
||||
| `cookie_secure` | bool | `false` | Set Secure on the session cookie (needs HTTPS) |
|
||||
| `cookie_same_site` | string | `"Lax"` | `Strict`, `Lax`, or `None` |
|
||||
|
||||
With `enabled = true`, at least one passphrase must be set.
|
||||
When enabling ACL for the first time, configure both bootstrap fields. After
|
||||
the database exists, remove the bootstrap credentials from configuration.
|
||||
|
||||
#### `[frontends.rigctl]`
|
||||
|
||||
@@ -578,7 +577,7 @@ The link button in the top bar copies the current link to the clipboard. The
|
||||
address bar itself is updated as you tune, using `replaceState`, so sweeping
|
||||
the dial does not fill the browser's history.
|
||||
|
||||
Applying a link changes the radio, so it needs the `control` role; an `rx`
|
||||
Applying a link changes the radio, so it needs the `admin` role; a `user`
|
||||
session opens the page and says the link was not applied. Links describe the
|
||||
rig's own dial — while a tab is listening to a virtual channel the address is
|
||||
left as it was, rather than publishing a frequency the rig is not on.
|
||||
@@ -587,53 +586,58 @@ left as it was, rather than publishing a frequency the rig is not on.
|
||||
|
||||
## Authentication
|
||||
|
||||
The HTTP frontend supports optional passphrase-based authentication with two
|
||||
The HTTP frontend supports an optional user/password ACL with multiple accounts and two
|
||||
roles:
|
||||
|
||||
- **rx** — read-only access (monitoring, audio, decode streams)
|
||||
- **control** — full access (frequency, mode, PTT, and all settings)
|
||||
- **user** — read-only access (monitoring, audio, decode streams)
|
||||
- **admin** — full radio control, settings, and user management
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[frontends.http.auth]
|
||||
enabled = false
|
||||
rx_passphrase = "rx-only-passphrase"
|
||||
control_passphrase = "full-control-passphrase"
|
||||
tx_access_control_enabled = true
|
||||
users_file = "trx-http-users.json"
|
||||
bootstrap_admin_username = "admin"
|
||||
bootstrap_admin_password = "change-this-password"
|
||||
session_ttl_min = 480
|
||||
cookie_secure = false # true if served via HTTPS
|
||||
cookie_same_site = "Lax" # Strict|Lax|None
|
||||
```
|
||||
|
||||
When `enabled = false` (the default), all auth is bypassed and the UI behaves
|
||||
as before. When enabled, at least one passphrase must be set.
|
||||
as before. When enabling it for the first time, bootstrap credentials create
|
||||
the initial administrator and the Argon2id-hashed user database.
|
||||
|
||||
### Behaviour
|
||||
|
||||
- On login, the server issues an `HttpOnly` session cookie.
|
||||
- Sessions are in-memory; a server restart invalidates all sessions.
|
||||
- Rate limiting is applied per IP to mitigate brute-force attempts.
|
||||
- When `tx_access_control_enabled = true`, TX/PTT controls are hidden and
|
||||
rejected for unauthenticated or `rx`-role users.
|
||||
- User records persist in `users_file`; passwords are stored as salted Argon2id hashes.
|
||||
- `user` sessions cannot call control routes. There is no guest-access mode.
|
||||
- Administrators can add/remove users and change roles/passwords in Settings.
|
||||
- Removing an account or changing its password/role revokes its sessions.
|
||||
|
||||
### Routes
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/auth/login` | POST | Submit `{ "passphrase": "..." }` |
|
||||
| `/auth/login` | POST | Submit `{ "username": "...", "password": "..." }` |
|
||||
| `/auth/logout` | POST | Clear session |
|
||||
| `/auth/session` | GET | Check current session/role |
|
||||
| `/auth/users` | GET/POST | List or add users (admin only) |
|
||||
| `/auth/users/{username}` | PATCH/DELETE | Change password/role or remove user (admin only) |
|
||||
|
||||
Protected routes require at least `rx` role. Control routes (set frequency,
|
||||
mode, PTT, etc.) require `control` role.
|
||||
Protected routes require at least `user` role. Control routes (set frequency,
|
||||
mode, PTT, etc.) require `admin` role.
|
||||
|
||||
### Frontend Flow
|
||||
|
||||
1. On load, the UI calls `/auth/session`.
|
||||
2. If unauthenticated, a login screen is shown.
|
||||
3. On successful login, the normal UI loads.
|
||||
4. `rx` users see a read-only interface; `control` users get full controls.
|
||||
4. `user` accounts see a read-only interface; admins get full controls.
|
||||
5. If a session expires mid-use, streams stop and the login screen returns.
|
||||
|
||||
### Transport Security
|
||||
|
||||
Reference in New Issue
Block a user