Add maintence options to blueprints

This commit is contained in:
Owen
2025-12-22 14:00:34 -05:00
parent 71386d3b05
commit 2e60ecec87
3 changed files with 93 additions and 32 deletions

View File

@@ -2,7 +2,8 @@ import {
domains,
orgDomains,
Resource,
resourceHeaderAuth, resourceHeaderAuthExtendedCompatibility,
resourceHeaderAuth,
resourceHeaderAuthExtendedCompatibility,
resourcePincode,
resourceRules,
resourceWhitelist,
@@ -16,8 +17,8 @@ import {
userResources,
users
} from "@server/db";
import {resources, targets, sites} from "@server/db";
import {eq, and, asc, or, ne, count, isNotNull} from "drizzle-orm";
import { resources, targets, sites } from "@server/db";
import { eq, and, asc, or, ne, count, isNotNull } from "drizzle-orm";
import {
Config,
ConfigSchema,
@@ -25,12 +26,13 @@ import {
TargetData
} from "./types";
import logger from "@server/logger";
import {createCertificate} from "#dynamic/routers/certificates/createCertificate";
import {pickPort} from "@server/routers/target/helpers";
import {resourcePassword} from "@server/db";
import {hashPassword} from "@server/auth/password";
import {isValidCIDR, isValidIP, isValidUrlGlobPattern} from "../validators";
import {get} from "http";
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
import { pickPort } from "@server/routers/target/helpers";
import { resourcePassword } from "@server/db";
import { hashPassword } from "@server/auth/password";
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
import { isLicensedOrSubscribed } from "../isLicencedOrSubscribed";
import { build } from "@server/build";
export type ProxyResourcesResults = {
proxyResource: Resource;
@@ -63,7 +65,7 @@ export async function updateProxyResources(
if (targetSiteId) {
// Look up site by niceId
[site] = await trx
.select({siteId: sites.siteId})
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
@@ -75,7 +77,7 @@ export async function updateProxyResources(
} else if (siteId) {
// Use the provided siteId directly, but verify it belongs to the org
[site] = await trx
.select({siteId: sites.siteId})
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(eq(sites.siteId, siteId), eq(sites.orgId, orgId))
@@ -93,7 +95,7 @@ export async function updateProxyResources(
let internalPortToCreate;
if (!targetData["internal-port"]) {
const {internalPort, targetIps} = await pickPort(
const { internalPort, targetIps } = await pickPort(
site.siteId!,
trx
);
@@ -209,6 +211,16 @@ export async function updateProxyResources(
resource = existingResource;
} else {
// Update existing resource
const isLicensed = await isLicensedOrSubscribed(orgId);
if (build == "enterprise" && !isLicensed) {
logger.warn(
"Server is not licensed! Clearing set maintenance screen values"
);
// null the maintenance mode fields if not licensed
resourceData.maintenance = undefined;
}
[resource] = await trx
.update(resources)
.set({
@@ -228,12 +240,19 @@ export async function updateProxyResources(
tlsServerName: resourceData["tls-server-name"] || null,
emailWhitelistEnabled: resourceData.auth?.[
"whitelist-users"
]
]
? resourceData.auth["whitelist-users"].length > 0
: false,
headers: headers || null,
applyRules:
resourceData.rules && resourceData.rules.length > 0
resourceData.rules && resourceData.rules.length > 0,
maintenanceModeEnabled:
resourceData.maintenance?.enabled,
maintenanceModeType: resourceData.maintenance?.type,
maintenanceTitle: resourceData.maintenance?.title,
maintenanceMessage: resourceData.maintenance?.message,
maintenanceEstimatedTime:
resourceData.maintenance?.["estimated-time"]
})
.where(
eq(resources.resourceId, existingResource.resourceId)
@@ -303,8 +322,13 @@ export async function updateProxyResources(
const headerAuthPassword =
resourceData.auth?.["basic-auth"]?.password;
const headerAuthExtendedCompatibility =
resourceData.auth?.["basic-auth"]?.extendedCompatibility;
if (headerAuthUser && headerAuthPassword && headerAuthExtendedCompatibility !== null) {
resourceData.auth?.["basic-auth"]
?.extendedCompatibility;
if (
headerAuthUser &&
headerAuthPassword &&
headerAuthExtendedCompatibility !== null
) {
const headerAuthHash = await hashPassword(
Buffer.from(
`${headerAuthUser}:${headerAuthPassword}`
@@ -315,10 +339,13 @@ export async function updateProxyResources(
resourceId: existingResource.resourceId,
headerAuthHash
}),
trx.insert(resourceHeaderAuthExtendedCompatibility).values({
resourceId: existingResource.resourceId,
extendedCompatibilityIsActivated: headerAuthExtendedCompatibility
})
trx
.insert(resourceHeaderAuthExtendedCompatibility)
.values({
resourceId: existingResource.resourceId,
extendedCompatibilityIsActivated:
headerAuthExtendedCompatibility
})
]);
}
}
@@ -380,7 +407,7 @@ export async function updateProxyResources(
if (targetSiteId) {
// Look up site by niceId
[site] = await trx
.select({siteId: sites.siteId})
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
@@ -392,7 +419,7 @@ export async function updateProxyResources(
} else if (siteId) {
// Use the provided siteId directly, but verify it belongs to the org
[site] = await trx
.select({siteId: sites.siteId})
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
@@ -437,7 +464,7 @@ export async function updateProxyResources(
if (checkIfTargetChanged(existingTarget, updatedTarget)) {
let internalPortToUpdate;
if (!targetData["internal-port"]) {
const {internalPort, targetIps} = await pickPort(
const { internalPort, targetIps } = await pickPort(
site.siteId!,
trx
);
@@ -622,6 +649,15 @@ export async function updateProxyResources(
);
}
const isLicensed = await isLicensedOrSubscribed(orgId);
if (build == "enterprise" && !isLicensed) {
logger.warn(
"Server is not licensed! Clearing set maintenance screen values"
);
// null the maintenance mode fields if not licensed
resourceData.maintenance = undefined;
}
// Create new resource
const [newResource] = await trx
.insert(resources)
@@ -643,7 +679,13 @@ export async function updateProxyResources(
ssl: resourceSsl,
headers: headers || null,
applyRules:
resourceData.rules && resourceData.rules.length > 0
resourceData.rules && resourceData.rules.length > 0,
maintenanceModeEnabled: resourceData.maintenance?.enabled,
maintenanceModeType: resourceData.maintenance?.type,
maintenanceTitle: resourceData.maintenance?.title,
maintenanceMessage: resourceData.maintenance?.message,
maintenanceEstimatedTime:
resourceData.maintenance?.["estimated-time"]
})
.returning();
@@ -674,9 +716,14 @@ export async function updateProxyResources(
const headerAuthUser = resourceData.auth?.["basic-auth"]?.user;
const headerAuthPassword =
resourceData.auth?.["basic-auth"]?.password;
const headerAuthExtendedCompatibility = resourceData.auth?.["basic-auth"]?.extendedCompatibility;
const headerAuthExtendedCompatibility =
resourceData.auth?.["basic-auth"]?.extendedCompatibility;
if (headerAuthUser && headerAuthPassword && headerAuthExtendedCompatibility !== null) {
if (
headerAuthUser &&
headerAuthPassword &&
headerAuthExtendedCompatibility !== null
) {
const headerAuthHash = await hashPassword(
Buffer.from(
`${headerAuthUser}:${headerAuthPassword}`
@@ -688,10 +735,13 @@ export async function updateProxyResources(
resourceId: newResource.resourceId,
headerAuthHash
}),
trx.insert(resourceHeaderAuthExtendedCompatibility).values({
resourceId: newResource.resourceId,
extendedCompatibilityIsActivated: headerAuthExtendedCompatibility
}),
trx
.insert(resourceHeaderAuthExtendedCompatibility)
.values({
resourceId: newResource.resourceId,
extendedCompatibilityIsActivated:
headerAuthExtendedCompatibility
})
]);
}
}
@@ -1043,7 +1093,7 @@ async function getDomain(
trx: Transaction
) {
const [fullDomainExists] = await trx
.select({resourceId: resources.resourceId})
.select({ resourceId: resources.resourceId })
.from(resources)
.where(
and(