feat: add auth subsystem with WebAuthn passkeys support

New modules: lib/auth, lib/auth_users, lib/db, lib/db_sqlite, lib/password,
lib/webauthn, daemon/handlers/auth, scripts/bootstrap_auth, tests/test_auth

Frontend: webui/api/auth, hoover/components/auth, pages/login, passkeys, users

Updates: daemon/iface and server, lib/common and nginx, pyproject.toml deps,
install script, server.py, app.js, and websocket/api clients
This commit is contained in:
2026-07-24 01:21:39 +00:00
parent 04417cf05c
commit 56b200d233
28 changed files with 4900 additions and 82 deletions
+33
View File
@@ -167,6 +167,39 @@ GET_LOGS_NGINX_ERROR: Endpoint = _ep("GET", "/logs/nginx/error")
GET_LOGS_DNSMASQ: Endpoint = _ep("GET", "/logs/dnsmasq")
GET_LOGS_APP: Endpoint = _ep("GET", "/logs/app")
# ---- Authentication ----
POST_AUTH_LOGIN: Endpoint = _ep("POST", "/auth/login")
POST_AUTH_LOGOUT: Endpoint = _ep("POST", "/auth/logout")
POST_AUTH_REFRESH: Endpoint = _ep("POST", "/auth/refresh")
GET_AUTH_SESSION: Endpoint = _ep("GET", "/auth/session")
POST_AUTH_PASSWORD: Endpoint = _ep("POST", "/auth/password")
# User admin
GET_AUTH_USERS: Endpoint = _ep("GET", "/auth/users")
POST_AUTH_USER_CREATE: Endpoint = _ep("POST", "/auth/users")
POST_AUTH_USER_UPDATE: Endpoint = _ep("POST", "/auth/users/<username>")
DELETE_AUTH_USER: Endpoint = _ep("DELETE", "/auth/users/<username>")
# WebAuthn
POST_AUTH_WEBAUTHN_REGISTER_BEGIN: Endpoint = _ep(
"POST", "/auth/webauthn/register-begin"
)
POST_AUTH_WEBAUTHN_REGISTER_FINISH: Endpoint = _ep(
"POST", "/auth/webauthn/register-finish"
)
POST_AUTH_WEBAUTHN_AUTHENTICATE_BEGIN: Endpoint = _ep(
"POST", "/auth/webauthn/authenticate-begin"
)
POST_AUTH_WEBAUTHN_AUTHENTICATE_FINISH: Endpoint = _ep(
"POST", "/auth/webauthn/authenticate-finish"
)
GET_AUTH_WEBAUTHN_CREDENTIALS: Endpoint = _ep("GET", "/auth/webauthn/credentials")
GET_AUTH_WEBAUTHN_CREDENTIAL_COUNTS: Endpoint = _ep(
"GET", "/auth/webauthn/credential-counts"
)
DELETE_AUTH_WEBAUTHN_CREDENTIAL: Endpoint = _ep(
"DELETE", "/auth/webauthn/creds/<credential_id>"
)
# ---- Server infra (not going through client) ----
GET_HEALTH: Endpoint = _ep("GET", "/health")
POST_STATUS_REFRESH: Endpoint = _ep("POST", "/status/refresh")