Merge branch 'main' into dev

This commit is contained in:
Owen
2025-10-15 17:15:48 -07:00
7 changed files with 3449 additions and 459 deletions

View File

@@ -8,7 +8,7 @@ on:
jobs:
release:
name: Build and Release
runs-on: ubuntu-latest
runs-on: amd64-runner
steps:
- name: Checkout code

View File

@@ -2,7 +2,7 @@
major_tag := $(shell echo $(tag) | cut -d. -f1)
minor_tag := $(shell echo $(tag) | cut -d. -f1,2)
build-release:
build-release-arm:
@if [ -z "$(tag)" ]; then \
echo "Error: tag is required. Usage: make build-release tag=<tag>"; \
exit 1; \
@@ -25,6 +25,24 @@ build-release:
--tag fosrl/pangolin:postgresql-$(minor_tag) \
--tag fosrl/pangolin:postgresql-$(tag) \
--push .
docker buildx build \
--build-arg BUILD=enterprise
--build-arg DATABASE=sqlite \
--platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:ee-latest \
--tag fosrl/pangolin:ee-$(major_tag) \
--tag fosrl/pangolin:ee-$(minor_tag) \
--tag fosrl/pangolin:ee-$(tag) \
--push .
docker buildx build \
--build-arg BUILD=enterprise
--build-arg DATABASE=pg \
--platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:ee-postgresql-latest \
--tag fosrl/pangolin:ee-postgresql-$(major_tag) \
--tag fosrl/pangolin:ee-postgresql-$(minor_tag) \
--tag fosrl/pangolin:ee-postgresql-$(tag) \
--push .
build-arm:
docker buildx build --platform linux/arm64 -t fosrl/pangolin:latest .

3784
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,19 +17,28 @@ import { and, eq, isNotNull, or, inArray, sql } from "drizzle-orm";
import { decryptData } from "@server/lib/encryption";
import * as fs from "fs";
import NodeCache from "node-cache";
import logger from "@server/logger";
const encryptionKeyPath =
config.getRawPrivateConfig().server.encryption_key_path;
let encryptionKeyPath = "";
let encryptionKeyHex = "";
let encryptionKey: Buffer;
function loadEncryptData() {
if (encryptionKey) {
return; // already loaded
}
if (!fs.existsSync(encryptionKeyPath)) {
throw new Error(
"Encryption key file not found. Please generate one first."
);
encryptionKeyPath = config.getRawPrivateConfig().server.encryption_key_path;
if (!fs.existsSync(encryptionKeyPath)) {
throw new Error(
"Encryption key file not found. Please generate one first."
);
}
encryptionKeyHex = fs.readFileSync(encryptionKeyPath, "utf8").trim();
encryptionKey = Buffer.from(encryptionKeyHex, "hex");
}
const encryptionKeyHex = fs.readFileSync(encryptionKeyPath, "utf8").trim();
const encryptionKey = Buffer.from(encryptionKeyHex, "hex");
// Define the return type for clarity and type safety
export type CertificateResult = {
id: number;
@@ -49,6 +58,9 @@ export async function getValidCertificatesForDomains(
domains: Set<string>,
useCache: boolean = true
): Promise<Array<CertificateResult>> {
loadEncryptData(); // Ensure encryption key is loaded
const finalResults: CertificateResult[] = [];
const domainsToQuery = new Set<string>();
@@ -69,7 +81,8 @@ export async function getValidCertificatesForDomains(
// 2. If all domains were resolved from the cache, return early
if (domainsToQuery.size === 0) {
return decryptFinalResults(finalResults);
const decryptedResults = decryptFinalResults(finalResults);
return decryptedResults;
}
// 3. Prepare domains for the database query
@@ -126,23 +139,32 @@ export async function getValidCertificatesForDomains(
for (const domain of domainsToQuery) {
let foundCert: (typeof potentialCerts)[0] | undefined = undefined;
// Priority 1: Check for an exact match
// Priority 1: Check for an exact match (non-wildcard)
if (exactMatches.has(domain)) {
foundCert = exactMatches.get(domain);
}
// Priority 2: Check for a wildcard match on the parent domain
// Priority 2: Check for a wildcard certificate that matches the exact domain
else {
const parts = domain.split(".");
if (parts.length > 1) {
const parentDomain = parts.slice(1).join(".");
if (wildcardMatches.has(parentDomain)) {
foundCert = wildcardMatches.get(parentDomain);
if (wildcardMatches.has(domain)) {
foundCert = wildcardMatches.get(domain);
}
// Priority 3: Check for a wildcard match on the parent domain
else {
const parts = domain.split(".");
if (parts.length > 1) {
const parentDomain = parts.slice(1).join(".");
if (wildcardMatches.has(parentDomain)) {
foundCert = wildcardMatches.get(parentDomain);
}
}
}
}
// If a certificate was found, format it, add to results, and cache it
if (foundCert) {
logger.debug(
`Creating result cert for ${domain} using cert from ${foundCert.domain}`
);
const resultCert: CertificateResult = {
id: foundCert.certId,
domain: foundCert.domain, // The actual domain of the cert record
@@ -163,7 +185,8 @@ export async function getValidCertificatesForDomains(
}
}
return decryptFinalResults(finalResults);
const decryptedResults = decryptFinalResults(finalResults);
return decryptedResults;
}
function decryptFinalResults(

View File

@@ -172,6 +172,12 @@ export function readPrivateConfigFile() {
return {};
}
// test if the config file is there
if (!fs.existsSync(privateConfigFilePath1)) {
// load the default values of the zod schema and return those
return privateConfigSchema.parse({});
}
const loadConfig = (configPath: string) => {
try {
const yamlContent = fs.readFileSync(configPath, "utf8");

View File

@@ -224,6 +224,7 @@ export async function getTraefikConfig(
}
// get the valid certs for these domains
validCerts = await getValidCertificatesForDomains(domains, true); // we are caching here because this is called often
logger.debug(`Valid certs for domains: ${JSON.stringify(validCerts)}`);
}
const config_output: any = {

View File

@@ -292,11 +292,33 @@ hybridRouter.get(
}
);
let encryptionKeyPath = "";
let encryptionKeyHex = "";
let encryptionKey: Buffer;
function loadEncryptData() {
if (encryptionKey) {
return; // already loaded
}
encryptionKeyPath = privateConfig.getRawPrivateConfig().server.encryption_key_path;
if (!fs.existsSync(encryptionKeyPath)) {
throw new Error(
"Encryption key file not found. Please generate one first."
);
}
encryptionKeyHex = fs.readFileSync(encryptionKeyPath, "utf8").trim();
encryptionKey = Buffer.from(encryptionKeyHex, "hex");
}
// Get valid certificates for given domains (supports wildcard certs)
hybridRouter.get(
"/certificates/domains",
async (req: Request, res: Response, next: NextFunction) => {
try {
loadEncryptData(); // Ensure encryption key is loaded
const parsed = getCertificatesByDomainsQuerySchema.safeParse(
req.query
);
@@ -425,20 +447,6 @@ hybridRouter.get(
filtered.push(cert);
}
const encryptionKeyPath =
privateConfig.getRawPrivateConfig().server.encryption_key_path;
if (!fs.existsSync(encryptionKeyPath)) {
throw new Error(
"Encryption key file not found. Please generate one first."
);
}
const encryptionKeyHex = fs
.readFileSync(encryptionKeyPath, "utf8")
.trim();
const encryptionKey = Buffer.from(encryptionKeyHex, "hex");
const result = filtered.map((cert) => {
// Decrypt and save certificate file
const decryptedCert = decryptData(