Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e32745a8f | |||
| 121573de2f | |||
| cd957526e2 | |||
| 7aa5f07731 |
14
changelog.md
14
changelog.md
@@ -1,5 +1,19 @@
|
||||
# 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
|
||||
|
||||
- Pass includeWildcard flag to smartAcme.getCertificateForDomain to avoid incorrectly including/excluding wildcard certificates based on whether the requested domain itself is a wildcard
|
||||
- Detect wildcard domains via domain.startsWith('*.') and set includeWildcard to false for wildcard requests
|
||||
- Treat empty or whitespace-only stored values as null in StorageManager.getJSON to avoid parsing empty strings as JSON and potential errors
|
||||
|
||||
## 2026-02-16 - 6.2.0 - feat(ts_web)
|
||||
add Certificate Management documentation and ops-view-certificates reference
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@serve.zone/dcrouter",
|
||||
"private": false,
|
||||
"version": "6.2.0",
|
||||
"version": "6.2.2",
|
||||
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
@@ -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",
|
||||
|
||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -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
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '6.2.0',
|
||||
version: '6.2.2',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
@@ -499,7 +505,10 @@ export class DcRouter {
|
||||
// smartacme v9 handles concurrency, per-domain dedup, and rate limiting internally
|
||||
eventComms.log(`Attempting DNS-01 via SmartAcme for ${domain}`);
|
||||
eventComms.setSource('smartacme-dns-01');
|
||||
const cert = await this.smartAcme.getCertificateForDomain(domain);
|
||||
const isWildcardDomain = domain.startsWith('*.');
|
||||
const cert = await this.smartAcme.getCertificateForDomain(domain, {
|
||||
includeWildcard: !isWildcardDomain,
|
||||
});
|
||||
if (cert.validUntil) {
|
||||
eventComms.setExpiryDate(new Date(cert.validUntil));
|
||||
}
|
||||
@@ -576,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`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -378,7 +378,7 @@ export class StorageManager {
|
||||
*/
|
||||
async getJSON<T = any>(key: string): Promise<T | null> {
|
||||
const value = await this.get(key);
|
||||
if (value === null) {
|
||||
if (value === null || value.trim() === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '6.2.0',
|
||||
version: '6.2.2',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user