@serve.zone/dcrouter 11.0.5 → 11.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist_serve/bundle.js +3358 -3358
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/cache/classes.cache.cleaner.d.ts +47 -0
  5. package/dist_ts/cache/classes.cache.cleaner.js +130 -0
  6. package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +119 -0
  7. package/dist_ts/cache/documents/classes.cached.ip.reputation.js +323 -0
  8. package/dist_ts/cache/documents/index.d.ts +2 -0
  9. package/dist_ts/cache/documents/index.js +3 -0
  10. package/dist_ts/cache/index.d.ts +4 -0
  11. package/dist_ts/cache/index.js +7 -0
  12. package/dist_ts/classes.cert-provision-scheduler.d.ts +53 -0
  13. package/dist_ts/classes.cert-provision-scheduler.js +110 -0
  14. package/dist_ts/classes.dcrouter.d.ts +337 -0
  15. package/dist_ts/classes.dcrouter.js +1405 -0
  16. package/dist_ts/classes.storage-cert-manager.d.ts +18 -0
  17. package/dist_ts/classes.storage-cert-manager.js +43 -0
  18. package/dist_ts/config/classes.api-token-manager.d.ts +46 -0
  19. package/dist_ts/config/classes.api-token-manager.js +150 -0
  20. package/dist_ts/config/classes.route-config-manager.d.ts +35 -0
  21. package/dist_ts/config/classes.route-config-manager.js +231 -0
  22. package/dist_ts/config/index.d.ts +3 -0
  23. package/dist_ts/config/index.js +5 -0
  24. package/dist_ts/config/validator.d.ts +104 -0
  25. package/dist_ts/config/validator.js +152 -0
  26. package/dist_ts/errors/base.errors.d.ts +224 -0
  27. package/dist_ts/errors/base.errors.js +320 -0
  28. package/dist_ts/errors/error-handler.d.ts +98 -0
  29. package/dist_ts/errors/error-handler.js +282 -0
  30. package/dist_ts/errors/error.codes.d.ts +115 -0
  31. package/dist_ts/errors/error.codes.js +136 -0
  32. package/dist_ts/errors/index.d.ts +54 -0
  33. package/dist_ts/errors/index.js +136 -0
  34. package/dist_ts/errors/reputation.errors.d.ts +183 -0
  35. package/dist_ts/errors/reputation.errors.js +292 -0
  36. package/dist_ts/index.d.ts +7 -0
  37. package/dist_ts/index.js +11 -0
  38. package/dist_ts/logger.d.ts +21 -0
  39. package/dist_ts/logger.js +81 -0
  40. package/dist_ts/monitoring/classes.metricscache.d.ts +32 -0
  41. package/dist_ts/monitoring/classes.metricscache.js +63 -0
  42. package/dist_ts/monitoring/classes.metricsmanager.d.ts +178 -0
  43. package/dist_ts/monitoring/classes.metricsmanager.js +642 -0
  44. package/dist_ts/monitoring/index.d.ts +1 -0
  45. package/dist_ts/monitoring/index.js +2 -0
  46. package/dist_ts/opsserver/classes.opsserver.d.ts +37 -0
  47. package/dist_ts/opsserver/classes.opsserver.js +85 -0
  48. package/dist_ts/opsserver/handlers/admin.handler.d.ts +31 -0
  49. package/dist_ts/opsserver/handlers/admin.handler.js +180 -0
  50. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
  51. package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
  52. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +32 -0
  53. package/dist_ts/opsserver/handlers/certificate.handler.js +421 -0
  54. package/dist_ts/opsserver/handlers/config.handler.d.ts +7 -0
  55. package/dist_ts/opsserver/handlers/config.handler.js +192 -0
  56. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
  57. package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
  58. package/dist_ts/opsserver/handlers/index.d.ts +11 -0
  59. package/dist_ts/opsserver/handlers/index.js +12 -0
  60. package/dist_ts/opsserver/handlers/logs.handler.d.ts +25 -0
  61. package/dist_ts/opsserver/handlers/logs.handler.js +256 -0
  62. package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
  63. package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
  64. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
  65. package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
  66. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
  67. package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
  68. package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
  69. package/dist_ts/opsserver/handlers/security.handler.js +231 -0
  70. package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
  71. package/dist_ts/opsserver/handlers/stats.handler.js +399 -0
  72. package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
  73. package/dist_ts/opsserver/helpers/guards.js +43 -0
  74. package/dist_ts/opsserver/index.d.ts +1 -0
  75. package/dist_ts/opsserver/index.js +2 -0
  76. package/dist_ts/paths.d.ts +26 -0
  77. package/dist_ts/paths.js +45 -0
  78. package/dist_ts/plugins.d.ts +79 -0
  79. package/dist_ts/plugins.js +113 -0
  80. package/dist_ts/radius/classes.accounting.manager.d.ts +218 -0
  81. package/dist_ts/radius/classes.accounting.manager.js +417 -0
  82. package/dist_ts/radius/classes.radius.server.d.ts +171 -0
  83. package/dist_ts/radius/classes.radius.server.js +385 -0
  84. package/dist_ts/radius/classes.vlan.manager.d.ts +128 -0
  85. package/dist_ts/radius/classes.vlan.manager.js +279 -0
  86. package/dist_ts/radius/index.d.ts +13 -0
  87. package/dist_ts/radius/index.js +14 -0
  88. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +82 -0
  89. package/dist_ts/remoteingress/classes.remoteingress-manager.js +227 -0
  90. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
  91. package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
  92. package/dist_ts/remoteingress/index.d.ts +2 -0
  93. package/dist_ts/remoteingress/index.js +3 -0
  94. package/dist_ts/security/classes.contentscanner.d.ts +164 -0
  95. package/dist_ts/security/classes.contentscanner.js +642 -0
  96. package/dist_ts/security/classes.ipreputationchecker.d.ts +160 -0
  97. package/dist_ts/security/classes.ipreputationchecker.js +537 -0
  98. package/dist_ts/security/classes.securitylogger.d.ts +144 -0
  99. package/dist_ts/security/classes.securitylogger.js +233 -0
  100. package/dist_ts/security/index.d.ts +3 -0
  101. package/dist_ts/security/index.js +4 -0
  102. package/dist_ts/sms/classes.smsservice.d.ts +15 -0
  103. package/dist_ts/sms/classes.smsservice.js +72 -0
  104. package/dist_ts/sms/config/sms.config.d.ts +93 -0
  105. package/dist_ts/sms/config/sms.config.js +2 -0
  106. package/dist_ts/sms/config/sms.schema.d.ts +5 -0
  107. package/dist_ts/sms/config/sms.schema.js +121 -0
  108. package/dist_ts/sms/index.d.ts +1 -0
  109. package/dist_ts/sms/index.js +2 -0
  110. package/dist_ts/storage/classes.storagemanager.d.ts +83 -0
  111. package/dist_ts/storage/classes.storagemanager.js +350 -0
  112. package/dist_ts/storage/index.d.ts +1 -0
  113. package/dist_ts/storage/index.js +3 -0
  114. package/dist_ts_web/00_commitinfo_data.js +1 -1
  115. package/package.json +21 -13
  116. package/ts/00_commitinfo_data.ts +1 -1
  117. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,421 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
