From 739253b2e59883fd64c1d682fb0d661dca4154af Mon Sep 17 00:00:00 2001 From: Mike Teehan Date: Tue, 28 Jul 2026 01:44:10 +0000 Subject: [PATCH] fix: WS reconnection deadlock, remove redundant try/except, fix docs - websocket.js: schedule reconnect backoff when token refresh fails, otherwise WebSocket stays dead after 3+ disconnects with failed refresh - daemon/handlers/auth.py: remove two redundant try/except ValueError: raise blocks in webauthn register/authenticate finish handlers - docs/api.md: mark permissions as optional in Create User endpoint --- daemon/handlers/auth.py | 16 +++++----------- docs/api.md | 2 +- webui/static/hoover/websocket.js | 2 ++ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/daemon/handlers/auth.py b/daemon/handlers/auth.py index 96f87a7..25e73f4 100644 --- a/daemon/handlers/auth.py +++ b/daemon/handlers/auth.py @@ -409,13 +409,10 @@ def webauthn_register_finish(_request: Any, body: Any) -> dict[str, Any]: "username, credential_response, and registration_options are required" ) - try: - cred = verify_registration( - username, credential_response, registration_options, credential_name - ) - return {"ok": True, "credential": cred} - except ValueError: - raise + cred = verify_registration( + username, credential_response, registration_options, credential_name + ) + return {"ok": True, "credential": cred} @registry.register(POST_AUTH_WEBAUTHN_AUTHENTICATE_BEGIN) @@ -458,10 +455,7 @@ def webauthn_authenticate_finish(_request: Any, body: Any) -> dict[str, Any]: if not check_webauthn_rate(username, client_ip): raise ValueError("Too many WebAuthn attempts. Please try again later.") - try: - verify_authentication(username, assertion_response, auth_options) - except ValueError: - raise + verify_authentication(username, assertion_response, auth_options) user = get_user(username) if user is None: diff --git a/docs/api.md b/docs/api.md index 6eb0000..db3f896 100644 --- a/docs/api.md +++ b/docs/api.md @@ -204,7 +204,7 @@ Create a new user with password and per-subsystem permissions. |---|---|---|---| | `username` | `string` | Yes | Username | | `password` | `string` | Yes | Plain-text password | -| `permissions` | `object` | Yes | Per-subsystem permissions (`{ subsystem: "read" \| "rw" }`) | +| `permissions` | `object` | No | Per-subsystem permissions (`{ subsystem: "read" \| "rw" }`) | **Response:** `data` is `null` on success. diff --git a/webui/static/hoover/websocket.js b/webui/static/hoover/websocket.js index fbb3f0e..10f15d6 100644 --- a/webui/static/hoover/websocket.js +++ b/webui/static/hoover/websocket.js @@ -62,6 +62,8 @@ function _wsConnect() { setTimeout(_wsConnect, 100); }).catch(() => { _wsRefreshing = false; + _wsReconnectMs = Math.min(_wsReconnectMs * 2 + 1000, 15000); + setTimeout(_wsConnect, _wsReconnectMs); }); return; }