Merge branch 'private-http' of https://github.com/fosrl/pangolin into private-http

This commit is contained in:
miloschwartz
2026-04-12 12:17:57 -07:00
8 changed files with 38 additions and 27 deletions

View File

@@ -2437,6 +2437,7 @@
"validPassword": "Valid Password", "validPassword": "Valid Password",
"validEmail": "Valid email", "validEmail": "Valid email",
"validSSO": "Valid SSO", "validSSO": "Valid SSO",
"connectedClient": "Connected Client",
"resourceBlocked": "Resource Blocked", "resourceBlocked": "Resource Blocked",
"droppedByRule": "Dropped by Rule", "droppedByRule": "Dropped by Rule",
"noSessions": "No Sessions", "noSessions": "No Sessions",

View File

@@ -662,10 +662,10 @@ export async function generateSubnetProxyTargetV2(
} }
if ( if (
!siteResource.alias ||
!siteResource.aliasAddress || !siteResource.aliasAddress ||
!siteResource.destinationPort || !siteResource.destinationPort ||
!siteResource.scheme !siteResource.scheme ||
!siteResource.fullDomain
) { ) {
logger.debug( 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.` `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 tlsCert: string | undefined;
let tlsKey: string | undefined; let tlsKey: string | undefined;
if (siteResource.ssl && siteResource.alias) { if (siteResource.ssl && siteResource.fullDomain) {
try { try {
const certs = await getValidCertificatesForDomains( const certs = await getValidCertificatesForDomains(
new Set([siteResource.alias]), new Set([siteResource.fullDomain]),
true true
); );
if (certs.length > 0 && certs[0].certFile && certs[0].keyFile) { if (certs.length > 0 && certs[0].certFile && certs[0].keyFile) {
@@ -687,12 +687,12 @@ export async function generateSubnetProxyTargetV2(
tlsKey = certs[0].keyFile; tlsKey = certs[0].keyFile;
} else { } else {
logger.warn( 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) { } catch (err) {
logger.error( 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}`
); );
} }
} }

View File

@@ -144,7 +144,7 @@ export const handleRequestLogMessage: MessageHandler = async (context) => {
await logRequestAudit( await logRequestAudit(
{ {
action: true, action: true,
reason: 100, reason: 108,
resourceId: entry.resourceId, resourceId: entry.resourceId,
orgId orgId
}, },
@@ -163,4 +163,4 @@ export const handleRequestLogMessage: MessageHandler = async (context) => {
logger.debug( logger.debug(
`Buffered ${entries.length} request log entry/entries from newt ${newt.newtId} (site ${newt.siteId})` `Buffered ${entries.length} request log entry/entries from newt ${newt.newtId} (site ${newt.siteId})`
); );
}; };

View File

@@ -18,6 +18,7 @@ Reasons:
105 - Valid Password 105 - Valid Password
106 - Valid email 106 - Valid email
107 - Valid SSO 107 - Valid SSO
108 - Connected Client
201 - Resource Not Found 201 - Resource Not Found
202 - Resource Blocked 202 - Resource Blocked

View File

@@ -56,7 +56,7 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
if (existingSite.lastHolePunch && now - existingSite.lastHolePunch > 5) { if (existingSite.lastHolePunch && now - existingSite.lastHolePunch > 5) {
logger.warn( 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; return;
} }

View File

@@ -262,7 +262,7 @@ export async function createSiteResource(
let fullDomain: string | null = null; let fullDomain: string | null = null;
let finalSubdomain: string | null = null; let finalSubdomain: string | null = null;
if (domainId && subdomain) { if (domainId) {
// Validate domain and construct full domain // Validate domain and construct full domain
const domainResult = await validateAndConstructDomain( const domainResult = await validateAndConstructDomain(
domainId, domainId,

View File

@@ -80,18 +80,15 @@ const updateSiteResourceSchema = z
.strict() .strict()
.refine( .refine(
(data) => { (data) => {
if ( if (data.mode === "host" && data.destination) {
data.mode === "host" && const isValidIP = z
data.destination // .union([z.ipv4(), z.ipv6()])
) { .union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere
const isValidIP = z .safeParse(data.destination).success;
// .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) { if (isValidIP) {
return true; return true;
} }
// Check if it's a valid domain (hostname pattern, TLD not required) // Check if it's a valid domain (hostname pattern, TLD not required)
const domainRegex = const domainRegex =
@@ -306,7 +303,7 @@ export async function updateSiteResource(
let fullDomain: string | null = null; let fullDomain: string | null = null;
let finalSubdomain: string | null = null; let finalSubdomain: string | null = null;
if (domainId && subdomain) { if (domainId) {
// Validate domain and construct full domain // Validate domain and construct full domain
const domainResult = await validateAndConstructDomain( const domainResult = await validateAndConstructDomain(
domainId, domainId,
@@ -324,12 +321,16 @@ export async function updateSiteResource(
finalSubdomain = domainResult.subdomain; finalSubdomain = domainResult.subdomain;
// make sure the full domain is unique // make sure the full domain is unique
const existingResource = await db const [existingDomain] = await db
.select() .select()
.from(siteResources) .from(siteResources)
.where(eq(siteResources.fullDomain, fullDomain)); .where(eq(siteResources.fullDomain, fullDomain));
if (existingResource.length > 0) { if (
existingDomain &&
existingDomain.siteResourceId !==
existingSiteResource.siteResourceId
) {
return next( return next(
createHttpError( createHttpError(
HttpCode.CONFLICT, HttpCode.CONFLICT,
@@ -666,9 +667,14 @@ export async function handleMessagingForUpdatedSiteResource(
const destinationChanged = const destinationChanged =
existingSiteResource && existingSiteResource &&
existingSiteResource.destination !== updatedSiteResource.destination; existingSiteResource.destination !== updatedSiteResource.destination;
const destinationPortChanged =
existingSiteResource &&
existingSiteResource.destinationPort !==
updatedSiteResource.destinationPort;
const aliasChanged = const aliasChanged =
existingSiteResource && 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 = const portRangesChanged =
existingSiteResource && existingSiteResource &&
(existingSiteResource.tcpPortRangeString !== (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 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 const [newt] = await trx
.select() .select()
.from(newts) .from(newts)
@@ -694,7 +700,7 @@ export async function handleMessagingForUpdatedSiteResource(
} }
// Only update targets on newt if destination changed // Only update targets on newt if destination changed
if (destinationChanged || portRangesChanged) { if (destinationChanged || portRangesChanged || destinationPortChanged) {
const oldTarget = await generateSubnetProxyTargetV2( const oldTarget = await generateSubnetProxyTargetV2(
existingSiteResource, existingSiteResource,
mergedAllClients mergedAllClients

View File

@@ -360,6 +360,7 @@ export default function GeneralPage() {
// 105 - Valid Password // 105 - Valid Password
// 106 - Valid email // 106 - Valid email
// 107 - Valid SSO // 107 - Valid SSO
// 108 - Connected Client
// 201 - Resource Not Found // 201 - Resource Not Found
// 202 - Resource Blocked // 202 - Resource Blocked
@@ -377,6 +378,7 @@ export default function GeneralPage() {
105: t("validPassword"), 105: t("validPassword"),
106: t("validEmail"), 106: t("validEmail"),
107: t("validSSO"), 107: t("validSSO"),
108: t("connectedClient"),
201: t("resourceNotFound"), 201: t("resourceNotFound"),
202: t("resourceBlocked"), 202: t("resourceBlocked"),
203: t("droppedByRule"), 203: t("droppedByRule"),
@@ -630,6 +632,7 @@ export default function GeneralPage() {
{ value: "105", label: t("validPassword") }, { value: "105", label: t("validPassword") },
{ value: "106", label: t("validEmail") }, { value: "106", label: t("validEmail") },
{ value: "107", label: t("validSSO") }, { value: "107", label: t("validSSO") },
{ value: "108", label: t("connectedClient") },
{ value: "201", label: t("resourceNotFound") }, { value: "201", label: t("resourceNotFound") },
{ value: "202", label: t("resourceBlocked") }, { value: "202", label: t("resourceBlocked") },
{ value: "203", label: t("droppedByRule") }, { value: "203", label: t("droppedByRule") },