Merge branch 'dev' into distribution

This commit is contained in:
miloschwartz
2025-10-13 11:06:14 -07:00
85 changed files with 906 additions and 1639 deletions

View File

@@ -97,20 +97,4 @@ export async function getValidCertificatesForDomains(
});
return validCertsDecrypted;
}
export async function getValidCertificatesForDomainsHybrid(
domains: Set<string>
): Promise<
Array<{
id: number;
domain: string;
wildcard: boolean | null;
certFile: string | null;
keyFile: string | null;
expiresAt: number | null;
updatedAt?: number | null;
}>
> {
return []; // stub
}
}

View File

@@ -146,6 +146,10 @@ export class PrivateConfig {
if (parsedPrivateConfig.stripe?.s3Region) {
process.env.S3_REGION = parsedPrivateConfig.stripe.s3Region;
}
if (parsedPrivateConfig.flags?.generate_own_certificates) {
process.env.GENERATE_OWN_CERTIFICATES =
parsedPrivateConfig.flags.generate_own_certificates.toString();
}
}
this.rawPrivateConfig = parsedPrivateConfig;

View File

@@ -12,7 +12,7 @@
*/
import logger from "@server/logger";
import redisManager from "@server/private/lib/redis";
import redisManager from "#private/lib/redis";
import { build } from "@server/build";
// Rate limiting configuration

View File

