fix(dcrouter): persist proxy certificate validity dates and improve certificate status initialization

This commit is contained in:
2026-02-16 02:50:25 +00:00
parent 4e32745a8f
commit de0b7d1fe0
7 changed files with 78 additions and 29 deletions

View File

@@ -445,8 +445,8 @@ export class DcRouter {
if (routes.length > 0 || this.options.smartProxyConfig) {
console.log('Setting up SmartProxy with combined configuration');
// Track domains loaded from cert store so we can populate certificateStatusMap after start
const loadedCertDomains: string[] = [];
// Track cert entries loaded from cert store so we can populate certificateStatusMap after start
const loadedCertEntries: Array<{domain: string; publicKey: string; validUntil?: number; validFrom?: number}> = [];
// Create SmartProxy configuration
const smartProxyConfig: plugins.smartproxy.ISmartProxyOptions = {
@@ -461,14 +461,21 @@ export class DcRouter {
const data = await this.storageManager.getJSON(key);
if (data) {
certs.push(data);
loadedCertDomains.push(data.domain);
loadedCertEntries.push({ domain: data.domain, publicKey: data.publicKey, validUntil: data.validUntil, validFrom: data.validFrom });
}
}
return certs;
},
save: async (domain: string, publicKey: string, privateKey: string, ca?: string) => {
let validUntil: number | undefined;
let validFrom: number | undefined;
try {
const x509 = new plugins.crypto.X509Certificate(publicKey);
validUntil = new Date(x509.validTo).getTime();
validFrom = new Date(x509.validFrom).getTime();
} catch { /* PEM parsing failed */ }
await this.storageManager.setJSON(`/proxy-certs/${domain}`, {
domain, publicKey, privateKey, ca,
domain, publicKey, privateKey, ca, validUntil, validFrom,
});
},
remove: async (domain: string) => {
@@ -587,22 +594,46 @@ export class DcRouter {
console.log('[DcRouter] SmartProxy started successfully');
// Populate certificateStatusMap for certs loaded from store at startup
for (const domain of loadedCertDomains) {
if (!this.certificateStatusMap.has(domain)) {
const routeNames = this.findRouteNamesForDomain(domain);
for (const entry of loadedCertEntries) {
if (!this.certificateStatusMap.has(entry.domain)) {
const routeNames = this.findRouteNamesForDomain(entry.domain);
let expiryDate: string | undefined;
let issuedAt: string | undefined;
try {
const cleanDomain = domain.replace(/^\*\.?/, '');
const certMeta = await this.storageManager.getJSON(`/certs/${cleanDomain}`);
if (certMeta?.validUntil) {
expiryDate = new Date(certMeta.validUntil).toISOString();
}
if (certMeta?.created) {
issuedAt = new Date(certMeta.created).toISOString();
}
} catch { /* no metadata available */ }
this.certificateStatusMap.set(domain, {
// Use validUntil/validFrom from stored proxy-certs data if available
if (entry.validUntil) {
expiryDate = new Date(entry.validUntil).toISOString();
}
if (entry.validFrom) {
issuedAt = new Date(entry.validFrom).toISOString();
}
// Try SmartAcme /certs/ metadata as secondary source
if (!expiryDate) {
try {
const cleanDomain = entry.domain.replace(/^\*\.?/, '');
const certMeta = await this.storageManager.getJSON(`/certs/${cleanDomain}`);
if (certMeta?.validUntil) {
expiryDate = new Date(certMeta.validUntil).toISOString();
}
if (certMeta?.created && !issuedAt) {
issuedAt = new Date(certMeta.created).toISOString();
}
} catch { /* no metadata available */ }
}
// Fallback: parse X509 from PEM to get expiry
if (!expiryDate && entry.publicKey) {
try {
const x509 = new plugins.crypto.X509Certificate(entry.publicKey);
expiryDate = new Date(x509.validTo).toISOString();
if (!issuedAt) {
issuedAt = new Date(x509.validFrom).toISOString();
}
} catch { /* PEM parsing failed */ }
}
this.certificateStatusMap.set(entry.domain, {
status: 'valid',
routeNames,
expiryDate,
@@ -611,8 +642,8 @@ export class DcRouter {
});
}
}
if (loadedCertDomains.length > 0) {
console.log(`[DcRouter] Populated certificate status for ${loadedCertDomains.length} store-loaded domain(s)`);
if (loadedCertEntries.length > 0) {
console.log(`[DcRouter] Populated certificate status for ${loadedCertEntries.length} store-loaded domain(s)`);
}
console.log(`SmartProxy started with ${routes.length} routes`);