mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-01 23:59:09 +00:00
Merge branch 'main' into dev
This commit is contained in:
2
.github/workflows/cicd.yml
vendored
2
.github/workflows/cicd.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
name: Build and Release
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: amd64-runner
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
||||
20
Makefile
20
Makefile
@@ -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
3784
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user