account confirmation

This commit is contained in:
Mateusz Gruszczyński
2026-07-22 19:20:30 +02:00
parent d5ec8a28e7
commit 7c38edeef7
14 changed files with 193 additions and 17 deletions
+55 -5
View File
@@ -49,10 +49,19 @@ export function bindIdentityDialog({ dialog, onIdentity, initialMode = "login" }
switchMode.textContent = registering ? "Already registered? Log in" : "Create an account";
resetButton.hidden = resetting || registering;
backButton.hidden = !resetting;
form.autocomplete = resetting ? "off" : "on";
nickname.autocomplete = "nickname";
email.autocomplete = "username";
password.autocomplete = registering ? "new-password" : "current-password";
const loginMode = mode === "login";
form.autocomplete = loginMode ? "on" : "off";
nickname.autocomplete = "off";
nickname.dataset.bwignore = "true";
email.autocomplete = loginMode ? "username" : "off";
password.autocomplete = loginMode ? "current-password" : "off";
if (loginMode) {
email.removeAttribute("data-bwignore");
password.removeAttribute("data-bwignore");
} else {
email.dataset.bwignore = "true";
password.dataset.bwignore = "true";
}
message.textContent = "";
queueMicrotask(() => {
@@ -94,6 +103,13 @@ export function bindIdentityDialog({ dialog, onIdentity, initialMode = "login" }
const payload = { email: email.value.trim(), password: password.value };
if (mode === "register") payload.nickname = nickname.value.trim();
const session = await api(endpoint, { method: "POST", body: JSON.stringify(payload) });
if (mode === "register" && session.confirmation_required) {
message.classList.remove("error");
message.classList.add("success");
message.textContent = session.message;
password.value = "";
return;
}
setAuthSession(session);
await onIdentity(session.nickname, session);
dialog.close();
@@ -153,7 +169,19 @@ function bindLegacyIdentityDialog({ dialog, onIdentity }) {
email.disabled = false;
modeTitle.textContent = mode === "register" ? "Register nickname" : "Log in";
authSubmit.textContent = mode === "register" ? "Register and continue" : "Log in and continue";
password.autocomplete = mode === "register" ? "new-password" : "current-password";
const loginMode = mode === "login";
form.autocomplete = loginMode ? "on" : "off";
nickname.autocomplete = "off";
nickname.dataset.bwignore = "true";
email.autocomplete = loginMode ? "username" : "off";
password.autocomplete = loginMode ? "current-password" : "off";
if (loginMode) {
email.removeAttribute("data-bwignore");
password.removeAttribute("data-bwignore");
} else {
email.dataset.bwignore = "true";
password.dataset.bwignore = "true";
}
message.textContent = "";
queueMicrotask(() => (mode === "register" ? nickname : email).focus());
};
@@ -208,6 +236,13 @@ function bindLegacyIdentityDialog({ dialog, onIdentity }) {
const payload = { email: email.value.trim(), password: password.value };
if (mode === "register") payload.nickname = name;
const session = await api(endpoint, { method: "POST", body: JSON.stringify(payload) });
if (mode === "register" && session.confirmation_required) {
message.classList.remove("error");
message.classList.add("success");
message.textContent = session.message;
password.value = "";
return;
}
setAuthSession(session);
await onIdentity(session.nickname, session);
return;
@@ -250,6 +285,21 @@ export async function logoutCurrentSession() {
clearAuthSession();
}
export async function handleAccountConfirmationToken() {
const url = new URL(location.href);
const token = url.searchParams.get("confirm_token");
if (!token) return;
url.searchParams.delete("confirm_token");
history.replaceState({}, "", `${url.pathname}${url.search}${url.hash}`);
try {
const result = await api("/api/auth/confirm-account", { method: "POST", body: JSON.stringify({ token }) });
await showMessage(result.message, { title: "Account confirmed" });
} catch (error) {
await showMessage(error.message, { title: "Account confirmation failed" });
}
}
export async function handleResetToken() {
const url = new URL(location.href);
const token = url.searchParams.get("reset_token");
+2 -1
View File
@@ -1,7 +1,7 @@
import { installGlobalDiagnostics, logInfo } from "./logger.js";
installGlobalDiagnostics();
import { bindIdentityDialog, handleResetToken, logoutCurrentSession, validateCurrentSession } from "./auth-ui.js";
import { bindIdentityDialog, handleAccountConfirmationToken, handleResetToken, logoutCurrentSession, validateCurrentSession } from "./auth-ui.js";
import { getAuthToken } from "@rustpad/session";
import { api } from "@rustpad/api";
@@ -80,6 +80,7 @@ document.querySelector("#workspace-form").addEventListener("submit", async (even
}
});
handleAccountConfirmationToken();
handleResetToken();
const identityDialog = document.querySelector("#identity-dialog");