fix: auth review fixes — token revocation, WS auth, seeding, and hardening
Refresh/logout and token robustness - drop the post-rotation refresh_tokens row delete in auth_refresh so logout blacklists the current (rotated) refresh token; remove the dead _clear_refresh_token_after_rotation helper and clear_active_refresh_token - reject non-object JWT payloads in _extract_unverified_sub so crafted Authorization headers return 401 instead of crashing with 500 SQLite user store - make builtin-admin seeding idempotent: on a concurrent first start the losing seeder re-checks, finds the winner, and returns instead of raising IntegrityError - per-thread sqlite connections + busy_timeout so Flask worker threads don't hit cross-thread ProgrammingError / SQLITE_BUSY - add LogsDirectory + /var/log/vacuum-wall to ReadWritePaths in both systemd units so the fallback admin password actually lands on disk Frontend - skip apiFetch 401-recovery for public auth endpoints so a failed login no longer logs out a valid session - add /passkeys to the nav (passkey registration was unreachable); remove the dead checkWebAuthnCapable export - drop the CSP-blocked inline WS-URL script and the __WS_URL_PLACEHOLDER__ plumbing; the WS URL is derived from location Daemon / WS - parse Sec-WebSocket-Protocol manually (web.Request.get_subprotocols does not exist in aiohttp 3.13); X-Auth-Token is a custom-nginx fallback only — docstring and security docs corrected Install / system - bootstrap_auth.py is now idempotent: preserves existing auth config and syncs the admin password on re-runs (new reset_password helper) - WebUI server block renders auth_basic off (the UI is JWT-protected) - install.sh chown/chmod skips .git to avoid git dubious-ownership breakage - tolerate unreadable /etc/wireguard during system import Contracts / docs - create_user returns 409 on duplicate username per docs/api.md - correct docs/api.md response shapes, docs/security.md blacklist cleanup wording + one-refresh-per-user caveat, stale WS-URL references, and the .htpasswd description Tests: +7 regression tests (rotation/logout revocation, crafted-token 401, concurrent seeding); placeholder-substitution tests replaced with serve-as-is SPA root tests.
This commit is contained in:
+15
-3
@@ -206,7 +206,13 @@ Create a new user with password and per-subsystem permissions.
|
||||
| `password` | `string` | Yes | Plain-text password |
|
||||
| `permissions` | `object` | No | Per-subsystem permissions (`{ subsystem: "read" \| "rw" }`) |
|
||||
|
||||
**Response:** `data` is `null` on success.
|
||||
**Response (`data`):**
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `id` | `int` | User ID |
|
||||
| `username` | `string` | Username |
|
||||
| `permissions` | `object` | Per-subsystem permissions (`{ subsystem: "read" \| "rw" }`) |
|
||||
|
||||
Returns HTTP `409` if username already exists.
|
||||
|
||||
@@ -226,7 +232,13 @@ Update user's permissions. (To change a password, use `POST /api/auth/password`.
|
||||
|---|---|---|---|
|
||||
| `permissions` | `object` | No | New per-subsystem permissions |
|
||||
|
||||
**Response:** `data` is `null` on success.
|
||||
**Response (`data`):**
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `id` | `int` | User ID |
|
||||
| `username` | `string` | Username |
|
||||
| `permissions` | `object` | Per-subsystem permissions (`{ subsystem: "read" \| "rw" }`) |
|
||||
|
||||
Returns HTTP `404` if user not found.
|
||||
|
||||
@@ -240,7 +252,7 @@ Delete a user and all associated permissions and WebAuthn credentials (CASCADE).
|
||||
|
||||
**Auth:** `auth: "rw"` required. Cannot delete self.
|
||||
|
||||
**Response:** `data` is `null` on success.
|
||||
**Response:** `data` is `{"ok": true}` on success.
|
||||
|
||||
Returns HTTP `404` if user not found.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user