From f4854a3a744b963f529bce1933f960d5ee3c54bd Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Tue, 30 Jun 2026 21:54:27 -0400 Subject: [PATCH] include exit node endpoint in tcp/udp resources --- .../routers/launcher/formatLauncherAccess.ts | 43 ++++++++++++++++--- .../launcher/launcherResourceAccess.ts | 8 +++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/server/routers/launcher/formatLauncherAccess.ts b/server/routers/launcher/formatLauncherAccess.ts index 31f625bb7..c12767ce1 100644 --- a/server/routers/launcher/formatLauncherAccess.ts +++ b/server/routers/launcher/formatLauncherAccess.ts @@ -1,3 +1,5 @@ +import { formatEndpoint, parseEndpoint } from "@server/lib/ip"; + export type SiteResourceDestinationInput = { mode: "host" | "cidr" | "http" | "ssh"; destination: string | null; @@ -40,6 +42,7 @@ export type PublicResourceAccessInput = { ssl: boolean; proxyPort: number | null; wildcard: boolean; + exitNodeEndpoint?: string | null; }; export type SiteResourceAccessInput = { @@ -59,12 +62,20 @@ export type LauncherAccessFields = { accessUrl: string | null; }; -export function formatPublicResourceAccess( - resource: PublicResourceAccessInput +function formatTcpUdpResourceAccess( + exitNodeEndpoint: string | null | undefined, + proxyPort: number | null ): LauncherAccessFields { - const browserModes = ["http", "ssh", "rdp", "vnc"]; - if (!browserModes.includes(resource.mode)) { - const port = resource.proxyPort?.toString() ?? ""; + if (proxyPort == null) { + return { + accessDisplay: "", + accessCopyValue: "", + accessUrl: null + }; + } + + if (!exitNodeEndpoint?.trim()) { + const port = proxyPort.toString(); return { accessDisplay: port, accessCopyValue: port, @@ -72,6 +83,28 @@ export function formatPublicResourceAccess( }; } + const parsed = parseEndpoint(exitNodeEndpoint); + const host = parsed?.ip ?? exitNodeEndpoint.trim(); + const access = formatEndpoint(host, proxyPort); + + return { + accessDisplay: access, + accessCopyValue: access, + accessUrl: null + }; +} + +export function formatPublicResourceAccess( + resource: PublicResourceAccessInput +): LauncherAccessFields { + const browserModes = ["http", "ssh", "rdp", "vnc"]; + if (!browserModes.includes(resource.mode)) { + return formatTcpUdpResourceAccess( + resource.exitNodeEndpoint, + resource.proxyPort + ); + } + if (!resource.fullDomain) { return { accessDisplay: "", diff --git a/server/routers/launcher/launcherResourceAccess.ts b/server/routers/launcher/launcherResourceAccess.ts index 47e3529fe..5f4a5dd29 100644 --- a/server/routers/launcher/launcherResourceAccess.ts +++ b/server/routers/launcher/launcherResourceAccess.ts @@ -1,5 +1,6 @@ import { db } from "@server/db"; import { + exitNodes, labels, launcherViews, resourceLabels, @@ -860,11 +861,13 @@ async function mapPublicResources( siteId: sites.siteId, siteName: sites.name, siteType: sites.type, - siteOnline: sites.online + siteOnline: sites.online, + exitNodeEndpoint: exitNodes.endpoint }) .from(resources) .leftJoin(targets, eq(targets.resourceId, resources.resourceId)) .leftJoin(sites, eq(targets.siteId, sites.siteId)) + .leftJoin(exitNodes, eq(sites.exitNodeId, exitNodes.exitNodeId)) .where( and( inArray(resources.resourceId, resourceIds), @@ -891,7 +894,8 @@ async function mapPublicResources( fullDomain: row.fullDomain, ssl: row.ssl, proxyPort: row.proxyPort, - wildcard: row.wildcard + wildcard: row.wildcard, + exitNodeEndpoint: row.exitNodeEndpoint }); result.push({