(() => { "use strict"; const form = document.getElementById("login-form"); const passwordFields = document.getElementById("password-fields"); const totpFields = document.getElementById("totp-fields"); const enrollBox = document.getElementById("enroll-box"); const recoveryBox = document.getElementById("recovery-box"); const errorBox = document.getElementById("error-box"); const submitBtn = document.getElementById("submit-btn"); let pendingToken = null; let mode = "password"; // password -> totp | enroll_start -> enroll_confirm -> done function showError(msg) { errorBox.textContent = msg; } async function postJson(url, body) { const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "same-origin", body: JSON.stringify(body), }); const data = await res.json().catch(() => ({})); if (!res.ok) { throw new Error(data.detail || "Unbekannter Fehler"); } return data; } form.addEventListener("submit", async (ev) => { ev.preventDefault(); showError(""); try { if (mode === "password") { const username = document.getElementById("username").value.trim(); const password = document.getElementById("password").value; const result = await postJson("/auth/login", { username, password }); pendingToken = result.pending_token; passwordFields.style.display = "none"; totpFields.style.display = "block"; if (!result.totp_enrolled) { mode = "enroll_start"; const enroll = await postJson("/auth/totp/enroll/start", { pending_token: pendingToken }); document.getElementById("qr-img").src = "data:image/png;base64," + enroll.qr_png_base64; enrollBox.style.display = "block"; mode = "enroll_confirm"; submitBtn.textContent = "TOTP bestaetigen & einrichten"; } else { mode = "totp"; submitBtn.textContent = "Code bestaetigen"; } return; } if (mode === "totp") { const code = document.getElementById("totp-code").value.trim(); await postJson("/auth/login/totp", { pending_token: pendingToken, code }); window.location.href = "/dashboard"; return; } if (mode === "enroll_confirm") { const code = document.getElementById("totp-code").value.trim(); const result = await postJson("/auth/totp/enroll/confirm", { pending_token: pendingToken, code }); recoveryBox.style.display = "block"; document.getElementById("recovery-codes").textContent = result.recovery_codes.join("\n"); submitBtn.textContent = "Weiter zum Dashboard"; mode = "done"; return; } if (mode === "done") { window.location.href = "/dashboard"; } } catch (err) { showError(err.message); } }); })();