Auth: rate limiter, WebAuthn domain awareness, misc fixes

- Rate limiter tracks failures only; success resets counter
- Record failures/successes after password verification, not before
- WebAuthn rp_id/origin resolved dynamically from request domain
- Management domains auto-discovered from nginx backend config
- All WebAuthn operations validate domain against management list
- Add GET /api/auth/webauthn/capable endpoint for frontend checks
- Frontend checkWebAuthnCapable() function for domain-gated UI
- Timing side-channel fix: pre-compute dummy hash at module load
- Builtin admin seeded with random password (logged at WARNING)
- Logout handler returns consistent response shape
This commit is contained in:
2026-07-29 02:48:53 +00:00
parent 6d30f1387e
commit 48f8d0be18
11 changed files with 335 additions and 65 deletions
+11 -1
View File
@@ -397,7 +397,9 @@ async def _handle_ws(request: web.Request) -> web.Response:
)
session_header = request.headers.get("X-Session-Id")
payload = validate_token(token_param, token_type="access", session_id=session_header)
payload = validate_token(
token_param, token_type="access", session_id=session_header
)
if payload is None:
return web.json_response({"ok": False, "error": "unauthorized"}, status=401)
@@ -556,6 +558,14 @@ def main() -> None:
setup_logging()
# Startup checks
try:
from lib import webauthn as lib_webauthn
lib_webauthn.check_webauthn_config()
except Exception:
pass # ignore if webauthn module import failed
_register_routes()
app = create_app()