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
+14
View File
@@ -143,6 +143,20 @@ export function webauthnSupported() {
return typeof window !== 'undefined' && !!window.PublicKeyCredential;
}
/**
* Check if WebAuthn is enabled and available on the current domain.
* Calls GET /api/auth/webauthn/capable to query the server.
*
* @returns {Promise<object>} { enabled, rp_id, rp_name, origin, reason? }
*/
export async function checkWebAuthnCapable() {
const result = await apiFetch('/api/auth/webauthn/capable');
if (!result.ok) {
return { enabled: false, reason: 'Unable to check WebAuthn capability' };
}
return result.data || { enabled: false, reason: 'Server returned no data' };
}
/* ─── Base64url helpers ──────────────────────────────────────────────── */
/**