started with 2fa support

This commit is contained in:
2026-06-09 22:50:29 +02:00
parent 5485fd135d
commit ea8ea45c4c
10 changed files with 757 additions and 142 deletions

View File

@@ -2,22 +2,63 @@
document.addEventListener("DOMContentLoaded", () => {
const form = document.getElementById("login-form");
const errorBox = document.getElementById("error");
const usernameInput = document.getElementById("username");
const passwordInput = document.getElementById("password");
const twoFactorInput = document.getElementById("two-factor-code");
const twoFactorGroup = document.getElementById("two-factor-group");
const submitButton = document.getElementById("login-submit");
let pendingTwoFactorToken = null;
if (!form) return;
function showError(message) {
errorBox.textContent = message || "Login failed.";
errorBox.style.display = "block";
}
function storeTokens(data) {
localStorage.setItem("access_token", data.access_token);
localStorage.setItem("refresh_token", data.refresh_token);
}
function switchToTwoFactorMode(token) {
pendingTwoFactorToken = token;
usernameInput.disabled = true;
passwordInput.disabled = true;
twoFactorGroup.style.display = "block";
twoFactorInput.required = true;
twoFactorInput.focus();
submitButton.textContent = "Verify code";
}
form.addEventListener("submit", async (e) => {
e.preventDefault();
errorBox.style.display = "none";
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
submitButton.disabled = true;
try {
const response = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password })
});
let response;
if (pendingTwoFactorToken) {
response = await fetch("/api/login/2fa", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
two_factor_token: pendingTwoFactorToken,
code: twoFactorInput.value.trim()
})
});
} else {
response = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: usernameInput.value,
password: passwordInput.value
})
});
}
if (!response.ok) {
const text = await response.text();
@@ -26,17 +67,17 @@ document.addEventListener("DOMContentLoaded", () => {
const data = await response.json();
localStorage.setItem("access_token", data.access_token);
localStorage.setItem("refresh_token", data.refresh_token);
document.cookie = `access_token=${data.access_token}; path=/; max-age=900; SameSite=Lax; Secure`;
document.cookie = `refresh_token=${data.refresh_token}; path=/; max-age=604800; SameSite=Lax; Secure`;
if (data.requires_2fa) {
switchToTwoFactorMode(data.two_factor_token);
return;
}
storeTokens(data);
window.location.href = "/dashboard";
} catch (err) {
errorBox.textContent = err.message || "Login failed.";
errorBox.style.display = "block";
showError(err.message);
} finally {
submitButton.disabled = false;
}
});
});
});