paths in mail

This commit is contained in:
Mateusz Gruszczyński
2026-07-28 10:13:41 +02:00
parent 351dd081b5
commit d38b5b0b51
6 changed files with 60 additions and 23 deletions
+50 -13
View File
@@ -1,6 +1,6 @@
import { api } from "@rustpad/api";
import * as sessionStore from "@rustpad/session";
import { askInput, showMessage } from "@rustpad/modal";
import { askConfirm, askInput, showMessage } from "@rustpad/modal";
const { getAuthToken, setAuthSession, setNickname } = sessionStore;
const clearAuthSession = sessionStore.clearAuthSession || (() => {
@@ -319,28 +319,44 @@ export async function logoutCurrentSession() {
}
export async function handleAccountConfirmationToken() {
function mailActionToken(pathPrefix, legacyQueryName) {
const url = new URL(location.href);
const prefix = `${pathPrefix}/`;
let token = null;
if (url.pathname.startsWith(prefix)) {
const encodedToken = url.pathname.slice(prefix.length).split("/", 1)[0];
try { token = decodeURIComponent(encodedToken); } catch { token = null; }
}
if (!token) token = url.searchParams.get(legacyQueryName);
return token?.trim() || null;
}
function clearMailActionUrl() {
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}`);
url.searchParams.delete("reset_token");
url.searchParams.delete("account_action_token");
history.replaceState({}, "", `/${url.search}${url.hash}`);
}
export async function handleAccountConfirmationToken() {
const token = mailActionToken("/auth/confirm", "confirm_token");
if (!token) return false;
clearMailActionUrl();
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" });
}
return true;
}
export async function handleResetToken() {
const url = new URL(location.href);
const token = url.searchParams.get("reset_token");
if (!token) return;
// Remove the token immediately. Refreshing or navigating back must not reopen the reset dialog.
url.searchParams.delete("reset_token");
history.replaceState({}, "", `${url.pathname}${url.search}${url.hash}`);
const token = mailActionToken("/auth/reset-password", "reset_token");
if (!token) return false;
clearMailActionUrl();
const password = await askInput({
title: "Set a new password",
@@ -352,11 +368,32 @@ export async function handleResetToken() {
confirmText: "Change password",
bitwardenIgnore: true,
});
if (!password) return;
if (!password) return true;
try {
await api("/api/auth/password-reset/confirm", { method: "POST", body: JSON.stringify({ token, password }) });
await showMessage("Password changed. The reset link has been used and cannot be opened again.", { title: "Password changed" });
} catch (error) {
await showMessage(error.message, { title: "Password reset failed" });
}
return true;
}
export async function handleAccountActionToken() {
const token = mailActionToken("/auth/account-action", "account_action_token");
if (!token) return false;
clearMailActionUrl();
const confirmed = await askConfirm(
"Confirm the requested account action. If you did not request it, cancel and ignore the e-mail.",
{ title: "Confirm account action", confirmText: "Confirm action", danger: true },
);
if (!confirmed) return true;
try {
const result = await api("/api/auth/account-action/confirm", { method: "POST", body: JSON.stringify({ token }) });
await showMessage(result.message, { title: "Account action confirmed" });
} catch (error) {
await showMessage(error.message, { title: "Account action failed" });
}
return true;
}