Merge branch 'dev' into feat/login-page-customization

This commit is contained in:
miloschwartz
2025-12-17 11:41:17 -05:00
660 changed files with 19695 additions and 12803 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1708,4 +1708,4 @@
"Desert Box Turtle",
"African Striped Weasel"
]
}
}

View File

@@ -1,6 +1,7 @@
import { join } from "path";
import { readFileSync } from "fs";
import { db, resources, siteResources } from "@server/db";
import { clients, db, resources, siteResources } from "@server/db";
import { randomInt } from "crypto";
import { exitNodes, sites } from "@server/db";
import { eq, and } from "drizzle-orm";
import { __DIRNAME } from "@server/lib/consts";
@@ -15,6 +16,25 @@ if (!dev) {
}
export const names = JSON.parse(readFileSync(file, "utf-8"));
export async function getUniqueClientName(orgId: string): Promise<string> {
let loops = 0;
while (true) {
if (loops > 100) {
throw new Error("Could not generate a unique name");
}
const name = generateName();
const count = await db
.select({ niceId: clients.niceId, orgId: clients.orgId })
.from(clients)
.where(and(eq(clients.niceId, name), eq(clients.orgId, orgId)));
if (count.length === 0) {
return name;
}
loops++;
}
}
export async function getUniqueSiteName(orgId: string): Promise<string> {
let loops = 0;
while (true) {
@@ -46,11 +66,21 @@ export async function getUniqueResourceName(orgId: string): Promise<string> {
db
.select({ niceId: resources.niceId, orgId: resources.orgId })
.from(resources)
.where(and(eq(resources.niceId, name), eq(resources.orgId, orgId))),
.where(
and(eq(resources.niceId, name), eq(resources.orgId, orgId))
),
db
.select({ niceId: siteResources.niceId, orgId: siteResources.orgId })
.select({
niceId: siteResources.niceId,
orgId: siteResources.orgId
})
.from(siteResources)
.where(and(eq(siteResources.niceId, name), eq(siteResources.orgId, orgId)))
.where(
and(
eq(siteResources.niceId, name),
eq(siteResources.orgId, orgId)
)
)
]);
if (resourceCount.length === 0 && siteResourceCount.length === 0) {
return name;
@@ -59,7 +89,9 @@ export async function getUniqueResourceName(orgId: string): Promise<string> {
}
}
export async function getUniqueSiteResourceName(orgId: string): Promise<string> {
export async function getUniqueSiteResourceName(
orgId: string
): Promise<string> {
let loops = 0;
while (true) {
if (loops > 100) {
@@ -71,11 +103,21 @@ export async function getUniqueSiteResourceName(orgId: string): Promise<string>
db
.select({ niceId: resources.niceId, orgId: resources.orgId })
.from(resources)
.where(and(eq(resources.niceId, name), eq(resources.orgId, orgId))),
.where(
and(eq(resources.niceId, name), eq(resources.orgId, orgId))
),
db
.select({ niceId: siteResources.niceId, orgId: siteResources.orgId })
.select({
niceId: siteResources.niceId,
orgId: siteResources.orgId
})
.from(siteResources)
.where(and(eq(siteResources.niceId, name), eq(siteResources.orgId, orgId)))
.where(
and(
eq(siteResources.niceId, name),
eq(siteResources.orgId, orgId)
)
)
]);
if (resourceCount.length === 0 && siteResourceCount.length === 0) {
return name;
@@ -86,9 +128,7 @@ export async function getUniqueSiteResourceName(orgId: string): Promise<string>
export async function getUniqueExitNodeEndpointName(): Promise<string> {
let loops = 0;
const count = await db
.select()
.from(exitNodes);
const count = await db.select().from(exitNodes);
while (true) {
if (loops > 100) {
throw new Error("Could not generate a unique name");
@@ -107,14 +147,11 @@ export async function getUniqueExitNodeEndpointName(): Promise<string> {
}
}
export function generateName(): string {
const name = (
names.descriptors[
Math.floor(Math.random() * names.descriptors.length)
] +
names.descriptors[randomInt(names.descriptors.length)] +
"-" +
names.animals[Math.floor(Math.random() * names.animals.length)]
names.animals[randomInt(names.animals.length)]
)
.toLowerCase()
.replace(/\s/g, "-");

View File

@@ -6,28 +6,28 @@ import { withReplicas } from "drizzle-orm/pg-core";
function createDb() {
const config = readConfigFile();
if (!config.postgres) {
// check the environment variables for postgres config
if (process.env.POSTGRES_CONNECTION_STRING) {
config.postgres = {
connection_string: process.env.POSTGRES_CONNECTION_STRING
};
if (process.env.POSTGRES_REPLICA_CONNECTION_STRINGS) {
const replicas =
process.env.POSTGRES_REPLICA_CONNECTION_STRINGS.split(
","
).map((conn) => ({
// check the environment variables for postgres config first before the config file
if (process.env.POSTGRES_CONNECTION_STRING) {
config.postgres = {
connection_string: process.env.POSTGRES_CONNECTION_STRING
};
if (process.env.POSTGRES_REPLICA_CONNECTION_STRINGS) {
const replicas =
process.env.POSTGRES_REPLICA_CONNECTION_STRINGS.split(",").map(
(conn) => ({
connection_string: conn.trim()
}));
config.postgres.replicas = replicas;
}
} else {
throw new Error(
"Postgres configuration is missing in the configuration file."
);
})
);
config.postgres.replicas = replicas;
}
}
if (!config.postgres) {
throw new Error(
"Postgres configuration is missing in the configuration file."
);
}
const connectionString = config.postgres?.connection_string;
const replicaConnections = config.postgres?.replicas || [];
@@ -51,7 +51,7 @@ function createDb() {
if (!replicaConnections.length) {
replicas.push(
DrizzlePostgres(primaryPool, {
logger: process.env.NODE_ENV === "development"
logger: process.env.QUERY_LOGGING == "true"
})
);
} else {
@@ -65,7 +65,7 @@ function createDb() {
});
replicas.push(
DrizzlePostgres(replicaPool, {
logger: process.env.NODE_ENV === "development"
logger: process.env.QUERY_LOGGING == "true"
})
);
}
@@ -73,7 +73,7 @@ function createDb() {
return withReplicas(
DrizzlePostgres(primaryPool, {
logger: process.env.QUERY_LOGGING === "true"
logger: process.env.QUERY_LOGGING == "true"
}),
replicas as any
);

View File

@@ -47,13 +47,13 @@ export const orgs = pgTable("orgs", {
requireTwoFactor: boolean("requireTwoFactor"),
maxSessionLengthHours: integer("maxSessionLengthHours"),
passwordExpiryDays: integer("passwordExpiryDays"),
settingsLogRetentionDaysRequest: integer("settingsLogRetentionDaysRequest") // where 0 = dont keep logs and -1 = keep forever
settingsLogRetentionDaysRequest: integer("settingsLogRetentionDaysRequest") // where 0 = dont keep logs and -1 = keep forever, and 9001 = end of the following year
.notNull()
.default(7),
settingsLogRetentionDaysAccess: integer("settingsLogRetentionDaysAccess")
settingsLogRetentionDaysAccess: integer("settingsLogRetentionDaysAccess") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0),
settingsLogRetentionDaysAction: integer("settingsLogRetentionDaysAction")
settingsLogRetentionDaysAction: integer("settingsLogRetentionDaysAction") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0)
});
@@ -178,7 +178,7 @@ export const targetHealthCheck = pgTable("targetHealthCheck", {
hcMethod: varchar("hcMethod").default("GET"),
hcStatus: integer("hcStatus"), // http code
hcHealth: text("hcHealth").default("unknown"), // "unknown", "healthy", "unhealthy"
hcTlsServerName: text("hcTlsServerName"),
hcTlsServerName: text("hcTlsServerName")
});
export const exitNodes = pgTable("exitNodes", {
@@ -214,7 +214,10 @@ export const siteResources = pgTable("siteResources", {
destination: varchar("destination").notNull(), // ip, cidr, hostname; validate against the mode
enabled: boolean("enabled").notNull().default(true),
alias: varchar("alias"),
aliasAddress: varchar("aliasAddress")
aliasAddress: varchar("aliasAddress"),
tcpPortRangeString: varchar("tcpPortRangeString"),
udpPortRangeString: varchar("udpPortRangeString"),
disableIcmp: boolean("disableIcmp").notNull().default(false)
});
export const clientSiteResources = pgTable("clientSiteResources", {
@@ -645,6 +648,7 @@ export const clients = pgTable("clients", {
// optionally tied to a user and in this case delete when the user deletes
onDelete: "cascade"
}),
niceId: varchar("niceId").notNull(),
olmId: text("olmId"), // to lock it to a specific olm optionally
name: varchar("name").notNull(),
pubKey: varchar("pubKey"),

View File

@@ -52,10 +52,7 @@ export async function getResourceByDomain(
resourceHeaderAuth,
eq(resourceHeaderAuth.resourceId, resources.resourceId)
)
.innerJoin(
orgs,
eq(orgs.orgId, resources.orgId)
)
.innerJoin(orgs, eq(orgs.orgId, resources.orgId))
.where(eq(resources.fullDomain, domain))
.limit(1);

View File

@@ -8,7 +8,7 @@ const runMigrations = async () => {
console.log("Running migrations...");
try {
migrate(db as any, {
migrationsFolder: migrationsFolder,
migrationsFolder: migrationsFolder
});
console.log("Migrations completed successfully.");
} catch (error) {

View File

@@ -44,13 +44,13 @@ export const orgs = sqliteTable("orgs", {
requireTwoFactor: integer("requireTwoFactor", { mode: "boolean" }),
maxSessionLengthHours: integer("maxSessionLengthHours"), // hours
passwordExpiryDays: integer("passwordExpiryDays"), // days
settingsLogRetentionDaysRequest: integer("settingsLogRetentionDaysRequest") // where 0 = dont keep logs and -1 = keep forever
settingsLogRetentionDaysRequest: integer("settingsLogRetentionDaysRequest") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(7),
settingsLogRetentionDaysAccess: integer("settingsLogRetentionDaysAccess")
settingsLogRetentionDaysAccess: integer("settingsLogRetentionDaysAccess") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0),
settingsLogRetentionDaysAction: integer("settingsLogRetentionDaysAction")
settingsLogRetentionDaysAction: integer("settingsLogRetentionDaysAction") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0)
});
@@ -240,7 +240,10 @@ export const siteResources = sqliteTable("siteResources", {
destination: text("destination").notNull(), // ip, cidr, hostname
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
alias: text("alias"),
aliasAddress: text("aliasAddress")
aliasAddress: text("aliasAddress"),
tcpPortRangeString: text("tcpPortRangeString"),
udpPortRangeString: text("udpPortRangeString"),
disableIcmp: integer("disableIcmp", { mode: "boolean" })
});
export const clientSiteResources = sqliteTable("clientSiteResources", {
@@ -356,7 +359,7 @@ export const clients = sqliteTable("clients", {
// optionally tied to a user and in this case delete when the user deletes
onDelete: "cascade"
}),
niceId: text("niceId").notNull(),
name: text("name").notNull(),
pubKey: text("pubKey"),
olmId: text("olmId"), // to lock it to a specific olm optionally