// deno-lint-ignore-file const { startRegistration, startAuthentication } = SimpleWebAuthnBrowser; function setStatus(msg, isError = false) { const el = document.getElementById("statusMessage"); if (el) { el.textContent = msg; el.className = isError ? "error" : "success"; } } async function startWebAuthnRegistration(username, inviteCode) { setStatus(""); if (!username || !inviteCode) { setStatus("Username and Invite Code are required.", true); return; } try { // 1. Fetch challenge from API const resp = await fetch("/api/register/challenge", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username, inviteCode }), }); let data; try { data = await resp.json(); } catch { const text = await resp.text().catch(() => ""); setStatus(`Challenge request failed (${resp.status}): ${text}`, true); return; } if (!resp.ok) { setStatus(data.error || "Failed to get registration challenge", true); return; } // 2. Pass challenge to authenticator let attResp; try { attResp = await startRegistration({ optionsJSON: data.options }); } catch (error) { if (error.name === "InvalidStateError") { setStatus("Authenticator was probably already registered.", true); } else { setStatus(error.message || "Registration failed on device", true); } throw error; } // 3. Send response back to verify const verificationResp = await fetch("/api/register/verify", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username, inviteCode, response: attResp, }), }); let verificationJSON; try { verificationJSON = await verificationResp.json(); } catch { const text = await verificationResp.text().catch(() => ""); setStatus( `Verification failed (${verificationResp.status}): ${text}`, true, ); return; } if (verificationJSON.success) { setStatus("Registration successful! You can now log in."); setTimeout(() => { globalThis.location.href = "/login"; }, 2000); } else { setStatus( verificationJSON.error || "Registration verification failed", true, ); } } catch (err) { console.error(err); } } async function startWebAuthnLogin() { setStatus(""); try { // 1. Fetch challenge const resp = await fetch("/api/login/challenge", { method: "POST", }); let data; try { data = await resp.json(); } catch { const text = await resp.text().catch(() => ""); setStatus(`Login challenge failed (${resp.status}): ${text}`, true); return; } if (!resp.ok) { setStatus(data.error || "Failed to get login challenge", true); return; } // 2. Pass challenge to authenticator let asseResp; try { asseResp = await startAuthentication({ optionsJSON: data.options }); } catch (error) { setStatus(error.message || "Authentication failed on device", true); throw error; } // 3. Send response back to verify const verificationResp = await fetch("/api/login/verify", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ response: asseResp, }), }); let verificationJSON; try { verificationJSON = await verificationResp.json(); } catch { const text = await verificationResp.text().catch(() => ""); setStatus( `Login verification failed (${verificationResp.status}): ${text}`, true, ); return; } if (verificationJSON.success) { setStatus("Login successful! Redirecting..."); setTimeout(() => { globalThis.location.href = "/dashboard"; }, 1000); } else { setStatus(verificationJSON.error || "Login verification failed", true); } } catch (err) { console.error(err); } }