@@ -17,7 +17,7 @@ import { MemoryStore, Store } from "express-rate-limit";
import RedisStore from "#private/lib/redisStore";
export function createStore(): Store {
if (build != "oss" && privateConfig.getRawPrivateConfig().flags?.enable_redis) {
if (build != "oss" && privateConfig.getRawPrivateConfig().flags.enable_redis) {
const rateLimitStore: Store = new RedisStore({
prefix: "api-rate-limit", // Optional: customize Redis key prefix
skipFailedRequests: true, // Don't count failed requests

View File

@@ -20,15 +20,18 @@ import { build } from "@server/build";
const portSchema = z.number().positive().gt(0).lte(65535);
export const privateConfigSchema = z
.object({
app: z.object({
export const privateConfigSchema = z.object({
app: z
.object({
region: z.string().optional().default("default"),
base_domain: z.string().optional()
}).optional().default({
})
.optional()
.default({
region: "default"
}),
server: z.object({
server: z
.object({
encryption_key_path: z
.string()
.optional()
@@ -37,125 +40,132 @@ export const privateConfigSchema = z
resend_api_key: z.string().optional(),
reo_client_id: z.string().optional(),
fossorial_api_key: z.string().optional()
}).optional().default({
})
.optional()
.default({
encryption_key_path: "./config/encryption.pem"
}),
redis: z
.object({
host: z.string(),
port: portSchema,
password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0),
replicas: z
.array(
z.object({
host: z.string(),
port: portSchema,
password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0)
redis: z
.object({
host: z.string(),
port: portSchema,
password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0),
replicas: z
.array(
z.object({
host: z.string(),
port: portSchema,
password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0)
})
)
.optional()
// tls: z
// .object({
// reject_unauthorized: z
// .boolean()
// .optional()
// .default(true)
// })
// .optional()
})
.optional(),
gerbil: z
.object({
local_exit_node_reachable_at: z
.string()
.optional()
.default("http://gerbil:3003")
})
.optional()
.default({}),
flags: z
.object({
enable_redis: z.boolean().optional().default(false),
generate_own_certificates: z.boolean().optional().default(false)
})
.optional()
.default({}),
branding: z
.object({
app_name: z.string().optional(),
background_image_path: z.string().optional(),
colors: z
.object({
light: colorsSchema.optional(),
dark: colorsSchema.optional()
})
.optional(),
logo: z
.object({
light_path: z.string().optional(),
dark_path: z.string().optional(),
auth_page: z
.object({
width: z.number().optional(),
height: z.number().optional()
})
)
.optional()
// tls: z
// .object({
// reject_unauthorized: z
// .boolean()
// .optional()
// .default(true)
// })
// .optional()
})
.optional(),
gerbil: z
.object({
local_exit_node_reachable_at: z.string().optional().default("http://gerbil:3003")
})
.optional()
.default({}),
flags: z
.object({
enable_redis: z.boolean().optional(),
})
.optional(),
branding: z
.object({
app_name: z.string().optional(),
background_image_path: z.string().optional(),
colors: z
.object({
light: colorsSchema.optional(),
dark: colorsSchema.optional()
})
.optional(),
logo: z
.object({
light_path: z.string().optional(),
dark_path: z.string().optional(),
auth_page: z
.object({
width: z.number().optional(),
height: z.number().optional()
})
.optional(),
navbar: z
.object({
width: z.number().optional(),
height: z.number().optional()
})
.optional()
})
.optional(),
favicon_path: z.string().optional(),
footer: z
.array(
z.object({
text: z.string(),
href: z.string().optional()
.optional(),
navbar: z
.object({
width: z.number().optional(),
height: z.number().optional()
})
)
.optional(),
login_page: z
.object({
subtitle_text: z.string().optional(),
title_text: z.string().optional()
.optional()
})
.optional(),
favicon_path: z.string().optional(),
footer: z
.array(
z.object({
text: z.string(),
href: z.string().optional()
})
.optional(),
signup_page: z
.object({
subtitle_text: z.string().optional(),
title_text: z.string().optional()
})
.optional(),
resource_auth_page: z
.object({
show_logo: z.boolean().optional(),
hide_powered_by: z.boolean().optional(),
title_text: z.string().optional(),
subtitle_text: z.string().optional()
})
.optional(),
emails: z
.object({
signature: z.string().optional(),
colors: z
.object({
primary: z.string().optional()
})
.optional()
})
.optional()
})
.optional(),
stripe: z
.object({
secret_key: z.string(),
webhook_secret: z.string(),
s3Bucket: z.string(),
s3Region: z.string().default("us-east-1"),
localFilePath: z.string()
})
.optional(),
});
)
.optional(),
login_page: z
.object({
subtitle_text: z.string().optional(),
title_text: z.string().optional()
})
.optional(),
signup_page: z
.object({
subtitle_text: z.string().optional(),
title_text: z.string().optional()
})
.optional(),
resource_auth_page: z
.object({
show_logo: z.boolean().optional(),
hide_powered_by: z.boolean().optional(),
title_text: z.string().optional(),
subtitle_text: z.string().optional()
})
.optional(),
emails: z
.object({
signature: z.string().optional(),
colors: z
.object({
primary: z.string().optional()
})
.optional()
})
.optional()
})
.optional(),
stripe: z
.object({
secret_key: z.string(),
webhook_secret: z.string(),
s3Bucket: z.string(),
s3Region: z.string().default("us-east-1"),
localFilePath: z.string()
})
.optional()
});
export function readPrivateConfigFile() {
if (build == "oss") {
@@ -186,9 +196,7 @@ export function readPrivateConfigFile() {
}
if (!environment) {
throw new Error(
"No private configuration file found."
);
throw new Error("No private configuration file found.");
}
return environment;

View File

@@ -46,7 +46,7 @@ class RedisManager {
this.isEnabled = false;
return;
}
this.isEnabled = privateConfig.getRawPrivateConfig().flags?.enable_redis || false;
this.isEnabled = privateConfig.getRawPrivateConfig().flags.enable_redis || false;
if (this.isEnabled) {
this.initializeClients();
}

View File

@@ -14,10 +14,10 @@
import Stripe from "stripe";
import privateConfig from "#private/lib/config";
import logger from "@server/logger";
import { build } from "@server/build";
import { noop } from "@server/lib/billing/usageService";
let stripe: Stripe | undefined = undefined;
if (build == "saas") {
if (!noop()) {
const stripeApiKey = privateConfig.getRawPrivateConfig().stripe?.secret_key;
if (!stripeApiKey) {
logger.error("Stripe secret key is not configured");

View File

@@ -21,11 +21,10 @@ import {
} from "@server/db";
import { and, eq, inArray, or, isNull, ne, isNotNull, desc } from "drizzle-orm";
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import config from "@server/lib/config";
import { orgs, resources, sites, Target, targets } from "@server/db";
import { build } from "@server/build";
import { sanitize } from "@server/lib/traefik/utils";
import privateConfig from "#private/lib/config";
const redirectHttpsMiddlewareName = "redirect-to-https";
const redirectToRootMiddlewareName = "redirect-to-root";
@@ -79,7 +78,7 @@ export async function getTraefikConfig(
path: targets.path,
pathMatchType: targets.pathMatchType,
priority: targets.priority,
// Site fields
siteId: sites.siteId,
siteType: sites.type,
@@ -234,12 +233,13 @@ export async function getTraefikConfig(
continue;
}
if (resource.certificateStatus !== "valid") {
logger.debug(
`Resource ${resource.resourceId} has certificate stats ${resource.certificateStats}`
);
continue;
}
// TODO: for now dont filter it out because if you have multiple domain ids and one is failed it causes all of them to fail
// if (resource.certificateStatus !== "valid" && privateConfig.getRawPrivateConfig().flags.generate_own_certificates) {
// logger.debug(
// `Resource ${resource.resourceId} has certificate stats ${resource.certificateStats}`
// );
// continue;
// }
// add routers and services empty objects if they don't exist
if (!config_output.http.routers) {
@@ -264,18 +264,21 @@ export async function getTraefikConfig(
const configDomain = config.getDomain(resource.domainId);
let certResolver: string, preferWildcardCert: boolean;
if (!configDomain) {
certResolver = config.getRawConfig().traefik.cert_resolver;
preferWildcardCert =
config.getRawConfig().traefik.prefer_wildcard_cert;
} else {
certResolver = configDomain.cert_resolver;
preferWildcardCert = configDomain.prefer_wildcard_cert;
}
let tls = {};
if (build == "oss") {
if (
!privateConfig.getRawPrivateConfig().flags
.generate_own_certificates
) {
let certResolver: string, preferWildcardCert: boolean;
if (!configDomain) {
certResolver = config.getRawConfig().traefik.cert_resolver;
preferWildcardCert =
config.getRawConfig().traefik.prefer_wildcard_cert;
} else {
certResolver = configDomain.cert_resolver;
preferWildcardCert = configDomain.prefer_wildcard_cert;
}
tls = {
certResolver: certResolver,
...(preferWildcardCert
@@ -419,7 +422,7 @@ export async function getTraefikConfig(
return (
(targets as TargetWithSite[])
.filter((target: TargetWithSite) => {
.filter((target: TargetWithSite) => {
if (!target.enabled) {
return false;
}
@@ -440,7 +443,7 @@ export async function getTraefikConfig(
) {
return false;
}
} else if (target.site.type === "newt") {
} else if (target.site.type === "newt") {
if (
!target.internalPort ||
!target.method ||
@@ -448,10 +451,10 @@ export async function getTraefikConfig(
) {
return false;
}
}
return true;
})
.map((target: TargetWithSite) => {
}
return true;
})
.map((target: TargetWithSite) => {
if (
target.site.type === "local" ||
target.site.type === "wireguard"
@@ -459,14 +462,14 @@ export async function getTraefikConfig(
return {
url: `${target.method}://${target.ip}:${target.port}`
};
} else if (target.site.type === "newt") {
} else if (target.site.type === "newt") {
const ip =
target.site.subnet!.split("/")[0];
return {
url: `${target.method}://${ip}:${target.internalPort}`
};
}
})
}
})
// filter out duplicates
.filter(
(v, i, a) =>
@@ -709,4 +712,4 @@ export async function getTraefikConfig(
}
return config_output;
}
}