diff --git a/messages/en-US.json b/messages/en-US.json index bfb07ef74..1cfee968e 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -307,6 +307,8 @@ "privateResourceTypeCidrDescription": "Expose a CIDR range on the site network to connected clients", "privateResourceTypeHttpDescription": "Access an HTTP or HTTPS service through a domain", "privateResourceTypeSshDescription": "Access an SSH server from connected clients", + "privateResourceTypeGatewayDescription": "Send all internet traffic to exit through the site network.", + "resourceTypeGatewayDescription": "Send all internet traffic to exit through the site network.", "resourceDomainDescription": "The resource will be served at this fully qualified domain name.", "resourceHTTPSSettings": "HTTPS Settings", "resourceHTTPSSettingsDescription": "Configure how the resource will be accessed over HTTPS", @@ -2927,6 +2929,7 @@ "editInternalResourceDialogModePort": "Port", "editInternalResourceDialogModeHost": "Host", "editInternalResourceDialogModeCidr": "CIDR", + "editInternalResourceDialogModeGateway": "Exit Node", "editInternalResourceDialogModeHttp": "HTTP", "editInternalResourceDialogModeHttps": "HTTPS", "editInternalResourceDialogModeInference": "AI Gateway", @@ -2938,6 +2941,7 @@ "editInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.", "editInternalResourceDialogDestinationIPDescription": "The IP or hostname address of the resource on the site's network.", "editInternalResourceDialogDestinationCidrDescription": "The CIDR range of the resource on the site's network.", + "editInternalResourceDialogDestinationGatewayDescription": "The sites to uses as exit nodes for this resource", "editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAliasDescription": "An optional internal DNS alias for this resource.", "createInternalResourceDialogNoSitesAvailable": "No Sites Available", @@ -2952,6 +2956,7 @@ "privateResourceNetworkAccessDescription": "Control TCP/UDP port access and whether ICMP ping is allowed for this resource.", "hostSettings": "Host", "cidrSettings": "CIDR", + "gatewaySettings": "Exit Node", "createInternalResourceDialogResourceProperties": "Resource Properties", "createInternalResourceDialogName": "Name", "createInternalResourceDialogSite": "Site", @@ -2990,6 +2995,7 @@ "createInternalResourceDialogModeHttps": "HTTPS", "createInternalResourceDialogModeSsh": "SSH", "createInternalResourceDialogModeInference": "AI Gateway", + "createInternalResourceDialogModeGateway": "Exit Node", "scheme": "Scheme", "createInternalResourceDialogScheme": "Scheme", "createInternalResourceDialogEnableSsl": "Enable TLS", diff --git a/server/db/pg/schema/schema.ts b/server/db/pg/schema/schema.ts index 63ea3b23a..a4210ab8e 100644 --- a/server/db/pg/schema/schema.ts +++ b/server/db/pg/schema/schema.ts @@ -493,7 +493,7 @@ export const siteResources = pgTable( ssl: boolean("ssl").notNull().default(false), mode: varchar("mode") .$type<"host" | "cidr" | "http" | "ssh" | "inference" | "gateway">() - .notNull(), // "host" | "cidr" | "http" + .notNull(), scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode proxyPort: integer("proxyPort"), // only for port mode destinationPort: integer("destinationPort"), // only for port mode diff --git a/server/db/sqlite/schema/schema.ts b/server/db/sqlite/schema/schema.ts index cdd06ea20..a2c2339aa 100644 --- a/server/db/sqlite/schema/schema.ts +++ b/server/db/sqlite/schema/schema.ts @@ -514,7 +514,7 @@ export const siteResources = sqliteTable("siteResources", { ssl: integer("ssl", { mode: "boolean" }).notNull().default(false), mode: text("mode") .$type<"host" | "cidr" | "http" | "ssh" | "inference" | "gateway">() - .notNull(), // "host" | "cidr" | "http" + .notNull(), scheme: text("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode proxyPort: integer("proxyPort"), // only for port mode destinationPort: integer("destinationPort"), // only for port mode diff --git a/src/components/PrivateResourceInfoBox.tsx b/src/components/PrivateResourceInfoBox.tsx index 48f7fdd06..bec193bae 100644 --- a/src/components/PrivateResourceInfoBox.tsx +++ b/src/components/PrivateResourceInfoBox.tsx @@ -108,15 +108,19 @@ export function PrivateResourceInfoSections({ tcpPortRangeString: siteResource.tcpPortRangeString ?? "*", udpPortRangeString: siteResource.udpPortRangeString ?? "*" }); + const showAccess = siteResource.mode !== "gateway"; const showAlias = siteResource.mode !== "cidr" && siteResource.mode !== "http" && - siteResource.mode !== "inference"; + siteResource.mode !== "inference" && + siteResource.mode !== "gateway"; const showDestination = !( siteResource.mode === "ssh" && siteResource.authDaemonMode === "native" - ) && siteResource.mode !== "inference"; + ) && + siteResource.mode !== "inference" && + siteResource.mode !== "gateway"; const showCertificate = !!( (siteResource.mode === "http" || siteResource.mode === "inference") && siteResource.ssl && @@ -129,7 +133,8 @@ export function PrivateResourceInfoSections({ siteResource.mode !== "inference"; const numSections = - 2 + + 1 + + (showAccess ? 1 : 0) + (showDestination ? 1 : 0) + (showAlias ? 1 : 0) + (showCertificate ? 1 : 0) + @@ -144,17 +149,19 @@ export function PrivateResourceInfoSections({ - - {t("access")} - - - - + {showAccess ? ( + + {t("access")} + + + + + ) : null} {showDestination ? ( diff --git a/src/lib/privateResourceForm.ts b/src/lib/privateResourceForm.ts index ad678bb73..4b8464540 100644 --- a/src/lib/privateResourceForm.ts +++ b/src/lib/privateResourceForm.ts @@ -421,7 +421,14 @@ export function createCreateFormSchema(t: TranslateFn) { .min(1, t("createInternalResourceDialogNameRequired")) .max(255, t("createInternalResourceDialogNameMaxLength")), siteIds: z.array(z.number().int().positive()).optional(), - mode: z.enum(["host", "cidr", "http", "ssh", "inference"]), + mode: z.enum([ + "host", + "cidr", + "http", + "ssh", + "inference", + "gateway" + ]), destination: z.string().nullish(), alias: z.string().nullish(), destinationPort: z @@ -468,6 +475,7 @@ export function createCreateFormSchema(t: TranslateFn) { if ( data.mode !== "ssh" && data.mode !== "inference" && + data.mode !== "gateway" && (!trimmedDestination || trimmedDestination.length < 1) ) { ctx.addIssue({