mirror of
https://github.com/fosrl/pangolin.git
synced 2026-04-12 22:26:29 +00:00
Crud working
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
clients,
|
clients,
|
||||||
clientSiteResources,
|
clientSiteResources,
|
||||||
|
domains,
|
||||||
|
orgDomains,
|
||||||
roles,
|
roles,
|
||||||
roleSiteResources,
|
roleSiteResources,
|
||||||
SiteResource,
|
SiteResource,
|
||||||
@@ -11,10 +13,83 @@ import {
|
|||||||
userSiteResources
|
userSiteResources
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { sites } from "@server/db";
|
import { sites } from "@server/db";
|
||||||
import { eq, and, ne, inArray, or } from "drizzle-orm";
|
import { eq, and, ne, inArray, or, isNotNull } from "drizzle-orm";
|
||||||
import { Config } from "./types";
|
import { Config } from "./types";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { getNextAvailableAliasAddress } from "../ip";
|
import { getNextAvailableAliasAddress } from "../ip";
|
||||||
|
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||||
|
|
||||||
|
async function getDomainForSiteResource(
|
||||||
|
siteResourceId: number | undefined,
|
||||||
|
fullDomain: string,
|
||||||
|
orgId: string,
|
||||||
|
trx: Transaction
|
||||||
|
): Promise<{ subdomain: string | null; domainId: string }> {
|
||||||
|
const [fullDomainExists] = await trx
|
||||||
|
.select({ siteResourceId: siteResources.siteResourceId })
|
||||||
|
.from(siteResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(siteResources.fullDomain, fullDomain),
|
||||||
|
eq(siteResources.orgId, orgId),
|
||||||
|
siteResourceId
|
||||||
|
? ne(siteResources.siteResourceId, siteResourceId)
|
||||||
|
: isNotNull(siteResources.siteResourceId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (fullDomainExists) {
|
||||||
|
throw new Error(
|
||||||
|
`Site resource already exists with domain: ${fullDomain} in org ${orgId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const possibleDomains = await trx
|
||||||
|
.select()
|
||||||
|
.from(domains)
|
||||||
|
.innerJoin(orgDomains, eq(domains.domainId, orgDomains.domainId))
|
||||||
|
.where(and(eq(orgDomains.orgId, orgId), eq(domains.verified, true)))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (possibleDomains.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Domain not found for full-domain: ${fullDomain} in org ${orgId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const validDomains = possibleDomains.filter((domain) => {
|
||||||
|
if (domain.domains.type == "ns" || domain.domains.type == "wildcard") {
|
||||||
|
return (
|
||||||
|
fullDomain === domain.domains.baseDomain ||
|
||||||
|
fullDomain.endsWith(`.${domain.domains.baseDomain}`)
|
||||||
|
);
|
||||||
|
} else if (domain.domains.type == "cname") {
|
||||||
|
return fullDomain === domain.domains.baseDomain;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (validDomains.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Domain not found for full-domain: ${fullDomain} in org ${orgId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const domainSelection = validDomains[0].domains;
|
||||||
|
const baseDomain = domainSelection.baseDomain;
|
||||||
|
|
||||||
|
let subdomain: string | null = null;
|
||||||
|
if (fullDomain !== baseDomain) {
|
||||||
|
subdomain = fullDomain.replace(`.${baseDomain}`, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
await createCertificate(domainSelection.domainId, fullDomain, trx);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subdomain,
|
||||||
|
domainId: domainSelection.domainId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function siteResourceModeForDb(mode: "host" | "cidr" | "http" | "https"): {
|
function siteResourceModeForDb(mode: "host" | "cidr" | "http" | "https"): {
|
||||||
mode: "host" | "cidr" | "http";
|
mode: "host" | "cidr" | "http";
|
||||||
@@ -91,6 +166,19 @@ export async function updateClientResources(
|
|||||||
|
|
||||||
if (existingResource) {
|
if (existingResource) {
|
||||||
const mappedMode = siteResourceModeForDb(resourceData.mode);
|
const mappedMode = siteResourceModeForDb(resourceData.mode);
|
||||||
|
|
||||||
|
let domainInfo:
|
||||||
|
| { subdomain: string | null; domainId: string }
|
||||||
|
| undefined;
|
||||||
|
if (resourceData["full-domain"] && mappedMode.mode === "http") {
|
||||||
|
domainInfo = await getDomainForSiteResource(
|
||||||
|
existingResource.siteResourceId,
|
||||||
|
resourceData["full-domain"],
|
||||||
|
orgId,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Update existing resource
|
// Update existing resource
|
||||||
const [updatedResource] = await trx
|
const [updatedResource] = await trx
|
||||||
.update(siteResources)
|
.update(siteResources)
|
||||||
@@ -107,7 +195,10 @@ export async function updateClientResources(
|
|||||||
alias: resourceData.alias || null,
|
alias: resourceData.alias || null,
|
||||||
disableIcmp: resourceData["disable-icmp"],
|
disableIcmp: resourceData["disable-icmp"],
|
||||||
tcpPortRangeString: resourceData["tcp-ports"],
|
tcpPortRangeString: resourceData["tcp-ports"],
|
||||||
udpPortRangeString: resourceData["udp-ports"]
|
udpPortRangeString: resourceData["udp-ports"],
|
||||||
|
fullDomain: resourceData["full-domain"] || null,
|
||||||
|
subdomain: domainInfo ? domainInfo.subdomain : null,
|
||||||
|
domainId: domainInfo ? domainInfo.domainId : null
|
||||||
})
|
})
|
||||||
.where(
|
.where(
|
||||||
eq(
|
eq(
|
||||||
@@ -118,7 +209,6 @@ export async function updateClientResources(
|
|||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
const siteResourceId = existingResource.siteResourceId;
|
const siteResourceId = existingResource.siteResourceId;
|
||||||
const orgId = existingResource.orgId;
|
|
||||||
|
|
||||||
await trx
|
await trx
|
||||||
.delete(clientSiteResources)
|
.delete(clientSiteResources)
|
||||||
@@ -231,6 +321,18 @@ export async function updateClientResources(
|
|||||||
aliasAddress = await getNextAvailableAliasAddress(orgId);
|
aliasAddress = await getNextAvailableAliasAddress(orgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let domainInfo:
|
||||||
|
| { subdomain: string | null; domainId: string }
|
||||||
|
| undefined;
|
||||||
|
if (resourceData["full-domain"] && mappedMode.mode === "http") {
|
||||||
|
domainInfo = await getDomainForSiteResource(
|
||||||
|
undefined,
|
||||||
|
resourceData["full-domain"],
|
||||||
|
orgId,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Create new resource
|
// Create new resource
|
||||||
const [newResource] = await trx
|
const [newResource] = await trx
|
||||||
.insert(siteResources)
|
.insert(siteResources)
|
||||||
@@ -250,7 +352,10 @@ export async function updateClientResources(
|
|||||||
aliasAddress: aliasAddress,
|
aliasAddress: aliasAddress,
|
||||||
disableIcmp: resourceData["disable-icmp"],
|
disableIcmp: resourceData["disable-icmp"],
|
||||||
tcpPortRangeString: resourceData["tcp-ports"],
|
tcpPortRangeString: resourceData["tcp-ports"],
|
||||||
udpPortRangeString: resourceData["udp-ports"]
|
udpPortRangeString: resourceData["udp-ports"],
|
||||||
|
fullDomain: resourceData["full-domain"] || null,
|
||||||
|
subdomain: domainInfo ? domainInfo.subdomain : null,
|
||||||
|
domainId: domainInfo ? domainInfo.domainId : null
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
|||||||
@@ -1100,7 +1100,7 @@ function checkIfTargetChanged(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getDomain(
|
export async function getDomain(
|
||||||
resourceId: number | undefined,
|
resourceId: number | undefined,
|
||||||
fullDomain: string,
|
fullDomain: string,
|
||||||
orgId: string,
|
orgId: string,
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ export function isTargetsOnlyResource(resource: any): boolean {
|
|||||||
export const ClientResourceSchema = z
|
export const ClientResourceSchema = z
|
||||||
.object({
|
.object({
|
||||||
name: z.string().min(1).max(255),
|
name: z.string().min(1).max(255),
|
||||||
mode: z.enum(["host", "cidr", "http", "https"]),
|
mode: z.enum(["host", "cidr", "http"]),
|
||||||
site: z.string(),
|
site: z.string(),
|
||||||
// protocol: z.enum(["tcp", "udp"]).optional(),
|
// protocol: z.enum(["tcp", "udp"]).optional(),
|
||||||
// proxyPort: z.int().positive().optional(),
|
// proxyPort: z.int().positive().optional(),
|
||||||
@@ -335,6 +335,8 @@ export const ClientResourceSchema = z
|
|||||||
"tcp-ports": portRangeStringSchema.optional().default("*"),
|
"tcp-ports": portRangeStringSchema.optional().default("*"),
|
||||||
"udp-ports": portRangeStringSchema.optional().default("*"),
|
"udp-ports": portRangeStringSchema.optional().default("*"),
|
||||||
"disable-icmp": z.boolean().optional().default(false),
|
"disable-icmp": z.boolean().optional().default(false),
|
||||||
|
"full-domain": z.string().optional(),
|
||||||
|
ssl: z.boolean().optional(),
|
||||||
alias: z
|
alias: z
|
||||||
.string()
|
.string()
|
||||||
.regex(
|
.regex(
|
||||||
@@ -477,6 +479,39 @@ export const ConfigSchema = z
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enforce the full-domain uniqueness across client-resources in the same stack
|
||||||
|
const clientFullDomainMap = new Map<string, string[]>();
|
||||||
|
|
||||||
|
Object.entries(config["client-resources"]).forEach(
|
||||||
|
([resourceKey, resource]) => {
|
||||||
|
const fullDomain = resource["full-domain"];
|
||||||
|
if (fullDomain) {
|
||||||
|
if (!clientFullDomainMap.has(fullDomain)) {
|
||||||
|
clientFullDomainMap.set(fullDomain, []);
|
||||||
|
}
|
||||||
|
clientFullDomainMap.get(fullDomain)!.push(resourceKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const clientFullDomainDuplicates = Array.from(
|
||||||
|
clientFullDomainMap.entries()
|
||||||
|
)
|
||||||
|
.filter(([_, resourceKeys]) => resourceKeys.length > 1)
|
||||||
|
.map(
|
||||||
|
([fullDomain, resourceKeys]) =>
|
||||||
|
`'${fullDomain}' used by resources: ${resourceKeys.join(", ")}`
|
||||||
|
)
|
||||||
|
.join("; ");
|
||||||
|
|
||||||
|
if (clientFullDomainDuplicates.length !== 0) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
path: ["client-resources"],
|
||||||
|
message: `Duplicate 'full-domain' values found: ${clientFullDomainDuplicates}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Enforce proxy-port uniqueness within proxy-resources per protocol
|
// Enforce proxy-port uniqueness within proxy-resources per protocol
|
||||||
const protocolPortMap = new Map<string, string[]>();
|
const protocolPortMap = new Map<string, string[]>();
|
||||||
|
|
||||||
|
|||||||
@@ -478,9 +478,9 @@ export type Alias = { alias: string | null; aliasAddress: string | null };
|
|||||||
|
|
||||||
export function generateAliasConfig(allSiteResources: SiteResource[]): Alias[] {
|
export function generateAliasConfig(allSiteResources: SiteResource[]): Alias[] {
|
||||||
return allSiteResources
|
return allSiteResources
|
||||||
.filter((sr) => sr.alias && sr.aliasAddress && sr.mode == "host")
|
.filter((sr) => sr.aliasAddress && ((sr.alias && sr.mode == "host") || (sr.fullDomain && sr.mode == "http")))
|
||||||
.map((sr) => ({
|
.map((sr) => ({
|
||||||
alias: sr.alias,
|
alias: sr.alias || sr.fullDomain,
|
||||||
aliasAddress: sr.aliasAddress
|
aliasAddress: sr.aliasAddress
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -672,7 +672,6 @@ export async function generateSubnetProxyTargetV2(
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const publicProtocol = siteResource.ssl ? "https" : "http";
|
|
||||||
// also push a match for the alias address
|
// also push a match for the alias address
|
||||||
let tlsCert: string | undefined;
|
let tlsCert: string | undefined;
|
||||||
let tlsKey: string | undefined;
|
let tlsKey: string | undefined;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import { getUserDeviceName } from "@server/db/names";
|
|||||||
import { buildSiteConfigurationForOlmClient } from "./buildConfiguration";
|
import { buildSiteConfigurationForOlmClient } from "./buildConfiguration";
|
||||||
import { OlmErrorCodes, sendOlmError } from "./error";
|
import { OlmErrorCodes, sendOlmError } from "./error";
|
||||||
import { handleFingerprintInsertion } from "./fingerprintingUtils";
|
import { handleFingerprintInsertion } from "./fingerprintingUtils";
|
||||||
import { Alias } from "@server/lib/ip";
|
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { canCompress } from "@server/lib/clientVersionChecks";
|
import { canCompress } from "@server/lib/clientVersionChecks";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ const createSiteResourceSchema = z
|
|||||||
.strict()
|
.strict()
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
if (data.mode === "host" || data.mode == "http") {
|
if (data.mode === "host") {
|
||||||
if (data.mode == "host") {
|
if (data.mode == "host") {
|
||||||
// Check if it's a valid IP address using zod (v4 or v6)
|
// Check if it's a valid IP address using zod (v4 or v6)
|
||||||
const isValidIP = z
|
const isValidIP = z
|
||||||
@@ -262,7 +262,6 @@ export async function createSiteResource(
|
|||||||
|
|
||||||
let fullDomain: string | null = null;
|
let fullDomain: string | null = null;
|
||||||
let finalSubdomain: string | null = null;
|
let finalSubdomain: string | null = null;
|
||||||
let finalAlias = alias ? alias.trim() : null;
|
|
||||||
if (domainId && subdomain) {
|
if (domainId && subdomain) {
|
||||||
// Validate domain and construct full domain
|
// Validate domain and construct full domain
|
||||||
const domainResult = await validateAndConstructDomain(
|
const domainResult = await validateAndConstructDomain(
|
||||||
@@ -279,18 +278,32 @@ export async function createSiteResource(
|
|||||||
|
|
||||||
fullDomain = domainResult.fullDomain;
|
fullDomain = domainResult.fullDomain;
|
||||||
finalSubdomain = domainResult.subdomain;
|
finalSubdomain = domainResult.subdomain;
|
||||||
finalAlias = fullDomain; // we will use the full domain as the alias for uniqueness checks and routing
|
|
||||||
|
// make sure the full domain is unique
|
||||||
|
const existingResource = await db
|
||||||
|
.select()
|
||||||
|
.from(siteResources)
|
||||||
|
.where(eq(siteResources.fullDomain, fullDomain));
|
||||||
|
|
||||||
|
if (existingResource.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
"Resource with that domain already exists"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the alias is unique within the org if provided
|
// make sure the alias is unique within the org if provided
|
||||||
if (finalAlias) {
|
if (alias) {
|
||||||
const [conflict] = await db
|
const [conflict] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(siteResources)
|
.from(siteResources)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(siteResources.orgId, orgId),
|
eq(siteResources.orgId, orgId),
|
||||||
eq(siteResources.alias, finalAlias.trim())
|
eq(siteResources.alias, alias.trim())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
@@ -330,13 +343,14 @@ export async function createSiteResource(
|
|||||||
scheme,
|
scheme,
|
||||||
destinationPort,
|
destinationPort,
|
||||||
enabled,
|
enabled,
|
||||||
alias: finalAlias,
|
alias: alias ? alias.trim() : null,
|
||||||
aliasAddress,
|
aliasAddress,
|
||||||
tcpPortRangeString,
|
tcpPortRangeString,
|
||||||
udpPortRangeString,
|
udpPortRangeString,
|
||||||
disableIcmp,
|
disableIcmp,
|
||||||
domainId,
|
domainId,
|
||||||
subdomain: finalSubdomain
|
subdomain: finalSubdomain,
|
||||||
|
fullDomain
|
||||||
};
|
};
|
||||||
if (isLicensedSshPam) {
|
if (isLicensedSshPam) {
|
||||||
if (authDaemonPort !== undefined)
|
if (authDaemonPort !== undefined)
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ function querySiteResourcesBase() {
|
|||||||
disableIcmp: siteResources.disableIcmp,
|
disableIcmp: siteResources.disableIcmp,
|
||||||
authDaemonMode: siteResources.authDaemonMode,
|
authDaemonMode: siteResources.authDaemonMode,
|
||||||
authDaemonPort: siteResources.authDaemonPort,
|
authDaemonPort: siteResources.authDaemonPort,
|
||||||
|
subdomain: siteResources.subdomain,
|
||||||
|
domainId: siteResources.domainId,
|
||||||
|
fullDomain: siteResources.fullDomain,
|
||||||
siteName: sites.name,
|
siteName: sites.name,
|
||||||
siteNiceId: sites.niceId,
|
siteNiceId: sites.niceId,
|
||||||
siteAddress: sites.address
|
siteAddress: sites.address
|
||||||
|
|||||||
@@ -81,11 +81,9 @@ const updateSiteResourceSchema = z
|
|||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
if (
|
if (
|
||||||
(data.mode === "host" ||
|
data.mode === "host" &&
|
||||||
data.mode == "http") &&
|
|
||||||
data.destination
|
data.destination
|
||||||
) {
|
) {
|
||||||
if (data.mode == "host") {
|
|
||||||
const isValidIP = z
|
const isValidIP = z
|
||||||
// .union([z.ipv4(), z.ipv6()])
|
// .union([z.ipv4(), z.ipv6()])
|
||||||
.union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere
|
.union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere
|
||||||
@@ -94,7 +92,6 @@ const updateSiteResourceSchema = z
|
|||||||
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 =
|
||||||
@@ -309,7 +306,6 @@ export async function updateSiteResource(
|
|||||||
|
|
||||||
let fullDomain: string | null = null;
|
let fullDomain: string | null = null;
|
||||||
let finalSubdomain: string | null = null;
|
let finalSubdomain: string | null = null;
|
||||||
let finalAlias = alias ? alias.trim() : null;
|
|
||||||
if (domainId && subdomain) {
|
if (domainId && subdomain) {
|
||||||
// Validate domain and construct full domain
|
// Validate domain and construct full domain
|
||||||
const domainResult = await validateAndConstructDomain(
|
const domainResult = await validateAndConstructDomain(
|
||||||
@@ -326,18 +322,32 @@ export async function updateSiteResource(
|
|||||||
|
|
||||||
fullDomain = domainResult.fullDomain;
|
fullDomain = domainResult.fullDomain;
|
||||||
finalSubdomain = domainResult.subdomain;
|
finalSubdomain = domainResult.subdomain;
|
||||||
finalAlias = fullDomain; // we will use the full domain as the alias for uniqueness checks and routing
|
|
||||||
|
// make sure the full domain is unique
|
||||||
|
const existingResource = await db
|
||||||
|
.select()
|
||||||
|
.from(siteResources)
|
||||||
|
.where(eq(siteResources.fullDomain, fullDomain));
|
||||||
|
|
||||||
|
if (existingResource.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
"Resource with that domain already exists"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the alias is unique within the org if provided
|
// make sure the alias is unique within the org if provided
|
||||||
if (finalAlias) {
|
if (alias) {
|
||||||
const [conflict] = await db
|
const [conflict] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(siteResources)
|
.from(siteResources)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(siteResources.orgId, existingSiteResource.orgId),
|
eq(siteResources.orgId, existingSiteResource.orgId),
|
||||||
eq(siteResources.alias, finalAlias.trim()),
|
eq(siteResources.alias, alias.trim()),
|
||||||
ne(siteResources.siteResourceId, siteResourceId) // exclude self
|
ne(siteResources.siteResourceId, siteResourceId) // exclude self
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -405,12 +415,13 @@ export async function updateSiteResource(
|
|||||||
destination,
|
destination,
|
||||||
destinationPort,
|
destinationPort,
|
||||||
enabled,
|
enabled,
|
||||||
alias: finalAlias,
|
alias: alias ? alias.trim() : null,
|
||||||
tcpPortRangeString,
|
tcpPortRangeString,
|
||||||
udpPortRangeString,
|
udpPortRangeString,
|
||||||
disableIcmp,
|
disableIcmp,
|
||||||
domainId,
|
domainId,
|
||||||
subdomain: finalSubdomain,
|
subdomain: finalSubdomain,
|
||||||
|
fullDomain,
|
||||||
...sshPamSet
|
...sshPamSet
|
||||||
})
|
})
|
||||||
.where(
|
.where(
|
||||||
@@ -507,18 +518,20 @@ export async function updateSiteResource(
|
|||||||
.set({
|
.set({
|
||||||
name: name,
|
name: name,
|
||||||
siteId: siteId,
|
siteId: siteId,
|
||||||
|
niceId: niceId,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
scheme,
|
scheme,
|
||||||
ssl,
|
ssl,
|
||||||
destination: destination,
|
destination: destination,
|
||||||
destinationPort: destinationPort,
|
destinationPort: destinationPort,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
alias: finalAlias,
|
alias: alias ? alias.trim() : null,
|
||||||
tcpPortRangeString: tcpPortRangeString,
|
tcpPortRangeString: tcpPortRangeString,
|
||||||
udpPortRangeString: udpPortRangeString,
|
udpPortRangeString: udpPortRangeString,
|
||||||
disableIcmp: disableIcmp,
|
disableIcmp: disableIcmp,
|
||||||
domainId,
|
domainId,
|
||||||
subdomain: finalSubdomain,
|
subdomain: finalSubdomain,
|
||||||
|
fullDomain,
|
||||||
...sshPamSet
|
...sshPamSet
|
||||||
})
|
})
|
||||||
.where(
|
.where(
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ export default async function ClientResourcesPage(
|
|||||||
udpPortRangeString: siteResource.udpPortRangeString || null,
|
udpPortRangeString: siteResource.udpPortRangeString || null,
|
||||||
disableIcmp: siteResource.disableIcmp || false,
|
disableIcmp: siteResource.disableIcmp || false,
|
||||||
authDaemonMode: siteResource.authDaemonMode ?? null,
|
authDaemonMode: siteResource.authDaemonMode ?? null,
|
||||||
authDaemonPort: siteResource.authDaemonPort ?? null
|
authDaemonPort: siteResource.authDaemonPort ?? null,
|
||||||
|
subdomain: siteResource.subdomain ?? null,
|
||||||
|
domainId: siteResource.domainId ?? null,
|
||||||
|
fullDomain: siteResource.fullDomain ?? null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ export type InternalResourceRow = {
|
|||||||
disableIcmp: boolean;
|
disableIcmp: boolean;
|
||||||
authDaemonMode?: "site" | "remote" | null;
|
authDaemonMode?: "site" | "remote" | null;
|
||||||
authDaemonPort?: number | null;
|
authDaemonPort?: number | null;
|
||||||
|
subdomain?: string | null;
|
||||||
|
domainId?: string | null;
|
||||||
|
fullDomain?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function resolveHttpHttpsDisplayPort(
|
function resolveHttpHttpsDisplayPort(
|
||||||
@@ -313,8 +316,8 @@ export default function ClientResourcesTable({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (resourceRow.mode === "http" && resourceRow.alias) {
|
if (resourceRow.mode === "http") {
|
||||||
const url = `${resourceRow.ssl ? "https" : "http"}://${resourceRow.alias}`;
|
const url = `${resourceRow.ssl ? "https" : "http"}://${resourceRow.fullDomain}`;
|
||||||
return (
|
return (
|
||||||
<CopyToClipboard
|
<CopyToClipboard
|
||||||
text={url}
|
text={url}
|
||||||
|
|||||||
@@ -75,24 +75,34 @@ export default function CreateInternalResourceDialog({
|
|||||||
...(data.mode === "http" && {
|
...(data.mode === "http" && {
|
||||||
scheme: data.scheme,
|
scheme: data.scheme,
|
||||||
ssl: data.ssl ?? false,
|
ssl: data.ssl ?? false,
|
||||||
destinationPort: data.httpHttpsPort ?? undefined
|
destinationPort: data.httpHttpsPort ?? undefined,
|
||||||
}),
|
domainId: data.httpConfigDomainId
|
||||||
alias:
|
? data.httpConfigDomainId
|
||||||
data.alias &&
|
|
||||||
typeof data.alias === "string" &&
|
|
||||||
data.alias.trim()
|
|
||||||
? data.alias
|
|
||||||
: undefined,
|
: undefined,
|
||||||
tcpPortRangeString: data.tcpPortRangeString,
|
subdomain: data.httpConfigSubdomain
|
||||||
udpPortRangeString: data.udpPortRangeString,
|
? data.httpConfigSubdomain
|
||||||
disableIcmp: data.disableIcmp ?? false,
|
: undefined
|
||||||
...(data.authDaemonMode != null && {
|
|
||||||
authDaemonMode: data.authDaemonMode
|
|
||||||
}),
|
}),
|
||||||
...(data.authDaemonMode === "remote" &&
|
...(data.mode === "host" && {
|
||||||
data.authDaemonPort != null && {
|
alias:
|
||||||
authDaemonPort: data.authDaemonPort
|
data.alias &&
|
||||||
|
typeof data.alias === "string" &&
|
||||||
|
data.alias.trim()
|
||||||
|
? data.alias
|
||||||
|
: undefined,
|
||||||
|
...(data.authDaemonMode != null && {
|
||||||
|
authDaemonMode: data.authDaemonMode
|
||||||
}),
|
}),
|
||||||
|
...(data.authDaemonMode === "remote" &&
|
||||||
|
data.authDaemonPort != null && {
|
||||||
|
authDaemonPort: data.authDaemonPort
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
...((data.mode === "host" || data.mode == "cidr") && {
|
||||||
|
tcpPortRangeString: data.tcpPortRangeString,
|
||||||
|
udpPortRangeString: data.udpPortRangeString,
|
||||||
|
disableIcmp: data.disableIcmp ?? false
|
||||||
|
}),
|
||||||
roleIds: data.roles
|
roleIds: data.roles
|
||||||
? data.roles.map((r) => parseInt(r.id))
|
? data.roles.map((r) => parseInt(r.id))
|
||||||
: [],
|
: [],
|
||||||
|
|||||||
@@ -77,22 +77,28 @@ export default function EditInternalResourceDialog({
|
|||||||
...(data.mode === "http" && {
|
...(data.mode === "http" && {
|
||||||
scheme: data.scheme,
|
scheme: data.scheme,
|
||||||
ssl: data.ssl ?? false,
|
ssl: data.ssl ?? false,
|
||||||
destinationPort: data.httpHttpsPort ?? null
|
destinationPort: data.httpHttpsPort ?? null,
|
||||||
|
domainId: data.httpConfigDomainId ? data.httpConfigDomainId : undefined,
|
||||||
|
subdomain: data.httpConfigSubdomain ? data.httpConfigSubdomain : undefined
|
||||||
}),
|
}),
|
||||||
alias:
|
...(data.mode === "host" && {
|
||||||
data.alias &&
|
alias:
|
||||||
typeof data.alias === "string" &&
|
data.alias &&
|
||||||
data.alias.trim()
|
typeof data.alias === "string" &&
|
||||||
? data.alias
|
data.alias.trim()
|
||||||
: null,
|
? data.alias
|
||||||
tcpPortRangeString: data.tcpPortRangeString,
|
: null,
|
||||||
udpPortRangeString: data.udpPortRangeString,
|
...(data.authDaemonMode != null && {
|
||||||
disableIcmp: data.disableIcmp ?? false,
|
authDaemonMode: data.authDaemonMode
|
||||||
...(data.authDaemonMode != null && {
|
}),
|
||||||
authDaemonMode: data.authDaemonMode
|
...(data.authDaemonMode === "remote" && {
|
||||||
|
authDaemonPort: data.authDaemonPort || null
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
...(data.authDaemonMode === "remote" && {
|
...((data.mode === "host" || data.mode === "cidr") && {
|
||||||
authDaemonPort: data.authDaemonPort || null
|
tcpPortRangeString: data.tcpPortRangeString,
|
||||||
|
udpPortRangeString: data.udpPortRangeString,
|
||||||
|
disableIcmp: data.disableIcmp ?? false
|
||||||
}),
|
}),
|
||||||
roleIds: (data.roles || []).map((r) => parseInt(r.id)),
|
roleIds: (data.roles || []).map((r) => parseInt(r.id)),
|
||||||
userIds: (data.users || []).map((u) => u.id),
|
userIds: (data.users || []).map((u) => u.id),
|
||||||
|
|||||||
@@ -146,9 +146,9 @@ export type InternalResourceData = {
|
|||||||
httpHttpsPort?: number | null;
|
httpHttpsPort?: number | null;
|
||||||
scheme?: "http" | "https" | null;
|
scheme?: "http" | "https" | null;
|
||||||
ssl?: boolean;
|
ssl?: boolean;
|
||||||
httpConfigSubdomain?: string | null;
|
subdomain?: string | null;
|
||||||
httpConfigDomainId?: string | null;
|
domainId?: string | null;
|
||||||
httpConfigFullDomain?: string | null;
|
fullDomain?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const tagSchema = z.object({ id: z.string(), text: z.string() });
|
const tagSchema = z.object({ id: z.string(), text: z.string() });
|
||||||
@@ -479,9 +479,9 @@ export function InternalResourceForm({
|
|||||||
httpHttpsPort: resource.httpHttpsPort ?? null,
|
httpHttpsPort: resource.httpHttpsPort ?? null,
|
||||||
scheme: resource.scheme ?? "http",
|
scheme: resource.scheme ?? "http",
|
||||||
ssl: resource.ssl ?? false,
|
ssl: resource.ssl ?? false,
|
||||||
httpConfigSubdomain: resource.httpConfigSubdomain ?? null,
|
httpConfigSubdomain: resource.subdomain ?? null,
|
||||||
httpConfigDomainId: resource.httpConfigDomainId ?? null,
|
httpConfigDomainId: resource.domainId ?? null,
|
||||||
httpConfigFullDomain: resource.httpConfigFullDomain ?? null,
|
httpConfigFullDomain: resource.fullDomain ?? null,
|
||||||
niceId: resource.niceId,
|
niceId: resource.niceId,
|
||||||
roles: [],
|
roles: [],
|
||||||
users: [],
|
users: [],
|
||||||
@@ -582,9 +582,9 @@ export function InternalResourceForm({
|
|||||||
httpHttpsPort: resource.httpHttpsPort ?? null,
|
httpHttpsPort: resource.httpHttpsPort ?? null,
|
||||||
scheme: resource.scheme ?? "http",
|
scheme: resource.scheme ?? "http",
|
||||||
ssl: resource.ssl ?? false,
|
ssl: resource.ssl ?? false,
|
||||||
httpConfigSubdomain: resource.httpConfigSubdomain ?? null,
|
httpConfigSubdomain: resource.subdomain ?? null,
|
||||||
httpConfigDomainId: resource.httpConfigDomainId ?? null,
|
httpConfigDomainId: resource.domainId ?? null,
|
||||||
httpConfigFullDomain: resource.httpConfigFullDomain ?? null,
|
httpConfigFullDomain: resource.fullDomain ?? null,
|
||||||
tcpPortRangeString: resource.tcpPortRangeString ?? "*",
|
tcpPortRangeString: resource.tcpPortRangeString ?? "*",
|
||||||
udpPortRangeString: resource.udpPortRangeString ?? "*",
|
udpPortRangeString: resource.udpPortRangeString ?? "*",
|
||||||
disableIcmp: resource.disableIcmp ?? false,
|
disableIcmp: resource.disableIcmp ?? false,
|
||||||
@@ -1023,7 +1023,6 @@ export function InternalResourceForm({
|
|||||||
"httpConfigFullDomain",
|
"httpConfigFullDomain",
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
form.setValue("alias", null);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
form.setValue(
|
form.setValue(
|
||||||
@@ -1038,7 +1037,6 @@ export function InternalResourceForm({
|
|||||||
"httpConfigFullDomain",
|
"httpConfigFullDomain",
|
||||||
res.fullDomain
|
res.fullDomain
|
||||||
);
|
);
|
||||||
form.setValue("alias", res.fullDomain);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
Reference in New Issue
Block a user