From 0cf385b718becb5e95b167d0f0047ad8cb29fc31 Mon Sep 17 00:00:00 2001 From: Owen Date: Sun, 12 Apr 2026 12:15:29 -0700 Subject: [PATCH] CRUD and newt mode http mostly working --- messages/en-US.json | 1 + server/lib/ip.ts | 12 +++--- .../routers/newt/handleRequestLogMessage.ts | 4 +- server/routers/badger/logRequestAudit.ts | 1 + server/routers/newt/handleGetConfigMessage.ts | 2 +- .../siteResource/createSiteResource.ts | 2 +- .../siteResource/updateSiteResource.ts | 40 +++++++++++-------- .../[orgId]/settings/logs/request/page.tsx | 3 ++ 8 files changed, 38 insertions(+), 27 deletions(-) diff --git a/messages/en-US.json b/messages/en-US.json index e4bcbd623..3a86af49b 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -2436,6 +2436,7 @@ "validPassword": "Valid Password", "validEmail": "Valid email", "validSSO": "Valid SSO", + "connectedClient": "Connected Client", "resourceBlocked": "Resource Blocked", "droppedByRule": "Dropped by Rule", "noSessions": "No Sessions", diff --git a/server/lib/ip.ts b/server/lib/ip.ts index 6f04b8170..13d35834b 100644 --- a/server/lib/ip.ts +++ b/server/lib/ip.ts @@ -662,10 +662,10 @@ export async function generateSubnetProxyTargetV2( } if ( - !siteResource.alias || !siteResource.aliasAddress || !siteResource.destinationPort || - !siteResource.scheme + !siteResource.scheme || + !siteResource.fullDomain ) { logger.debug( `Site resource ${siteResource.siteResourceId} is in HTTP mode but is missing alias or alias address or destinationPort or scheme, skipping alias target generation.` @@ -676,10 +676,10 @@ export async function generateSubnetProxyTargetV2( let tlsCert: string | undefined; let tlsKey: string | undefined; - if (siteResource.ssl && siteResource.alias) { + if (siteResource.ssl && siteResource.fullDomain) { try { const certs = await getValidCertificatesForDomains( - new Set([siteResource.alias]), + new Set([siteResource.fullDomain]), true ); if (certs.length > 0 && certs[0].certFile && certs[0].keyFile) { @@ -687,12 +687,12 @@ export async function generateSubnetProxyTargetV2( tlsKey = certs[0].keyFile; } else { logger.warn( - `No valid certificate found for SSL site resource ${siteResource.siteResourceId} with domain ${siteResource.alias}` + `No valid certificate found for SSL site resource ${siteResource.siteResourceId} with domain ${siteResource.fullDomain}` ); } } catch (err) { logger.error( - `Failed to retrieve certificate for site resource ${siteResource.siteResourceId} domain ${siteResource.alias}: ${err}` + `Failed to retrieve certificate for site resource ${siteResource.siteResourceId} domain ${siteResource.fullDomain}: ${err}` ); } } diff --git a/server/private/routers/newt/handleRequestLogMessage.ts b/server/private/routers/newt/handleRequestLogMessage.ts index c11c98950..6cbb18b72 100644 --- a/server/private/routers/newt/handleRequestLogMessage.ts +++ b/server/private/routers/newt/handleRequestLogMessage.ts @@ -144,7 +144,7 @@ export const handleRequestLogMessage: MessageHandler = async (context) => { await logRequestAudit( { action: true, - reason: 100, + reason: 108, resourceId: entry.resourceId, orgId }, @@ -163,4 +163,4 @@ export const handleRequestLogMessage: MessageHandler = async (context) => { logger.debug( `Buffered ${entries.length} request log entry/entries from newt ${newt.newtId} (site ${newt.siteId})` ); -}; \ No newline at end of file +}; diff --git a/server/routers/badger/logRequestAudit.ts b/server/routers/badger/logRequestAudit.ts index 92d01332e..db4c17939 100644 --- a/server/routers/badger/logRequestAudit.ts +++ b/server/routers/badger/logRequestAudit.ts @@ -18,6 +18,7 @@ Reasons: 105 - Valid Password 106 - Valid email 107 - Valid SSO +108 - Connected Client 201 - Resource Not Found 202 - Resource Blocked diff --git a/server/routers/newt/handleGetConfigMessage.ts b/server/routers/newt/handleGetConfigMessage.ts index 9c67f53ee..7d82e96af 100644 --- a/server/routers/newt/handleGetConfigMessage.ts +++ b/server/routers/newt/handleGetConfigMessage.ts @@ -56,7 +56,7 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { if (existingSite.lastHolePunch && now - existingSite.lastHolePunch > 5) { logger.warn( - `Site last hole punch is too old; skipping this register. The site is failing to hole punch and identify its network address with the server. Can the client reach the server on UDP port ${config.getRawConfig().gerbil.clients_start_port}?` + `Site last hole punch is too old; skipping this register. The site is failing to hole punch and identify its network address with the server. Can the site reach the server on UDP port ${config.getRawConfig().gerbil.clients_start_port}?` ); return; } diff --git a/server/routers/siteResource/createSiteResource.ts b/server/routers/siteResource/createSiteResource.ts index f871990fa..ec2eda527 100644 --- a/server/routers/siteResource/createSiteResource.ts +++ b/server/routers/siteResource/createSiteResource.ts @@ -262,7 +262,7 @@ export async function createSiteResource( let fullDomain: string | null = null; let finalSubdomain: string | null = null; - if (domainId && subdomain) { + if (domainId) { // Validate domain and construct full domain const domainResult = await validateAndConstructDomain( domainId, diff --git a/server/routers/siteResource/updateSiteResource.ts b/server/routers/siteResource/updateSiteResource.ts index ef72ebd84..6e253d0e3 100644 --- a/server/routers/siteResource/updateSiteResource.ts +++ b/server/routers/siteResource/updateSiteResource.ts @@ -80,18 +80,15 @@ const updateSiteResourceSchema = z .strict() .refine( (data) => { - if ( - data.mode === "host" && - data.destination - ) { - const isValidIP = z - // .union([z.ipv4(), z.ipv6()]) - .union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere - .safeParse(data.destination).success; + if (data.mode === "host" && data.destination) { + const isValidIP = z + // .union([z.ipv4(), z.ipv6()]) + .union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere + .safeParse(data.destination).success; - if (isValidIP) { - return true; - } + if (isValidIP) { + return true; + } // Check if it's a valid domain (hostname pattern, TLD not required) const domainRegex = @@ -306,7 +303,7 @@ export async function updateSiteResource( let fullDomain: string | null = null; let finalSubdomain: string | null = null; - if (domainId && subdomain) { + if (domainId) { // Validate domain and construct full domain const domainResult = await validateAndConstructDomain( domainId, @@ -324,12 +321,16 @@ export async function updateSiteResource( finalSubdomain = domainResult.subdomain; // make sure the full domain is unique - const existingResource = await db + const [existingDomain] = await db .select() .from(siteResources) .where(eq(siteResources.fullDomain, fullDomain)); - if (existingResource.length > 0) { + if ( + existingDomain && + existingDomain.siteResourceId !== + existingSiteResource.siteResourceId + ) { return next( createHttpError( HttpCode.CONFLICT, @@ -666,9 +667,14 @@ export async function handleMessagingForUpdatedSiteResource( const destinationChanged = existingSiteResource && existingSiteResource.destination !== updatedSiteResource.destination; + const destinationPortChanged = + existingSiteResource && + existingSiteResource.destinationPort !== + updatedSiteResource.destinationPort; const aliasChanged = existingSiteResource && - existingSiteResource.alias !== updatedSiteResource.alias; + (existingSiteResource.alias !== updatedSiteResource.alias || + existingSiteResource.fullDomain !== updatedSiteResource.fullDomain); // because the full domain gets sent down to the stuff as an alias const portRangesChanged = existingSiteResource && (existingSiteResource.tcpPortRangeString !== @@ -680,7 +686,7 @@ export async function handleMessagingForUpdatedSiteResource( // if the existingSiteResource is undefined (new resource) we don't need to do anything here, the rebuild above handled it all - if (destinationChanged || aliasChanged || portRangesChanged) { + if (destinationChanged || aliasChanged || portRangesChanged || destinationPortChanged) { const [newt] = await trx .select() .from(newts) @@ -694,7 +700,7 @@ export async function handleMessagingForUpdatedSiteResource( } // Only update targets on newt if destination changed - if (destinationChanged || portRangesChanged) { + if (destinationChanged || portRangesChanged || destinationPortChanged) { const oldTarget = await generateSubnetProxyTargetV2( existingSiteResource, mergedAllClients diff --git a/src/app/[orgId]/settings/logs/request/page.tsx b/src/app/[orgId]/settings/logs/request/page.tsx index 4a1fe3cd9..061995811 100644 --- a/src/app/[orgId]/settings/logs/request/page.tsx +++ b/src/app/[orgId]/settings/logs/request/page.tsx @@ -360,6 +360,7 @@ export default function GeneralPage() { // 105 - Valid Password // 106 - Valid email // 107 - Valid SSO + // 108 - Connected Client // 201 - Resource Not Found // 202 - Resource Blocked @@ -377,6 +378,7 @@ export default function GeneralPage() { 105: t("validPassword"), 106: t("validEmail"), 107: t("validSSO"), + 108: t("connectedClient"), 201: t("resourceNotFound"), 202: t("resourceBlocked"), 203: t("droppedByRule"), @@ -634,6 +636,7 @@ export default function GeneralPage() { { value: "105", label: t("validPassword") }, { value: "106", label: t("validEmail") }, { value: "107", label: t("validSSO") }, + { value: "108", label: t("connectedClient") }, { value: "201", label: t("resourceNotFound") }, { value: "202", label: t("resourceBlocked") }, { value: "203", label: t("droppedByRule") },