3
+ export class CertificateHandler {
4
+ opsServerRef;
5
+ constructor(opsServerRef) {
6
+ this.opsServerRef = opsServerRef;
7
+ this.registerHandlers();
8
+ }
9
+ registerHandlers() {
10
+ const viewRouter = this.opsServerRef.viewRouter;
11
+ const adminRouter = this.opsServerRef.adminRouter;
12
+ // ---- Read endpoints (viewRouter — valid identity required via middleware) ----
13
+ // Get Certificate Overview
14
+ viewRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getCertificateOverview', async (dataArg) => {
15
+ const certificates = await this.buildCertificateOverview();
16
+ const summary = this.buildSummary(certificates);
17
+ return { certificates, summary };
18
+ }));
19
+ // ---- Write endpoints (adminRouter — admin identity required via middleware) ----
20
+ // Legacy route-based reprovision (backward compat)
21
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('reprovisionCertificate', async (dataArg) => {
22
+ return this.reprovisionCertificateByRoute(dataArg.routeName);
23
+ }));
24
+ // Domain-based reprovision (preferred)
25
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('reprovisionCertificateDomain', async (dataArg) => {
26
+ return this.reprovisionCertificateDomain(dataArg.domain);
27
+ }));
28
+ // Delete certificate
29
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('deleteCertificate', async (dataArg) => {
30
+ return this.deleteCertificate(dataArg.domain);
31
+ }));
32
+ // Export certificate
33
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('exportCertificate', async (dataArg) => {
34
+ return this.exportCertificate(dataArg.domain);
35
+ }));
36
+ // Import certificate
37
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('importCertificate', async (dataArg) => {
38
+ return this.importCertificate(dataArg.cert);
39
+ }));
40
+ }
41
+ /**
42
+ * Build domain-centric certificate overview.
43
+ * Instead of one row per route, we produce one row per unique domain.
44
+ */
45
+ async buildCertificateOverview() {
46
+ const dcRouter = this.opsServerRef.dcRouterRef;
47
+ const smartProxy = dcRouter.smartProxy;
48
+ if (!smartProxy)
49
+ return [];
50
+ const routes = smartProxy.routeManager.getRoutes();
51
+ // Phase 1: Collect unique domains with their associated route info
52
+ const domainMap = new Map();
53
+ for (const route of routes) {
54
+ if (!route.name)
55
+ continue;
56
+ const tls = route.action?.tls;
57
+ if (!tls)
58
+ continue;
59
+ // Skip passthrough routes - they don't manage certificates
60
+ if (tls.mode === 'passthrough')
61
+ continue;
62
+ const routeDomains = route.match.domains
63
+ ? (Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains])
64
+ : [];
65
+ // Determine source
66
+ let source = 'none';
67
+ if (tls.certificate === 'auto') {
68
+ if (smartProxy.settings.certProvisionFunction) {
69
+ source = 'provision-function';
70
+ }
71
+ else {
72
+ source = 'acme';
73
+ }
74
+ }
75
+ else if (tls.certificate && typeof tls.certificate === 'object') {
76
+ source = 'static';
77
+ }
78
+ const canReprovision = source === 'acme' || source === 'provision-function';
79
+ const tlsMode = tls.mode;
80
+ for (const domain of routeDomains) {
81
+ const existing = domainMap.get(domain);
82
+ if (existing) {
83
+ // Add this route name to the existing domain entry
84
+ if (!existing.routeNames.includes(route.name)) {
85
+ existing.routeNames.push(route.name);
86
+ }
87
+ // Upgrade source if more specific
88
+ if (existing.source === 'none' && source !== 'none') {
89
+ existing.source = source;
90
+ existing.canReprovision = canReprovision;
91
+ }
92
+ }
93
+ else {
94
+ domainMap.set(domain, {
95
+ routeNames: [route.name],
96
+ source,
97
+ tlsMode,
98
+ canReprovision,
99
+ });
100
+ }
101
+ }
102
+ }
103
+ // Phase 2: Resolve status for each unique domain
104
+ const certificates = [];
105
+ for (const [domain, info] of domainMap) {
106
+ let status = 'unknown';
107
+ let expiryDate;
108
+ let issuedAt;
109
+ let issuer;
110
+ let error;
111
+ // Check event-based status from certificateStatusMap (now keyed by domain)
112
+ const eventStatus = dcRouter.certificateStatusMap.get(domain);
113
+ if (eventStatus) {
114
+ status = eventStatus.status;
115
+ expiryDate = eventStatus.expiryDate;
116
+ issuedAt = eventStatus.issuedAt;
117
+ error = eventStatus.error;
118
+ if (eventStatus.source) {
119
+ issuer = eventStatus.source;
120
+ }
121
+ }
122
+ // Try SmartProxy certificate status if no event data
123
+ if (status === 'unknown' && info.routeNames.length > 0) {
124
+ try {
125
+ const rustStatus = await smartProxy.getCertificateStatus(info.routeNames[0]);
126
+ if (rustStatus) {
127
+ if (rustStatus.expiryDate)
128
+ expiryDate = rustStatus.expiryDate;
129
+ if (rustStatus.issuer)
130
+ issuer = rustStatus.issuer;
131
+ if (rustStatus.issuedAt)
132
+ issuedAt = rustStatus.issuedAt;
133
+ if (rustStatus.status === 'valid' || rustStatus.status === 'expired') {
134
+ status = rustStatus.status;
135
+ }
136
+ }
137
+ }
138
+ catch {
139
+ // Rust bridge may not support this command yet — ignore
140
+ }
141
+ }
142
+ // Check persisted cert data from StorageManager
143
+ if (status === 'unknown') {
144
+ const cleanDomain = domain.replace(/^\*\.?/, '');
145
+ let certData = await dcRouter.storageManager.getJSON(`/certs/${cleanDomain}`);
146
+ if (!certData) {
147
+ // Also check certStore path (proxy-certs)
148
+ certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${domain}`);
149
+ }
150
+ if (certData?.validUntil) {
151
+ expiryDate = new Date(certData.validUntil).toISOString();
152
+ if (certData.created) {
153
+ issuedAt = new Date(certData.created).toISOString();
154
+ }
155
+ issuer = 'smartacme-dns-01';
156
+ }
157
+ else if (certData?.publicKey) {
158
+ // certStore has the cert — parse PEM for expiry
159
+ try {
160
+ const x509 = new plugins.crypto.X509Certificate(certData.publicKey);
161
+ expiryDate = new Date(x509.validTo).toISOString();
162
+ issuedAt = new Date(x509.validFrom).toISOString();
163
+ }
164
+ catch { /* PEM parsing failed */ }
165
+ status = 'valid';
166
+ issuer = 'cert-store';
167
+ }
168
+ else if (certData) {
169
+ status = 'valid';
170
+ issuer = 'cert-store';
171
+ }
172
+ }
173
+ // Compute status from expiry date
174
+ if (expiryDate && (status === 'valid' || status === 'unknown')) {
175
+ const expiry = new Date(expiryDate);
176
+ const now = new Date();
177
+ const daysUntilExpiry = (expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
178
+ if (daysUntilExpiry < 0) {
179
+ status = 'expired';
180
+ }
181
+ else if (daysUntilExpiry < 30) {
182
+ status = 'expiring';
183
+ }
184
+ else {
185
+ status = 'valid';
186
+ }
187
+ }
188
+ // Static certs with no other info default to 'valid'
189
+ if (info.source === 'static' && status === 'unknown') {
190
+ status = 'valid';
191
+ }
192
+ // ACME/provision-function routes with no cert data are still provisioning
193
+ if (status === 'unknown' && (info.source === 'acme' || info.source === 'provision-function')) {
194
+ status = 'provisioning';
195
+ }
196
+ // Phase 3: Attach backoff info
197
+ let backoffInfo;
198
+ if (dcRouter.certProvisionScheduler) {
199
+ const bi = await dcRouter.certProvisionScheduler.getBackoffInfo(domain);
200
+ if (bi) {
201
+ backoffInfo = bi;
202
+ }
203
+ }
204
+ certificates.push({
205
+ domain,
206
+ routeNames: info.routeNames,
207
+ status,
208
+ source: info.source,
209
+ tlsMode: info.tlsMode,
210
+ expiryDate,
211
+ issuer,
212
+ issuedAt,
213
+ error,
214
+ canReprovision: info.canReprovision,
215
+ backoffInfo,
216
+ });
217
+ }
218
+ return certificates;
219
+ }
220
+ buildSummary(certificates) {
221
+ const summary = { total: 0, valid: 0, expiring: 0, expired: 0, failed: 0, unknown: 0 };
222
+ summary.total = certificates.length;
223
+ for (const cert of certificates) {
224
+ switch (cert.status) {
225
+ case 'valid':
226
+ summary.valid++;
227
+ break;
228
+ case 'expiring':
229
+ summary.expiring++;
230
+ break;
231
+ case 'expired':
232
+ summary.expired++;
233
+ break;
234
+ case 'failed':
235
+ summary.failed++;
236
+ break;
237
+ case 'provisioning': // count as unknown
238
+ case 'unknown':
239
+ summary.unknown++;
240
+ break;
241
+ }
242
+ }
243
+ return summary;
244
+ }
245
+ /**
246
+ * Legacy route-based reprovisioning
247
+ */
248
+ async reprovisionCertificateByRoute(routeName) {
249
+ const dcRouter = this.opsServerRef.dcRouterRef;
250
+ const smartProxy = dcRouter.smartProxy;
251
+ if (!smartProxy) {
252
+ return { success: false, message: 'SmartProxy is not running' };
253
+ }
254
+ try {
255
+ await smartProxy.provisionCertificate(routeName);
256
+ // Clear event-based status for domains in this route
257
+ for (const [domain, entry] of dcRouter.certificateStatusMap) {
258
+ if (entry.routeNames.includes(routeName)) {
259
+ dcRouter.certificateStatusMap.delete(domain);
260
+ }
261
+ }
262
+ return { success: true, message: `Certificate reprovisioning triggered for route '${routeName}'` };
263
+ }
264
+ catch (err) {
265
+ return { success: false, message: err.message || 'Failed to reprovision certificate' };
266
+ }
267
+ }
268
+ /**
269
+ * Domain-based reprovisioning — clears backoff first, then triggers provision
270
+ */
271
+ async reprovisionCertificateDomain(domain) {
272
+ const dcRouter = this.opsServerRef.dcRouterRef;
273
+ const smartProxy = dcRouter.smartProxy;
274
+ if (!smartProxy) {
275
+ return { success: false, message: 'SmartProxy is not running' };
276
+ }
277
+ // Clear backoff for this domain (user override)
278
+ if (dcRouter.certProvisionScheduler) {
279
+ await dcRouter.certProvisionScheduler.clearBackoff(domain);
280
+ }
281
+ // Clear status map entry so it gets refreshed
282
+ dcRouter.certificateStatusMap.delete(domain);
283
+ // Try to provision via SmartAcme directly
284
+ if (dcRouter.smartAcme) {
285
+ try {
286
+ await dcRouter.smartAcme.getCertificateForDomain(domain);
287
+ return { success: true, message: `Certificate reprovisioning triggered for domain '${domain}'` };
288
+ }
289
+ catch (err) {
290
+ return { success: false, message: err.message || `Failed to reprovision certificate for ${domain}` };
291
+ }
292
+ }
293
+ // Fallback: try provisioning via the first matching route
294
+ const routeNames = dcRouter.findRouteNamesForDomain(domain);
295
+ if (routeNames.length > 0) {
296
+ try {
297
+ await smartProxy.provisionCertificate(routeNames[0]);
298
+ return { success: true, message: `Certificate reprovisioning triggered for domain '${domain}' via route '${routeNames[0]}'` };
299
+ }
300
+ catch (err) {
301
+ return { success: false, message: err.message || `Failed to reprovision certificate for ${domain}` };
302
+ }
303
+ }
304
+ return { success: false, message: `No routes found for domain '${domain}'` };
305
+ }
306
+ /**
307
+ * Delete certificate data for a domain from storage
308
+ */
309
+ async deleteCertificate(domain) {
310
+ const dcRouter = this.opsServerRef.dcRouterRef;
311
+ const cleanDomain = domain.replace(/^\*\.?/, '');
312
+ // Delete from all known storage paths
313
+ const paths = [
314
+ `/proxy-certs/${domain}`,
315
+ `/proxy-certs/${cleanDomain}`,
316
+ `/certs/${cleanDomain}`,
317
+ ];
318
+ for (const path of paths) {
319
+ try {
320
+ await dcRouter.storageManager.delete(path);
321
+ }
322
+ catch {
323
+ // Path may not exist — ignore
324
+ }
325
+ }
326
+ // Clear from in-memory status map
327
+ dcRouter.certificateStatusMap.delete(domain);
328
+ // Clear backoff info
329
+ if (dcRouter.certProvisionScheduler) {
330
+ await dcRouter.certProvisionScheduler.clearBackoff(domain);
331
+ }
332
+ return { success: true, message: `Certificate data deleted for '${domain}'` };
333
+ }
334
+ /**
335
+ * Export certificate data for a domain as ICert-shaped JSON
336
+ */
337
+ async exportCertificate(domain) {
338
+ const dcRouter = this.opsServerRef.dcRouterRef;
339
+ const cleanDomain = domain.replace(/^\*\.?/, '');
340
+ // Try SmartAcme /certs/ path first (has full ICert fields)
341
+ let certData = await dcRouter.storageManager.getJSON(`/certs/${cleanDomain}`);
342
+ if (certData && certData.publicKey && certData.privateKey) {
343
+ return {
344
+ success: true,
345
+ cert: {
346
+ id: certData.id || plugins.crypto.randomUUID(),
347
+ domainName: certData.domainName || domain,
348
+ created: certData.created || Date.now(),
349
+ validUntil: certData.validUntil || 0,
350
+ privateKey: certData.privateKey,
351
+ publicKey: certData.publicKey,
352
+ csr: certData.csr || '',
353
+ },
354
+ };
355
+ }
356
+ // Fallback: try /proxy-certs/ with original domain
357
+ certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${domain}`);
358
+ if (!certData || !certData.publicKey) {
359
+ // Try with clean domain
360
+ certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${cleanDomain}`);
361
+ }
362
+ if (certData && certData.publicKey && certData.privateKey) {
363
+ return {
364
+ success: true,
365
+ cert: {
366
+ id: plugins.crypto.randomUUID(),
367
+ domainName: domain,
368
+ created: certData.validFrom || Date.now(),
369
+ validUntil: certData.validUntil || 0,
370
+ privateKey: certData.privateKey,
371
+ publicKey: certData.publicKey,
372
+ csr: '',
373
+ },
374
+ };
375
+ }
376
+ return { success: false, message: `No certificate data found for '${domain}'` };
377
+ }
378
+ /**
379
+ * Import a certificate from ICert-shaped JSON
380
+ */
381
+ async importCertificate(cert) {
382
+ // Validate PEM content
383
+ if (!cert.publicKey || !cert.publicKey.includes('-----BEGIN CERTIFICATE-----')) {
384
+ return { success: false, message: 'Invalid publicKey: must contain a PEM-encoded certificate' };
385
+ }
386
+ if (!cert.privateKey || !cert.privateKey.includes('-----BEGIN')) {
387
+ return { success: false, message: 'Invalid privateKey: must contain a PEM-encoded key' };
388
+ }
389
+ const dcRouter = this.opsServerRef.dcRouterRef;
390
+ const cleanDomain = cert.domainName.replace(/^\*\.?/, '');
391
+ // Save to /certs/ (SmartAcme-compatible path)
392
+ await dcRouter.storageManager.setJSON(`/certs/${cleanDomain}`, {
393
+ id: cert.id,
394
+ domainName: cert.domainName,
395
+ created: cert.created,
396
+ validUntil: cert.validUntil,
397
+ privateKey: cert.privateKey,
398
+ publicKey: cert.publicKey,
399
+ csr: cert.csr || '',
400
+ });
401
+ // Also save to /proxy-certs/ (proxy-cert format)
402
+ await dcRouter.storageManager.setJSON(`/proxy-certs/${cert.domainName}`, {
403
+ domain: cert.domainName,
404
+ publicKey: cert.publicKey,
405
+ privateKey: cert.privateKey,
406
+ ca: undefined,
407
+ validUntil: cert.validUntil,
408
+ validFrom: cert.created,
409
+ });
410
+ // Update in-memory status map
411
+ dcRouter.certificateStatusMap.set(cert.domainName, {
412
+ status: 'valid',
413
+ source: 'static',
414
+ expiryDate: cert.validUntil ? new Date(cert.validUntil).toISOString() : undefined,
415
+ issuedAt: cert.created ? new Date(cert.created).toISOString() : undefined,
416
+ routeNames: [],
417
+ });
418
+ return { success: true, message: `Certificate imported for '${cert.domainName}'` };
419
+ }
420
+ }
421
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUuaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL29wc3NlcnZlci9oYW5kbGVycy9jZXJ0aWZpY2F0ZS5oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxNQUFNLE9BQU8sa0JBQWtCO0lBQ1Q7SUFBcEIsWUFBb0IsWUFBdUI7UUFBdkIsaUJBQVksR0FBWixZQUFZLENBQVc7UUFDekMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVPLGdCQUFnQjtRQUN0QixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQztRQUNoRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQztRQUVsRCxpRkFBaUY7UUFFakYsMkJBQTJCO1FBQzNCLFVBQVUsQ0FBQyxlQUFlLENBQ3hCLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ25DLHdCQUF3QixFQUN4QixLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7WUFDaEIsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUMzRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ2hELE9BQU8sRUFBRSxZQUFZLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDbkMsQ0FBQyxDQUNGLENBQ0YsQ0FBQztRQUVGLG1GQUFtRjtRQUVuRixtREFBbUQ7UUFDbkQsV0FBVyxDQUFDLGVBQWUsQ0FDekIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsd0JBQXdCLEVBQ3hCLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtZQUNoQixPQUFP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
@@ -0,0 +1,7 @@
1
+ import type { OpsServer } from '../classes.opsserver.js';
2
+ export declare class ConfigHandler {
3
+ private opsServerRef;
4
+ constructor(opsServerRef: OpsServer);
5
+ private registerHandlers;
6
+ private getConfiguration;
7
+ }
@@ -0,0 +1,192 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as paths from '../../paths.js';
3
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
4
+ export class ConfigHandler {
5
+ opsServerRef;
6
+ constructor(opsServerRef) {
7
+ this.opsServerRef = opsServerRef;
8
+ this.registerHandlers();
9
+ }
10
+ registerHandlers() {
11
+ // Config endpoint registers directly on viewRouter (valid identity required via middleware)
12
+ const router = this.opsServerRef.viewRouter;
13
+ // Get Configuration Handler (read-only)
14
+ router.addTypedHandler(new plugins.typedrequest.TypedHandler('getConfiguration', async (dataArg, toolsArg) => {
15
+ const config = await this.getConfiguration();
16
+ return {
17
+ config,
18
+ section: dataArg.section,
19
+ };
20
+ }));
21
+ }
22
+ async getConfiguration() {
23
+ const dcRouter = this.opsServerRef.dcRouterRef;
24
+ const opts = dcRouter.options;
25
+ const resolvedPaths = dcRouter.resolvedPaths;
26
+ // --- System ---
27
+ const storageBackend = opts.storage?.readFunction
28
+ ? 'custom'
29
+ : opts.storage?.fsPath
30
+ ? 'filesystem'
31
+ : 'memory';
32
+ // Resolve proxy IPs: fall back to SmartProxy's runtime proxyIPs if not in opts
33
+ let proxyIps = opts.proxyIps || [];
34
+ if (proxyIps.length === 0 && dcRouter.smartProxy) {
35
+ const spSettings = dcRouter.smartProxy.settings;
36
+ if (spSettings?.proxyIPs?.length > 0) {
37
+ proxyIps = spSettings.proxyIPs;
38
+ }
39
+ }
40
+ const system = {
41
+ baseDir: resolvedPaths.dcrouterHomeDir,
42
+ dataDir: resolvedPaths.dataDir,
43
+ publicIp: opts.publicIp || dcRouter.detectedPublicIp || null,
44
+ proxyIps,
45
+ uptime: Math.floor(process.uptime()),
46
+ storageBackend,
47
+ storagePath: opts.storage?.fsPath || null,
48
+ };
49
+ // --- SmartProxy ---
50
+ let acmeInfo = null;
51
+ if (opts.smartProxyConfig?.acme) {
52
+ const acme = opts.smartProxyConfig.acme;
53
+ acmeInfo = {
54
+ enabled: acme.enabled !== false,
55
+ accountEmail: acme.accountEmail || '',
56
+ useProduction: acme.useProduction !== false,
57
+ autoRenew: acme.autoRenew !== false,
58
+ renewThresholdDays: acme.renewThresholdDays || 30,
59
+ };
60
+ }
61
+ let routeCount = 0;
62
+ if (dcRouter.routeConfigManager) {
63
+ try {
64
+ const merged = await dcRouter.routeConfigManager.getMergedRoutes();
65
+ routeCount = merged.routes.length;
66
+ }
67
+ catch {
68
+ routeCount = opts.smartProxyConfig?.routes?.length || 0;
69
+ }
70
+ }
71
+ else if (opts.smartProxyConfig?.routes) {
72
+ routeCount = opts.smartProxyConfig.routes.length;
73
+ }
74
+ const smartProxy = {
75
+ enabled: !!dcRouter.smartProxy,
76
+ routeCount,
77
+ acme: acmeInfo,
78
+ };
79
+ // --- Email ---
80
+ let emailDomains = [];
81
+ if (dcRouter.emailServer && dcRouter.emailServer.domainRegistry) {
82
+ emailDomains = dcRouter.emailServer.domainRegistry.getAllDomains();
83
+ }
84
+ else if (opts.emailConfig?.domains) {
85
+ emailDomains = opts.emailConfig.domains.map((d) => typeof d === 'string' ? d : d.domain);
86
+ }
87
+ let portMapping = null;
88
+ if (opts.emailPortConfig?.portMapping) {
89
+ portMapping = {};
90
+ for (const [ext, int] of Object.entries(opts.emailPortConfig.portMapping)) {
91
+ portMapping[String(ext)] = int;
92
+ }
93
+ }
94
+ const email = {
95
+ enabled: !!dcRouter.emailServer,
96
+ ports: opts.emailConfig?.ports || [],
97
+ portMapping,
98
+ hostname: opts.emailConfig?.hostname || null,
99
+ domains: emailDomains,
100
+ emailRouteCount: opts.emailConfig?.routes?.length || 0,
101
+ receivedEmailsPath: opts.emailPortConfig?.receivedEmailsPath || null,
102
+ };
103
+ // --- DNS ---
104
+ const dnsRecords = (opts.dnsRecords || []).map(r => ({
105
+ name: r.name,
106
+ type: r.type,
107
+ value: r.value,
108
+ ttl: r.ttl,
109
+ }));
110
+ const dns = {
111
+ enabled: !!dcRouter.dnsServer,
112
+ port: 53,
113
+ nsDomains: opts.dnsNsDomains || [],
114
+ scopes: opts.dnsScopes || [],
115
+ recordCount: dnsRecords.length,
116
+ records: dnsRecords,
117
+ dnsChallenge: !!opts.dnsChallenge?.cloudflareApiKey,
118
+ };
119
+ // --- TLS ---
120
+ let tlsSource = 'none';
121
+ if (opts.tls?.certPath && opts.tls?.keyPath) {
122
+ tlsSource = 'static';
123
+ }
124
+ else if (opts.smartProxyConfig?.acme?.enabled !== false && opts.smartProxyConfig?.acme) {
125
+ tlsSource = 'acme';
126
+ }
127
+ const tls = {
128
+ contactEmail: opts.tls?.contactEmail || opts.smartProxyConfig?.acme?.accountEmail || null,
129
+ domain: opts.tls?.domain || null,
130
+ source: tlsSource,
131
+ certPath: opts.tls?.certPath || null,
132
+ keyPath: opts.tls?.keyPath || null,
133
+ };
134
+ // --- Cache ---
135
+ const cacheConfig = opts.cacheConfig;
136
+ const cache = {
137
+ enabled: cacheConfig?.enabled !== false,
138
+ storagePath: cacheConfig?.storagePath || resolvedPaths.defaultTsmDbPath,
139
+ dbName: cacheConfig?.dbName || 'dcrouter',
140
+ defaultTTLDays: cacheConfig?.defaultTTLDays || 30,
141
+ cleanupIntervalHours: cacheConfig?.cleanupIntervalHours || 1,
142
+ ttlConfig: cacheConfig?.ttlConfig ? { ...cacheConfig.ttlConfig } : {},
143
+ };
144
+ // --- RADIUS ---
145
+ const radiusCfg = opts.radiusConfig;
146
+ const radius = {
147
+ enabled: !!dcRouter.radiusServer,
148
+ authPort: radiusCfg?.authPort || null,
149
+ acctPort: radiusCfg?.acctPort || null,
150
+ bindAddress: radiusCfg?.bindAddress || null,
151
+ clientCount: radiusCfg?.clients?.length || 0,
152
+ vlanDefaultVlan: radiusCfg?.vlanAssignment?.defaultVlan ?? null,
153
+ vlanAllowUnknownMacs: radiusCfg?.vlanAssignment?.allowUnknownMacs ?? null,
154
+ vlanMappingCount: radiusCfg?.vlanAssignment?.mappings?.length || 0,
155
+ };
156
+ // --- Remote Ingress ---
157
+ const riCfg = opts.remoteIngressConfig;
158
+ const connectedEdgeIps = dcRouter.tunnelManager?.getConnectedEdgeIps() || [];
159
+ // Determine TLS mode: custom certs > ACME from cert store > self-signed fallback
160
+ let tlsMode = 'self-signed';
161
+ if (riCfg?.tls?.certPath && riCfg?.tls?.keyPath) {
162
+ tlsMode = 'custom';
163
+ }
164
+ else if (riCfg?.hubDomain) {
165
+ try {
166
+ const stored = await dcRouter.storageManager.getJSON(`/proxy-certs/${riCfg.hubDomain}`);
167
+ if (stored?.publicKey && stored?.privateKey) {
168
+ tlsMode = 'acme';
169
+ }
170
+ }
171
+ catch { /* no stored cert */ }
172
+ }
173
+ const remoteIngress = {
174
+ enabled: !!dcRouter.remoteIngressManager,
175
+ tunnelPort: riCfg?.tunnelPort || null,
176
+ hubDomain: riCfg?.hubDomain || null,
177
+ tlsMode,
178
+ connectedEdgeIps,
179
+ };
180
+ return {
181
+ system,
182
+ smartProxy,
183
+ email,
184
+ dns,
185
+ tls,
186
+ cache,
187
+ radius,
188
+ remoteIngress,
189
+ };
190
+ }
191
+ }
192
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9vcHNzZXJ2ZXIvaGFuZGxlcnMvY29uZmlnLmhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUM1QyxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBRXhDLE9BQU8sS0FBSyxVQUFVLE1BQU0saUNBQWlDLENBQUM7QUFFOUQsTUFBTSxPQUFPLGFBQWE7SUFDSjtJQUFwQixZQUFvQixZQUF1QjtRQUF2QixpQkFBWSxHQUFaLFlBQVksQ0FBVztRQUN6QyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRU8sZ0JBQWdCO1FBQ3RCLDRGQUE0RjtRQUM1RixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQztRQUU1Qyx3Q0FBd0M7UUFDeEMsTUFBTSxDQUFDLGVBQWUsQ0FDcEIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsa0JBQWtCLEVBQ2xCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDMUIsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUM3QyxPQUFPO2dCQUNMLE1BQU07Z0JBQ04sT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO2FBQ3pCLENBQUM7UUFDSixDQUFDLENBQ0YsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxnQkFBZ0I7UUFDNUIsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUM7UUFDL0MsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQztRQUM5QixNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDO1FBRTdDLGlCQUFpQjtRQUNqQixN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