Smail/frontend/src/utils/navigation.mjs
smail f60d3b0880
Some checks are pending
Security Checks / security (push) Waiting to run
整理前后端与测试构建目录并完善配置和安全引导
统一 frontend、backend、test、test-log 和 out 目录,更新构建、部署及测试入口;纳入配置管理兼容与首次安全引导修复;排除本机配置、密钥和测试产物。
2026-09-05 19:19:52 +08:00

101 lines
2.6 KiB
JavaScript

const BLOCKED_REDIRECT_PATHS = ["/login", "/login-verification", "/setup"];
function decodeRedirect(value) {
let decoded = value;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
const next = decodeURIComponent(decoded);
if (next === decoded) {
break;
}
decoded = next;
} catch {
break;
}
}
return decoded;
}
function getSafeLoginRedirect(value, fallback = "/") {
if (typeof value !== "string") {
return fallback;
}
const redirect = value.trim();
if (!redirect.startsWith("/") || redirect.startsWith("//")) {
return fallback;
}
const decodedRedirect = decodeRedirect(redirect);
if (!decodedRedirect.startsWith("/") || decodedRedirect.startsWith("//") || decodedRedirect.includes("\\")) {
return fallback;
}
const decodedPath = decodedRedirect
.split(/[?#]/, 1)[0]
.replace(/\/+$/, "")
.toLowerCase() || "/";
if (BLOCKED_REDIRECT_PATHS.some((path) => decodedPath === path || decodedPath.startsWith(`${path}/`))) {
return fallback;
}
return redirect;
}
function createLoginLocation(redirect) {
return {
name: "login",
query: {
redirect: getSafeLoginRedirect(redirect)
}
};
}
function createSetupLocation(redirect) {
return {
name: "setup",
query: {
redirect: getSafeLoginRedirect(redirect)
}
};
}
function getCurrentLoginRedirect(route) {
if (route?.name === "login" || route?.name === "login-verification") {
return getSafeLoginRedirect(route?.query?.redirect);
}
return getSafeLoginRedirect(route?.fullPath);
}
function createLoginRedirectHandler(router) {
let redirectPromise = null;
return function redirectToLogin() {
const currentRoute = router.currentRoute.value;
if (currentRoute?.name === "login" || currentRoute?.name === "login-verification") {
return Promise.resolve(false);
}
if (redirectPromise) {
return redirectPromise;
}
const location = createLoginLocation(getCurrentLoginRedirect(currentRoute));
redirectPromise = Promise.resolve(router.replace(location))
.then(() => true)
.finally(() => {
redirectPromise = null;
});
return redirectPromise;
};
}
export {
createLoginLocation,
createLoginRedirectHandler,
createSetupLocation,
getCurrentLoginRedirect,
getSafeLoginRedirect
};