From 3b006303a28dc5d7dbf5a3fe7d67a0a99864c18e Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Tue, 26 May 2026 20:32:41 +0300 Subject: [PATCH] Route engine launches through NODE.DC handoff --- server/dev-server.mjs | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/server/dev-server.mjs b/server/dev-server.mjs index b35d1d3..68c2526 100644 --- a/server/dev-server.mjs +++ b/server/dev-server.mjs @@ -407,6 +407,21 @@ app.get("/api/services/:serviceSlug/launch", requireSession, (req, res) => { return; } + if (isEngineServiceSlug(serviceSlug)) { + const handoffToken = createServiceHandoff("nodedc", runtimeContext.user); + const targetUrl = new URL("/auth/nodedc/handoff/", getEngineLaunchTargetUrl(app)); + const nextPath = sanitizeReturnTo(req.query.next_path || req.query.returnTo || "/"); + + targetUrl.searchParams.set("token", handoffToken); + + if (nextPath && nextPath !== "/") { + targetUrl.searchParams.set("next_path", nextPath); + } + + res.redirect(targetUrl.toString()); + return; + } + if (serviceSlug !== "task-manager") { res.redirect(app.openUrl || app.url || "/"); return; @@ -2828,6 +2843,7 @@ function getAppCatalog() { description: service.description, url: getServiceUrl(service), openUrl: getServiceUrl(service), + launchTargetUrl: getServiceLaunchTargetUrl(service), status: service.status ?? "disabled", provider: "authentik", requiredGroups, @@ -2861,6 +2877,11 @@ const engineRequiredGroups = [ "nodedc_viewer", ]; +function isEngineServiceSlug(serviceSlug) { + const slug = sanitizeServiceSlug(serviceSlug); + return slug === "nodedc" || slug === "engine" || slug === "nodedc-engine"; +} + function specialRequiredGroups(serviceOrSlug) { const slug = typeof serviceOrSlug === "string" ? serviceOrSlug : serviceOrSlug?.slug; const applicationSlug = typeof serviceOrSlug === "string" ? null : serviceOrSlug?.authentikApplicationSlug; @@ -2876,22 +2897,43 @@ function specialRequiredGroups(serviceOrSlug) { } function getServiceUrl(service) { - if (service.slug === "task-manager") { + if (service.slug === "task-manager" || isEngineServiceSlug(service.slug)) { return `/api/services/${encodeURIComponent(service.slug)}/launch`; } return service.launchUrl || service.url || "#"; } +function getServiceLaunchTargetUrl(service) { + if (isEngineServiceSlug(service?.slug)) { + return service.launchUrl || service.url || getEnginePublicBaseUrl(); + } + + return service?.launchUrl || service?.url || "#"; +} + function getTaskBaseUrl() { const taskBaseUrl = process.env.TASK_BASE_URL ?? `http://${process.env.TASK_DOMAIN ?? "task.local.nodedc"}`; return taskBaseUrl.replace(/\/$/, ""); } +function getEnginePublicBaseUrl() { + return String( + process.env.NODEDC_ENGINE_PUBLIC_URL || + process.env.NODEDC_ENGINE_BASE_URL || + process.env.ENGINE_BASE_URL || + "https://engine.nodedc.ru" + ).replace(/\/$/, ""); +} + function getEngineBaseUrl() { return String(config.engineBaseUrl || "https://engine.nodedc.ru").replace(/\/$/, ""); } +function getEngineLaunchTargetUrl(service) { + return String(service?.launchTargetUrl || getEnginePublicBaseUrl()).replace(/\/$/, ""); +} + async function requestTaskManagerInternalJson(pathname, init = {}) { if (!config.internalAccessToken) { throw new Error("NODE.DC internal access token is not configured");