From 121573de2fe486755e5ba213765f0c80cfd17441 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Mon, 16 Feb 2026 01:58:39 +0000 Subject: [PATCH] fix(certs): Populate certificate status for cert-store-loaded certificates after SmartProxy startup and check proxy-certs in opsserver certificate handler --- changelog.md | 7 ++++ package.json | 2 +- pnpm-lock.yaml | 10 ++--- ts/00_commitinfo_data.ts | 2 +- ts/classes.dcrouter.ts | 41 ++++++++++++++++++-- ts/opsserver/handlers/certificate.handler.ts | 10 ++++- ts_web/00_commitinfo_data.ts | 2 +- 7 files changed, 62 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index ac9b57a..9be8bb2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2026-02-16 - 6.2.2 - fix(certs) +Populate certificate status for cert-store-loaded certificates after SmartProxy startup and check proxy-certs in opsserver certificate handler + +- Track domains loaded from storageManager '/proxy-certs/' and populate certificateStatusMap with status, routeNames, expiryDate and issuedAt (when available) after SmartProxy starts +- Opsserver certificate handler now falls back to '/proxy-certs/{domain}' if '/certs/{cleanDomain}' is missing and marks cert-store-only entries as valid with issuer 'cert-store' +- Bump @push.rocks/smartproxy dependency from ^25.3.1 to ^25.4.0 + ## 2026-02-16 - 6.2.1 - fix(smartacme,storage) Respect wildcard domain requests when retrieving certificates and treat empty/whitespace storage values as null in getJSON diff --git a/package.json b/package.json index c054e2c..a0f4116 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@push.rocks/smartnetwork": "^4.4.0", "@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpromise": "^4.2.3", - "@push.rocks/smartproxy": "^25.3.1", + "@push.rocks/smartproxy": "^25.4.0", "@push.rocks/smartradius": "^1.1.1", "@push.rocks/smartrequest": "^5.0.1", "@push.rocks/smartrx": "^3.0.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a016952..6cfad29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,8 +75,8 @@ importers: specifier: ^4.2.3 version: 4.2.3 '@push.rocks/smartproxy': - specifier: ^25.3.1 - version: 25.3.1 + specifier: ^25.4.0 + version: 25.4.0 '@push.rocks/smartradius': specifier: ^1.1.1 version: 1.1.1 @@ -1031,8 +1031,8 @@ packages: '@push.rocks/smartpromise@4.2.3': resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==} - '@push.rocks/smartproxy@25.3.1': - resolution: {integrity: sha512-kGJGpx3KBUz+qWU2L9B2gbZoUbQEG2BFe6ZzK0b68Y32nHoSIMjol14hzc3sRgW1p/loWy+Gj+5j0KuVytKWmA==} + '@push.rocks/smartproxy@25.4.0': + resolution: {integrity: sha512-aU7ySk/2llRs6hcIGrl4gjuXsJOmLuVv952ys4H1yZyZSdPx7G8m5gJl6RxB5Rp8GzM2YaKUvCp00apcGcnEfw==} '@push.rocks/smartpuppeteer@2.0.5': resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==} @@ -6369,7 +6369,7 @@ snapshots: '@push.rocks/smartpromise@4.2.3': {} - '@push.rocks/smartproxy@25.3.1': + '@push.rocks/smartproxy@25.4.0': dependencies: '@push.rocks/smartcrypto': 2.0.4 '@push.rocks/smartlog': 3.1.11 diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index a84b0fa..0fba044 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '6.2.1', + version: '6.2.2', description: 'A multifaceted routing service handling mail and SMS delivery functions.' } diff --git a/ts/classes.dcrouter.ts b/ts/classes.dcrouter.ts index e9038e2..dcba7ac 100644 --- a/ts/classes.dcrouter.ts +++ b/ts/classes.dcrouter.ts @@ -444,7 +444,10 @@ export class DcRouter { // If we have routes or need a basic SmartProxy instance, create it 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[] = []; + // Create SmartProxy configuration const smartProxyConfig: plugins.smartproxy.ISmartProxyOptions = { ...this.options.smartProxyConfig, @@ -456,7 +459,10 @@ export class DcRouter { const certs: Array<{ domain: string; publicKey: string; privateKey: string; ca?: string }> = []; for (const key of keys) { const data = await this.storageManager.getJSON(key); - if (data) certs.push(data); + if (data) { + certs.push(data); + loadedCertDomains.push(data.domain); + } } return certs; }, @@ -579,7 +585,36 @@ export class DcRouter { console.log('[DcRouter] Starting SmartProxy...'); await this.smartProxy.start(); 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); + 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, { + status: 'valid', + routeNames, + expiryDate, + issuedAt, + source: 'cert-store', + }); + } + } + if (loadedCertDomains.length > 0) { + console.log(`[DcRouter] Populated certificate status for ${loadedCertDomains.length} store-loaded domain(s)`); + } + console.log(`SmartProxy started with ${routes.length} routes`); } } diff --git a/ts/opsserver/handlers/certificate.handler.ts b/ts/opsserver/handlers/certificate.handler.ts index 6ab27e0..106f4b7 100644 --- a/ts/opsserver/handlers/certificate.handler.ts +++ b/ts/opsserver/handlers/certificate.handler.ts @@ -156,13 +156,21 @@ export class CertificateHandler { // Check persisted cert data from StorageManager if (status === 'unknown') { const cleanDomain = domain.replace(/^\*\.?/, ''); - const certData = await dcRouter.storageManager.getJSON(`/certs/${cleanDomain}`); + let certData = await dcRouter.storageManager.getJSON(`/certs/${cleanDomain}`); + if (!certData) { + // Also check certStore path (proxy-certs) + certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${domain}`); + } if (certData?.validUntil) { expiryDate = new Date(certData.validUntil).toISOString(); if (certData.created) { issuedAt = new Date(certData.created).toISOString(); } issuer = 'smartacme-dns-01'; + } else if (certData) { + // certStore has the cert (no expiry metadata) — it's loaded and serving + status = 'valid'; + issuer = 'cert-store'; } } diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index a84b0fa..0fba044 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '6.2.1', + version: '6.2.2', description: 'A multifaceted routing service handling mail and SMS delivery functions.' }