Merge branch 'dev' of https://github.com/fosrl/pangolin into dev

This commit is contained in:
miloschwartz
2025-12-18 17:47:59 -05:00
6 changed files with 76 additions and 18 deletions

View File

@@ -81,6 +81,7 @@ function createDb() {
export const db = createDb();
export default db;
export const primaryDb = db.$primary;
export type Transaction = Parameters<
Parameters<(typeof db)["transaction"]>[0]
>[0];

View File

@@ -20,7 +20,7 @@ function createDb() {
export const db = createDb();
export default db;
export const driver: "pg" | "sqlite" = "sqlite";
export const primaryDb = db;
export type Transaction = Parameters<
Parameters<(typeof db)["transaction"]>[0]
>[0];

View File

@@ -1,4 +1,4 @@
import { db, requestAuditLog, driver } from "@server/db";
import { db, requestAuditLog, driver, primaryDb } from "@server/db";
import { registry } from "@server/openApi";
import { NextFunction } from "express";
import { Request, Response } from "express";
@@ -12,11 +12,6 @@ import response from "@server/lib/response";
import logger from "@server/logger";
import { getSevenDaysAgo } from "@app/lib/getSevenDaysAgo";
let primaryDb = db;
if (driver == "pg") {
primaryDb = db.$primary as typeof db; // select the primary instance in a replicated setup
}
const queryAccessAuditLogsQuery = z.object({
// iso string just validate its a parseable date
timeStart: z

View File

@@ -1,4 +1,4 @@
import { db, driver, requestAuditLog, resources } from "@server/db";
import { db, primaryDb, requestAuditLog, resources } from "@server/db";
import { registry } from "@server/openApi";
import { NextFunction } from "express";
import { Request, Response } from "express";
@@ -13,11 +13,6 @@ import response from "@server/lib/response";
import logger from "@server/logger";
import { getSevenDaysAgo } from "@app/lib/getSevenDaysAgo";
let primaryDb = db;
if (driver == "pg") {
primaryDb = db.$primary as typeof db; // select the primary instance in a replicated setup
}
export const queryAccessAuditLogsQuery = z.object({
// iso string just validate its a parseable date
timeStart: z

View File

@@ -2,6 +2,7 @@ import {
clientSiteResources,
db,
newts,
orgs,
roles,
roleSiteResources,
SiteResource,
@@ -10,7 +11,7 @@ import {
userSiteResources
} from "@server/db";
import { getUniqueSiteResourceName } from "@server/db/names";
import { getNextAvailableAliasAddress, portRangeStringSchema } from "@server/lib/ip";
import { getNextAvailableAliasAddress, isIpInCidr, portRangeStringSchema } from "@server/lib/ip";
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
import response from "@server/lib/response";
import logger from "@server/logger";
@@ -84,8 +85,7 @@ const createSiteResourceSchema = z
if (data.mode === "cidr") {
// Check if it's a valid CIDR (v4 or v6)
const isValidCIDR = z
// .union([z.cidrv4(), z.cidrv6()])
.union([z.cidrv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere
.union([z.cidrv4(), z.cidrv6()])
.safeParse(data.destination).success;
return isValidCIDR;
}
@@ -175,6 +175,39 @@ export async function createSiteResource(
return next(createHttpError(HttpCode.NOT_FOUND, "Site not found"));
}
const [org] = await db
.select()
.from(orgs)
.where(eq(orgs.orgId, orgId))
.limit(1);
if (!org) {
return next(createHttpError(HttpCode.NOT_FOUND, "Organization not found"));
}
if (!org.subnet || !org.utilitySubnet) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
`Organization with ID ${orgId} has no subnet or utilitySubnet defined defined`
)
);
}
// Only check if destination is an IP address
const isIp = z.union([z.ipv4(), z.ipv6()]).safeParse(destination).success;
if (
isIp &&
(isIpInCidr(destination, org.subnet) || isIpInCidr(destination, org.utilitySubnet))
) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"IP can not be in the CIDR range of the organization's subnet or utility subnet"
)
);
}
// // check if resource with same protocol and proxy port already exists (only for port mode)
// if (mode === "port" && protocol && proxyPort) {
// const [existingResource] = await db

View File

@@ -5,6 +5,7 @@ import {
clientSiteResourcesAssociationsCache,
db,
newts,
orgs,
roles,
roleSiteResources,
sites,
@@ -24,6 +25,7 @@ import {
generateAliasConfig,
generateRemoteSubnets,
generateSubnetProxyTargets,
isIpInCidr,
portRangeStringSchema
} from "@server/lib/ip";
import {
@@ -96,8 +98,7 @@ const updateSiteResourceSchema = z
if (data.mode === "cidr" && data.destination) {
// Check if it's a valid CIDR (v4 or v6)
const isValidCIDR = z
// .union([z.cidrv4(), z.cidrv6()])
.union([z.cidrv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere
.union([z.cidrv4(), z.cidrv6()])
.safeParse(data.destination).success;
return isValidCIDR;
}
@@ -196,6 +197,39 @@ export async function updateSiteResource(
);
}
const [org] = await db
.select()
.from(orgs)
.where(eq(orgs.orgId, existingSiteResource.orgId))
.limit(1);
if (!org) {
return next(createHttpError(HttpCode.NOT_FOUND, "Organization not found"));
}
if (!org.subnet || !org.utilitySubnet) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
`Organization with ID ${existingSiteResource.orgId} has no subnet or utilitySubnet defined defined`
)
);
}
// Only check if destination is an IP address
const isIp = z.union([z.ipv4(), z.ipv6()]).safeParse(destination).success;
if (
isIp &&
(isIpInCidr(destination!, org.subnet) || isIpInCidr(destination!, org.utilitySubnet))
) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"IP can not be in the CIDR range of the organization's subnet or utility subnet"
)
);
}
let existingSite = site;
let siteChanged = false;
if (existingSiteResource.siteId !== siteId) {