Add service login session sync

This commit is contained in:
DCCONSTRUCTIONS 2026-06-23 19:28:47 +03:00
parent 1b58246897
commit 5b23410549
3 changed files with 36 additions and 3 deletions

View File

@ -74,6 +74,7 @@ const bimViewerService = {
url: "https://bim.nodedc.tech",
launchUrl: "https://bim.nodedc.tech",
logoutUrl: "https://bim.nodedc.tech/logout",
loginSyncUrl: "https://bim.nodedc.tech/auth/login-sync",
accentColor: "#8FE3C8",
fallbackGradient: "linear-gradient(132deg, rgba(143, 227, 200, 0.78), rgba(24, 70, 64, 0.9) 46%, #080B0F 84%)",
status: "active",
@ -2500,6 +2501,7 @@ function normalizeService(service) {
? "https://bim.nodedc.tech"
: service.launchUrl,
logoutUrl: service.logoutUrl || "https://bim.nodedc.tech/logout",
loginSyncUrl: service.loginSyncUrl || "https://bim.nodedc.tech/auth/login-sync",
authentikApplicationSlug: service.authentikApplicationSlug || "bim-viewer",
authentikGroupName: service.authentikGroupName || "nodedc:bim:access",
};
@ -3663,6 +3665,7 @@ function sanitizeServicePatch(payload, service) {
"url",
"launchUrl",
"logoutUrl",
"loginSyncUrl",
"iconUrl",
"coverImageUrl",
"coverMediaKind",

View File

@ -214,7 +214,7 @@ app.get("/auth/callback", asyncRoute(async (req, res) => {
expiresAt: tokenSet.expires_in ? Date.now() + Number(tokenSet.expires_in) * 1000 : null,
});
setNoStore(res);
res.type("html").send(renderLoginCompletePage(pendingLogin.returnTo));
res.type("html").send(renderLoginCompletePage(pendingLogin.returnTo, getFrontchannelLoginSyncUrls()));
}));
app.get("/auth/logged-out", (req, res) => {
@ -3924,6 +3924,20 @@ function getFrontchannelLogoutUrls() {
return [...new Set(urls.map(normalizeLogoutUrl).filter(Boolean))];
}
function getFrontchannelLoginSyncUrls() {
const launcherData = readLauncherData();
const services = Array.isArray(launcherData?.services) ? launcherData.services : [];
const urls = [];
for (const service of services) {
if (typeof service.loginSyncUrl === "string" && service.loginSyncUrl.trim()) {
urls.push(service.loginSyncUrl.trim());
}
}
return [...new Set(urls.map(normalizeLogoutUrl).filter(Boolean))];
}
async function notifyTaskSessionLogout(session) {
if (!session?.user || !config.internalAccessToken || !config.taskInternalLogoutUrl) {
return;
@ -4016,8 +4030,9 @@ function renderGlobalLogoutPage(frontchannelLogoutUrls, finalRedirectUrl) {
</html>`;
}
function renderLoginCompletePage(returnTo) {
function renderLoginCompletePage(returnTo, frontchannelLoginSyncUrls = []) {
const redirectUrlJson = JSON.stringify(sanitizeReturnTo(returnTo));
const loginSyncUrlsJson = JSON.stringify(frontchannelLoginSyncUrls);
return `<!doctype html>
<html lang="ru">
@ -4045,7 +4060,14 @@ function renderLoginCompletePage(returnTo) {
try {
localStorage.setItem("nodedc:platform-session-event", JSON.stringify(eventPayload));
} catch {}
window.setTimeout(() => window.location.replace(${redirectUrlJson}), 30);
const loginSyncUrls = ${loginSyncUrlsJson};
for (const loginSyncUrl of loginSyncUrls) {
fetch(loginSyncUrl, { mode: "no-cors", credentials: "include", keepalive: true }).catch(() => undefined);
const image = new Image();
image.referrerPolicy = "no-referrer";
image.src = loginSyncUrl;
}
window.setTimeout(() => window.location.replace(${redirectUrlJson}), 180);
</script>
</body>
</html>`;
@ -4134,6 +4156,13 @@ function getSessionSyncAllowedOrigins() {
void 0;
}
}
for (const loginSyncUrl of getFrontchannelLoginSyncUrls()) {
try {
origins.add(new URL(loginSyncUrl).origin);
} catch {
void 0;
}
}
return [...origins];
}

View File

@ -14,6 +14,7 @@ export interface Service {
url: string;
launchUrl?: string | null;
logoutUrl?: string | null;
loginSyncUrl?: string | null;
iconUrl?: string | null;
coverImageUrl?: string | null;
coverMediaKind?: MediaKind | null;