mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-21 12:26:40 +00:00
Merge dev into fix/log-analytics-adjustments
This commit is contained in:
@@ -195,7 +195,9 @@ export class TraefikConfigManager {
|
||||
|
||||
state.set(domain, {
|
||||
exists: certExists && keyExists,
|
||||
lastModified: lastModified ? Math.floor(lastModified.getTime() / 1000) : null,
|
||||
lastModified: lastModified
|
||||
? Math.floor(lastModified.getTime() / 1000)
|
||||
: null,
|
||||
expiresAt,
|
||||
wildcard
|
||||
});
|
||||
@@ -464,7 +466,9 @@ export class TraefikConfigManager {
|
||||
config.getRawConfig().traefik.site_types,
|
||||
build == "oss", // filter out the namespace domains in open source
|
||||
build != "oss", // generate the login pages on the cloud and hybrid,
|
||||
build == "saas" ? false : config.getRawConfig().traefik.allow_raw_resources // dont allow raw resources on saas otherwise use config
|
||||
build == "saas"
|
||||
? false
|
||||
: config.getRawConfig().traefik.allow_raw_resources // dont allow raw resources on saas otherwise use config
|
||||
);
|
||||
|
||||
const domains = new Set<string>();
|
||||
@@ -786,29 +790,30 @@ export class TraefikConfigManager {
|
||||
"utf8"
|
||||
);
|
||||
|
||||
// Store the certificate expiry time
|
||||
if (cert.expiresAt) {
|
||||
const expiresAtPath = path.join(domainDir, ".expires_at");
|
||||
fs.writeFileSync(
|
||||
expiresAtPath,
|
||||
cert.expiresAt.toString(),
|
||||
"utf8"
|
||||
);
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`Certificate updated for domain: ${cert.domain}${cert.wildcard ? " (wildcard)" : ""}`
|
||||
);
|
||||
|
||||
// Update local state tracking
|
||||
this.lastLocalCertificateState.set(cert.domain, {
|
||||
exists: true,
|
||||
lastModified: Math.floor(Date.now() / 1000),
|
||||
expiresAt: cert.expiresAt,
|
||||
wildcard: cert.wildcard
|
||||
});
|
||||
}
|
||||
|
||||
// Always update expiry tracking when we fetch a certificate,
|
||||
// even if the cert content didn't change
|
||||
if (cert.expiresAt) {
|
||||
const expiresAtPath = path.join(domainDir, ".expires_at");
|
||||
fs.writeFileSync(
|
||||
expiresAtPath,
|
||||
cert.expiresAt.toString(),
|
||||
"utf8"
|
||||
);
|
||||
}
|
||||
|
||||
// Update local state tracking
|
||||
this.lastLocalCertificateState.set(cert.domain, {
|
||||
exists: true,
|
||||
lastModified: Math.floor(Date.now() / 1000),
|
||||
expiresAt: cert.expiresAt,
|
||||
wildcard: cert.wildcard
|
||||
});
|
||||
|
||||
// Always ensure the config entry exists and is up to date
|
||||
const certEntry = {
|
||||
certFile: certPath,
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from "./getTraefikConfig";
|
||||
export * from "./getTraefikConfig";
|
||||
|
||||
@@ -2,234 +2,249 @@ import { assertEquals } from "@test/assert";
|
||||
import { isDomainCoveredByWildcard } from "./TraefikConfigManager";
|
||||
|
||||
function runTests() {
|
||||
console.log('Running wildcard domain coverage tests...');
|
||||
|
||||
console.log("Running wildcard domain coverage tests...");
|
||||
|
||||
// Test case 1: Basic wildcard certificate at example.com
|
||||
const basicWildcardCerts = new Map([
|
||||
['example.com', { exists: true, wildcard: true }]
|
||||
["example.com", { exists: true, wildcard: true }]
|
||||
]);
|
||||
|
||||
|
||||
// Should match first-level subdomains
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('level1.example.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard("level1.example.com", basicWildcardCerts),
|
||||
true,
|
||||
'Wildcard cert at example.com should match level1.example.com'
|
||||
"Wildcard cert at example.com should match level1.example.com"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('api.example.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard("api.example.com", basicWildcardCerts),
|
||||
true,
|
||||
'Wildcard cert at example.com should match api.example.com'
|
||||
"Wildcard cert at example.com should match api.example.com"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('www.example.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard("www.example.com", basicWildcardCerts),
|
||||
true,
|
||||
'Wildcard cert at example.com should match www.example.com'
|
||||
"Wildcard cert at example.com should match www.example.com"
|
||||
);
|
||||
|
||||
|
||||
// Should match the root domain (exact match)
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('example.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard("example.com", basicWildcardCerts),
|
||||
true,
|
||||
'Wildcard cert at example.com should match example.com itself'
|
||||
"Wildcard cert at example.com should match example.com itself"
|
||||
);
|
||||
|
||||
|
||||
// Should NOT match second-level subdomains
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('level2.level1.example.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard(
|
||||
"level2.level1.example.com",
|
||||
basicWildcardCerts
|
||||
),
|
||||
false,
|
||||
'Wildcard cert at example.com should NOT match level2.level1.example.com'
|
||||
"Wildcard cert at example.com should NOT match level2.level1.example.com"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('deep.nested.subdomain.example.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard(
|
||||
"deep.nested.subdomain.example.com",
|
||||
basicWildcardCerts
|
||||
),
|
||||
false,
|
||||
'Wildcard cert at example.com should NOT match deep.nested.subdomain.example.com'
|
||||
"Wildcard cert at example.com should NOT match deep.nested.subdomain.example.com"
|
||||
);
|
||||
|
||||
|
||||
// Should NOT match different domains
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('test.otherdomain.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard("test.otherdomain.com", basicWildcardCerts),
|
||||
false,
|
||||
'Wildcard cert at example.com should NOT match test.otherdomain.com'
|
||||
"Wildcard cert at example.com should NOT match test.otherdomain.com"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('notexample.com', basicWildcardCerts),
|
||||
isDomainCoveredByWildcard("notexample.com", basicWildcardCerts),
|
||||
false,
|
||||
'Wildcard cert at example.com should NOT match notexample.com'
|
||||
"Wildcard cert at example.com should NOT match notexample.com"
|
||||
);
|
||||
|
||||
|
||||
// Test case 2: Multiple wildcard certificates
|
||||
const multipleWildcardCerts = new Map([
|
||||
['example.com', { exists: true, wildcard: true }],
|
||||
['test.org', { exists: true, wildcard: true }],
|
||||
['api.service.net', { exists: true, wildcard: true }]
|
||||
["example.com", { exists: true, wildcard: true }],
|
||||
["test.org", { exists: true, wildcard: true }],
|
||||
["api.service.net", { exists: true, wildcard: true }]
|
||||
]);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('app.example.com', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard("app.example.com", multipleWildcardCerts),
|
||||
true,
|
||||
'Should match subdomain of first wildcard cert'
|
||||
"Should match subdomain of first wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('staging.test.org', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard("staging.test.org", multipleWildcardCerts),
|
||||
true,
|
||||
'Should match subdomain of second wildcard cert'
|
||||
"Should match subdomain of second wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('v1.api.service.net', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard("v1.api.service.net", multipleWildcardCerts),
|
||||
true,
|
||||
'Should match subdomain of third wildcard cert'
|
||||
"Should match subdomain of third wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('deep.nested.api.service.net', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard(
|
||||
"deep.nested.api.service.net",
|
||||
multipleWildcardCerts
|
||||
),
|
||||
false,
|
||||
'Should NOT match multi-level subdomain of third wildcard cert'
|
||||
"Should NOT match multi-level subdomain of third wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
// Test exact domain matches for multiple certs
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('example.com', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard("example.com", multipleWildcardCerts),
|
||||
true,
|
||||
'Should match exact domain of first wildcard cert'
|
||||
"Should match exact domain of first wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('test.org', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard("test.org", multipleWildcardCerts),
|
||||
true,
|
||||
'Should match exact domain of second wildcard cert'
|
||||
"Should match exact domain of second wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('api.service.net', multipleWildcardCerts),
|
||||
isDomainCoveredByWildcard("api.service.net", multipleWildcardCerts),
|
||||
true,
|
||||
'Should match exact domain of third wildcard cert'
|
||||
"Should match exact domain of third wildcard cert"
|
||||
);
|
||||
|
||||
|
||||
// Test case 3: Non-wildcard certificates (should not match anything)
|
||||
const nonWildcardCerts = new Map([
|
||||
['example.com', { exists: true, wildcard: false }],
|
||||
['specific.domain.com', { exists: true, wildcard: false }]
|
||||
["example.com", { exists: true, wildcard: false }],
|
||||
["specific.domain.com", { exists: true, wildcard: false }]
|
||||
]);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('sub.example.com', nonWildcardCerts),
|
||||
isDomainCoveredByWildcard("sub.example.com", nonWildcardCerts),
|
||||
false,
|
||||
'Non-wildcard cert should not match subdomains'
|
||||
"Non-wildcard cert should not match subdomains"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('example.com', nonWildcardCerts),
|
||||
isDomainCoveredByWildcard("example.com", nonWildcardCerts),
|
||||
false,
|
||||
'Non-wildcard cert should not match even exact domain via this function'
|
||||
"Non-wildcard cert should not match even exact domain via this function"
|
||||
);
|
||||
|
||||
|
||||
// Test case 4: Non-existent certificates (should not match)
|
||||
const nonExistentCerts = new Map([
|
||||
['example.com', { exists: false, wildcard: true }],
|
||||
['missing.com', { exists: false, wildcard: true }]
|
||||
["example.com", { exists: false, wildcard: true }],
|
||||
["missing.com", { exists: false, wildcard: true }]
|
||||
]);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('sub.example.com', nonExistentCerts),
|
||||
isDomainCoveredByWildcard("sub.example.com", nonExistentCerts),
|
||||
false,
|
||||
'Non-existent wildcard cert should not match'
|
||||
"Non-existent wildcard cert should not match"
|
||||
);
|
||||
|
||||
|
||||
// Test case 5: Edge cases with special domain names
|
||||
const specialDomainCerts = new Map([
|
||||
['localhost', { exists: true, wildcard: true }],
|
||||
['127-0-0-1.nip.io', { exists: true, wildcard: true }],
|
||||
['xn--e1afmkfd.xn--p1ai', { exists: true, wildcard: true }] // IDN domain
|
||||
["localhost", { exists: true, wildcard: true }],
|
||||
["127-0-0-1.nip.io", { exists: true, wildcard: true }],
|
||||
["xn--e1afmkfd.xn--p1ai", { exists: true, wildcard: true }] // IDN domain
|
||||
]);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('app.localhost', specialDomainCerts),
|
||||
isDomainCoveredByWildcard("app.localhost", specialDomainCerts),
|
||||
true,
|
||||
'Should match subdomain of localhost wildcard'
|
||||
"Should match subdomain of localhost wildcard"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('test.127-0-0-1.nip.io', specialDomainCerts),
|
||||
isDomainCoveredByWildcard("test.127-0-0-1.nip.io", specialDomainCerts),
|
||||
true,
|
||||
'Should match subdomain of nip.io wildcard'
|
||||
"Should match subdomain of nip.io wildcard"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('sub.xn--e1afmkfd.xn--p1ai', specialDomainCerts),
|
||||
isDomainCoveredByWildcard(
|
||||
"sub.xn--e1afmkfd.xn--p1ai",
|
||||
specialDomainCerts
|
||||
),
|
||||
true,
|
||||
'Should match subdomain of IDN wildcard'
|
||||
"Should match subdomain of IDN wildcard"
|
||||
);
|
||||
|
||||
|
||||
// Test case 6: Empty input and edge cases
|
||||
const emptyCerts = new Map();
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('any.domain.com', emptyCerts),
|
||||
isDomainCoveredByWildcard("any.domain.com", emptyCerts),
|
||||
false,
|
||||
'Empty certificate map should not match any domain'
|
||||
"Empty certificate map should not match any domain"
|
||||
);
|
||||
|
||||
|
||||
// Test case 7: Domains with single character components
|
||||
const singleCharCerts = new Map([
|
||||
['a.com', { exists: true, wildcard: true }],
|
||||
['x.y.z', { exists: true, wildcard: true }]
|
||||
["a.com", { exists: true, wildcard: true }],
|
||||
["x.y.z", { exists: true, wildcard: true }]
|
||||
]);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('b.a.com', singleCharCerts),
|
||||
isDomainCoveredByWildcard("b.a.com", singleCharCerts),
|
||||
true,
|
||||
'Should match single character subdomain'
|
||||
"Should match single character subdomain"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('w.x.y.z', singleCharCerts),
|
||||
isDomainCoveredByWildcard("w.x.y.z", singleCharCerts),
|
||||
true,
|
||||
'Should match single character subdomain of multi-part domain'
|
||||
"Should match single character subdomain of multi-part domain"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('v.w.x.y.z', singleCharCerts),
|
||||
isDomainCoveredByWildcard("v.w.x.y.z", singleCharCerts),
|
||||
false,
|
||||
'Should NOT match multi-level subdomain of single char domain'
|
||||
"Should NOT match multi-level subdomain of single char domain"
|
||||
);
|
||||
|
||||
|
||||
// Test case 8: Domains with numbers and hyphens
|
||||
const numericCerts = new Map([
|
||||
['api-v2.service-1.com', { exists: true, wildcard: true }],
|
||||
['123.456.net', { exists: true, wildcard: true }]
|
||||
["api-v2.service-1.com", { exists: true, wildcard: true }],
|
||||
["123.456.net", { exists: true, wildcard: true }]
|
||||
]);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('staging.api-v2.service-1.com', numericCerts),
|
||||
isDomainCoveredByWildcard("staging.api-v2.service-1.com", numericCerts),
|
||||
true,
|
||||
'Should match subdomain with hyphens and numbers'
|
||||
"Should match subdomain with hyphens and numbers"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('test.123.456.net', numericCerts),
|
||||
isDomainCoveredByWildcard("test.123.456.net", numericCerts),
|
||||
true,
|
||||
'Should match subdomain with numeric components'
|
||||
"Should match subdomain with numeric components"
|
||||
);
|
||||
|
||||
|
||||
assertEquals(
|
||||
isDomainCoveredByWildcard('deep.staging.api-v2.service-1.com', numericCerts),
|
||||
isDomainCoveredByWildcard(
|
||||
"deep.staging.api-v2.service-1.com",
|
||||
numericCerts
|
||||
),
|
||||
false,
|
||||
'Should NOT match multi-level subdomain with hyphens and numbers'
|
||||
"Should NOT match multi-level subdomain with hyphens and numbers"
|
||||
);
|
||||
|
||||
console.log('All wildcard domain coverage tests passed!');
|
||||
|
||||
console.log("All wildcard domain coverage tests passed!");
|
||||
}
|
||||
|
||||
// Run all tests
|
||||
try {
|
||||
runTests();
|
||||
} catch (error) {
|
||||
console.error('Test failed:', error);
|
||||
console.error("Test failed:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -31,12 +31,17 @@ export function validatePathRewriteConfig(
|
||||
}
|
||||
|
||||
if (rewritePathType !== "stripPrefix") {
|
||||
if ((rewritePath && !rewritePathType) || (!rewritePath && rewritePathType)) {
|
||||
return { isValid: false, error: "Both rewritePath and rewritePathType must be specified together" };
|
||||
if (
|
||||
(rewritePath && !rewritePathType) ||
|
||||
(!rewritePath && rewritePathType)
|
||||
) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: "Both rewritePath and rewritePathType must be specified together"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!rewritePath || !rewritePathType) {
|
||||
return { isValid: true };
|
||||
}
|
||||
@@ -68,14 +73,14 @@ export function validatePathRewriteConfig(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Additional validation for stripPrefix
|
||||
if (rewritePathType === "stripPrefix") {
|
||||
if (pathMatchType !== "prefix") {
|
||||
logger.warn(`stripPrefix rewrite type is most effective with prefix path matching. Current match type: ${pathMatchType}`);
|
||||
logger.warn(
|
||||
`stripPrefix rewrite type is most effective with prefix path matching. Current match type: ${pathMatchType}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user