basic ui working

This commit is contained in:
miloschwartz
2026-04-09 22:24:39 -04:00
parent 510931e7d6
commit 79751c208d
12 changed files with 365 additions and 167 deletions

View File

@@ -16,6 +16,20 @@ import { Config } from "./types";
import logger from "@server/logger";
import { getNextAvailableAliasAddress } from "../ip";
function siteResourceModeForDb(mode: "host" | "cidr" | "http" | "https"): {
mode: "host" | "cidr" | "http";
ssl: boolean;
scheme: "http" | "https" | null;
} {
if (mode === "https") {
return { mode: "http", ssl: true, scheme: "https" };
}
if (mode === "http") {
return { mode: "http", ssl: false, scheme: "http" };
}
return { mode, ssl: false, scheme: null };
}
export type ClientResourcesResults = {
newSiteResource: SiteResource;
oldSiteResource?: SiteResource;
@@ -76,13 +90,16 @@ export async function updateClientResources(
}
if (existingResource) {
const mappedMode = siteResourceModeForDb(resourceData.mode);
// Update existing resource
const [updatedResource] = await trx
.update(siteResources)
.set({
name: resourceData.name || resourceNiceId,
siteId: site.siteId,
mode: resourceData.mode,
mode: mappedMode.mode,
ssl: mappedMode.ssl,
scheme: mappedMode.scheme,
destination: resourceData.destination,
destinationPort: resourceData["destination-port"],
enabled: true, // hardcoded for now
@@ -208,9 +225,9 @@ export async function updateClientResources(
oldSiteResource: existingResource
});
} else {
const mappedMode = siteResourceModeForDb(resourceData.mode);
let aliasAddress: string | null = null;
if (resourceData.mode == "host") {
// we can only have an alias on a host
if (mappedMode.mode === "host" || mappedMode.mode === "http") {
aliasAddress = await getNextAvailableAliasAddress(orgId);
}
@@ -222,7 +239,9 @@ export async function updateClientResources(
siteId: site.siteId,
niceId: resourceNiceId,
name: resourceData.name || resourceNiceId,
mode: resourceData.mode,
mode: mappedMode.mode,
ssl: mappedMode.ssl,
scheme: mappedMode.scheme,
destination: resourceData.destination,
destinationPort: resourceData["destination-port"],
enabled: true, // hardcoded for now

View File

@@ -652,7 +652,7 @@ export function generateSubnetProxyTargetV2(
disableIcmp,
resourceId: siteResource.siteResourceId
};
} else if (siteResource.mode == "http" || siteResource.mode == "https") {
} else if (siteResource.mode == "http") {
let destination = siteResource.destination;
// check if this is a valid ip
const ipSchema = z.union([z.ipv4(), z.ipv6()]);
@@ -667,10 +667,11 @@ export function generateSubnetProxyTargetV2(
!siteResource.scheme
) {
logger.debug(
`Site resource ${siteResource.siteResourceId} is in HTTP/HTTPS mode but is missing alias or alias address or destinationPort, skipping alias target generation.`
`Site resource ${siteResource.siteResourceId} is in HTTP mode but is missing alias or alias address or destinationPort or scheme, skipping alias target generation.`
);
return;
}
const publicProtocol = siteResource.ssl ? "https" : "http";
// also push a match for the alias address
target = {
sourcePrefixes: [],
@@ -679,14 +680,14 @@ export function generateSubnetProxyTargetV2(
portRange,
disableIcmp,
resourceId: siteResource.siteResourceId,
protocol: siteResource.mode, // will be either http or https,
protocol: publicProtocol,
httpTargets: [
{
destAddr: siteResource.destination,
destPort: siteResource.destinationPort,
scheme: siteResource.scheme
}
],
]
// tlsCert: "",
// tlsKey: ""
};

View File

@@ -267,7 +267,7 @@ export async function getTraefikConfig(
});
});
// Query siteResources in http/https mode that have aliases - needed for cert generation
// Query siteResources in HTTP mode with SSL enabled and aliases — cert generation / HTTPS edge
const siteResourcesWithAliases = await db
.select({
siteResourceId: siteResources.siteResourceId,
@@ -280,7 +280,8 @@ export async function getTraefikConfig(
and(
eq(siteResources.enabled, true),
isNotNull(siteResources.alias),
inArray(siteResources.mode, ["http", "https"]),
eq(siteResources.mode, "http"),
eq(siteResources.ssl, true),
or(
eq(sites.exitNodeId, exitNodeId),
and(
@@ -900,7 +901,7 @@ export async function getTraefikConfig(
}
}
// Add Traefik routes for siteResource aliases in http/https mode so that
// Add Traefik routes for siteResource aliases (HTTP mode + SSL) so that
// Traefik generates TLS certificates for those domains even when no
// matching resource exists yet.
if (siteResourcesWithAliases.length > 0) {

View File

@@ -111,6 +111,21 @@ const createSiteResourceSchema = z
{
message: "Destination must be a valid CIDR notation for cidr mode"
}
)
.refine(
(data) => {
if (data.mode !== "http") return true;
return (
data.scheme !== undefined &&
data.destinationPort !== undefined &&
data.destinationPort >= 1 &&
data.destinationPort <= 65535
);
},
{
message:
"HTTP mode requires scheme (http or https) and a valid destination port"
}
);
export type CreateSiteResourceBody = z.infer<typeof createSiteResourceSchema>;

View File

@@ -41,12 +41,12 @@ const listAllSiteResourcesByOrgQuerySchema = z.object({
}),
query: z.string().optional(),
mode: z
.enum(["host", "cidr", "http", "https"])
.enum(["host", "cidr", "http"])
.optional()
.catch(undefined)
.openapi({
type: "string",
enum: ["host", "cidr", "http", "https"],
enum: ["host", "cidr", "http"],
description: "Filter site resources by mode"
}),
sort_by: z
@@ -88,6 +88,7 @@ function querySiteResourcesBase() {
niceId: siteResources.niceId,
name: siteResources.name,
mode: siteResources.mode,
ssl: siteResources.ssl,
scheme: siteResources.scheme,
proxyPort: siteResources.proxyPort,
destinationPort: siteResources.destinationPort,
@@ -193,7 +194,9 @@ export async function listAllSiteResourcesByOrg(
const baseQuery = querySiteResourcesBase().where(and(...conditions));
const countQuery = db.$count(
querySiteResourcesBase().where(and(...conditions)).as("filtered_site_resources")
querySiteResourcesBase()
.where(and(...conditions))
.as("filtered_site_resources")
);
const [siteResourcesList, totalCount] = await Promise.all([

View File

@@ -125,6 +125,23 @@ const updateSiteResourceSchema = z
{
message: "Destination must be a valid CIDR notation for cidr mode"
}
)
.refine(
(data) => {
if (data.mode !== "http") return true;
return (
data.scheme !== undefined &&
data.scheme !== null &&
data.destinationPort !== undefined &&
data.destinationPort !== null &&
data.destinationPort >= 1 &&
data.destinationPort <= 65535
);
},
{
message:
"HTTP mode requires scheme (http or https) and a valid destination port"
}
);
export type UpdateSiteResourceBody = z.infer<typeof updateSiteResourceSchema>;