@push.rocks/smartproxy 18.1.0 → 19.0.0
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.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/certificate/certificate-manager.d.ts +150 -0
- package/dist_ts/certificate/certificate-manager.js +505 -0
- package/dist_ts/certificate/events/simplified-events.d.ts +56 -0
- package/dist_ts/certificate/events/simplified-events.js +13 -0
- package/dist_ts/certificate/models/certificate-errors.d.ts +69 -0
- package/dist_ts/certificate/models/certificate-errors.js +141 -0
- package/dist_ts/certificate/models/certificate-strategy.d.ts +60 -0
- package/dist_ts/certificate/models/certificate-strategy.js +73 -0
- package/dist_ts/certificate/simplified-certificate-manager.d.ts +150 -0
- package/dist_ts/certificate/simplified-certificate-manager.js +501 -0
- package/dist_ts/common/eventUtils.d.ts +1 -2
- package/dist_ts/common/eventUtils.js +2 -1
- package/dist_ts/core/models/common-types.d.ts +1 -1
- package/dist_ts/core/models/common-types.js +1 -1
- package/dist_ts/core/utils/event-utils.d.ts +9 -9
- package/dist_ts/core/utils/event-utils.js +6 -14
- package/dist_ts/http/index.d.ts +1 -9
- package/dist_ts/http/index.js +5 -11
- package/dist_ts/http/models/http-types.d.ts +13 -1
- package/dist_ts/http/models/http-types.js +1 -1
- package/dist_ts/index.d.ts +4 -6
- package/dist_ts/index.js +4 -10
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +4 -2
- package/dist_ts/proxies/index.d.ts +3 -2
- package/dist_ts/proxies/index.js +4 -5
- package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +31 -49
- package/dist_ts/proxies/network-proxy/certificate-manager.js +77 -374
- package/dist_ts/proxies/network-proxy/models/types.d.ts +12 -1
- package/dist_ts/proxies/network-proxy/models/types.js +1 -1
- package/dist_ts/proxies/network-proxy/network-proxy.d.ts +2 -7
- package/dist_ts/proxies/network-proxy/network-proxy.js +12 -19
- package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.d.ts +48 -0
- package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.js +76 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.js +21 -7
- package/dist_ts/proxies/smart-proxy/cert-store.d.ts +10 -0
- package/dist_ts/proxies/smart-proxy/cert-store.js +70 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +116 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +401 -0
- package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.d.ts +168 -0
- package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.js +642 -0
- package/dist_ts/proxies/smart-proxy/models/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/models/index.js +1 -5
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +13 -1
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +26 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.d.ts +65 -0
- package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.js +31 -0
- package/dist_ts/proxies/smart-proxy/models/smartproxy-options.d.ts +102 -0
- package/dist_ts/proxies/smart-proxy/models/smartproxy-options.js +73 -0
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +10 -44
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +66 -202
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +62 -2
- package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.d.ts +41 -0
- package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.js +132 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +18 -13
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +80 -198
- package/package.json +5 -3
- package/readme.md +13 -5
- package/readme.plan.md +1422 -617
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/common/eventUtils.ts +2 -2
- package/ts/core/models/common-types.ts +1 -1
- package/ts/core/utils/event-utils.ts +12 -21
- package/ts/http/index.ts +5 -12
- package/ts/http/models/http-types.ts +8 -4
- package/ts/index.ts +11 -14
- package/ts/plugins.ts +4 -1
- package/ts/proxies/index.ts +7 -4
- package/ts/proxies/network-proxy/certificate-manager.ts +92 -417
- package/ts/proxies/network-proxy/models/types.ts +14 -2
- package/ts/proxies/network-proxy/network-proxy.ts +13 -19
- package/ts/proxies/network-proxy/websocket-handler.ts +18 -6
- package/ts/proxies/smart-proxy/cert-store.ts +86 -0
- package/ts/proxies/smart-proxy/certificate-manager.ts +506 -0
- package/ts/proxies/smart-proxy/models/index.ts +2 -1
- package/ts/proxies/smart-proxy/models/interfaces.ts +14 -1
- package/ts/proxies/smart-proxy/models/route-types.ts +34 -4
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +86 -239
- package/ts/proxies/smart-proxy/route-connection-handler.ts +74 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +106 -224
- package/ts/certificate/acme/acme-factory.ts +0 -48
- package/ts/certificate/acme/challenge-handler.ts +0 -110
- package/ts/certificate/acme/index.ts +0 -3
- package/ts/certificate/events/certificate-events.ts +0 -36
- package/ts/certificate/index.ts +0 -75
- package/ts/certificate/models/certificate-types.ts +0 -109
- package/ts/certificate/providers/cert-provisioner.ts +0 -519
- package/ts/certificate/providers/index.ts +0 -3
- package/ts/certificate/storage/file-storage.ts +0 -234
- package/ts/certificate/storage/index.ts +0 -3
- package/ts/certificate/utils/certificate-helpers.ts +0 -50
- package/ts/http/port80/acme-interfaces.ts +0 -169
- package/ts/http/port80/challenge-responder.ts +0 -246
- package/ts/http/port80/index.ts +0 -13
- package/ts/http/port80/port80-handler.ts +0 -728
|
@@ -11,12 +11,8 @@ import { RouteManager } from './route-manager.js';
|
|
|
11
11
|
import { RouteConnectionHandler } from './route-connection-handler.js';
|
|
12
12
|
import { NFTablesManager } from './nftables-manager.js';
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
import {
|
|
16
|
-
import { CertProvisioner } from '../../certificate/providers/cert-provisioner.js';
|
|
17
|
-
import type { ICertificateData } from '../../certificate/models/certificate-types.js';
|
|
18
|
-
import { buildPort80Handler } from '../../certificate/acme/acme-factory.js';
|
|
19
|
-
import { createPort80HandlerOptions } from '../../common/port80-adapter.js';
|
|
14
|
+
// Certificate manager
|
|
15
|
+
import { SmartCertManager, type ICertStatus } from './certificate-manager.js';
|
|
20
16
|
|
|
21
17
|
// Import types and utilities
|
|
22
18
|
import type {
|
|
@@ -53,10 +49,8 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
53
49
|
private routeConnectionHandler: RouteConnectionHandler;
|
|
54
50
|
private nftablesManager: NFTablesManager;
|
|
55
51
|
|
|
56
|
-
//
|
|
57
|
-
private
|
|
58
|
-
// CertProvisioner for unified certificate workflows
|
|
59
|
-
private certProvisioner?: CertProvisioner;
|
|
52
|
+
// Certificate manager for ACME and static certificates
|
|
53
|
+
private certManager: SmartCertManager | null = null;
|
|
60
54
|
|
|
61
55
|
/**
|
|
62
56
|
* Constructor for SmartProxy
|
|
@@ -127,13 +121,12 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
127
121
|
this.settings.acme = {
|
|
128
122
|
enabled: false,
|
|
129
123
|
port: 80,
|
|
130
|
-
|
|
124
|
+
email: 'admin@example.com',
|
|
131
125
|
useProduction: false,
|
|
132
126
|
renewThresholdDays: 30,
|
|
133
127
|
autoRenew: true,
|
|
134
128
|
certificateStore: './certs',
|
|
135
129
|
skipConfiguredCerts: false,
|
|
136
|
-
httpsRedirectPort: 443,
|
|
137
130
|
renewCheckIntervalHours: 24,
|
|
138
131
|
routeForwards: []
|
|
139
132
|
};
|
|
@@ -180,29 +173,53 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
180
173
|
public settings: ISmartProxyOptions;
|
|
181
174
|
|
|
182
175
|
/**
|
|
183
|
-
* Initialize
|
|
176
|
+
* Initialize certificate manager
|
|
184
177
|
*/
|
|
185
|
-
private async
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
178
|
+
private async initializeCertificateManager(): Promise<void> {
|
|
179
|
+
// Extract global ACME options if any routes use auto certificates
|
|
180
|
+
const autoRoutes = this.settings.routes.filter(r =>
|
|
181
|
+
r.action.tls?.certificate === 'auto'
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (autoRoutes.length === 0 && !this.hasStaticCertRoutes()) {
|
|
185
|
+
console.log('No routes require certificate management');
|
|
189
186
|
return;
|
|
190
187
|
}
|
|
191
188
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
189
|
+
// Use the first auto route's ACME config as defaults
|
|
190
|
+
const defaultAcme = autoRoutes[0]?.action.tls?.acme;
|
|
191
|
+
|
|
192
|
+
this.certManager = new SmartCertManager(
|
|
193
|
+
this.settings.routes,
|
|
194
|
+
'./certs', // Certificate directory
|
|
195
|
+
defaultAcme ? {
|
|
196
|
+
email: defaultAcme.email,
|
|
197
|
+
useProduction: defaultAcme.useProduction,
|
|
198
|
+
port: defaultAcme.challengePort || 80
|
|
199
|
+
} : undefined
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Connect with NetworkProxy
|
|
203
|
+
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
204
|
+
this.certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
205
205
|
}
|
|
206
|
+
|
|
207
|
+
// Set route update callback for ACME challenges
|
|
208
|
+
this.certManager.setUpdateRoutesCallback(async (routes) => {
|
|
209
|
+
await this.updateRoutes(routes);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await this.certManager.initialize();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Check if we have routes with static certificates
|
|
217
|
+
*/
|
|
218
|
+
private hasStaticCertRoutes(): boolean {
|
|
219
|
+
return this.settings.routes.some(r =>
|
|
220
|
+
r.action.tls?.certificate &&
|
|
221
|
+
r.action.tls.certificate !== 'auto'
|
|
222
|
+
);
|
|
206
223
|
}
|
|
207
224
|
|
|
208
225
|
/**
|
|
@@ -215,51 +232,18 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
215
232
|
return;
|
|
216
233
|
}
|
|
217
234
|
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
// Initialize Port80Handler if enabled
|
|
221
|
-
await this.initializePort80Handler();
|
|
222
|
-
|
|
223
|
-
// Initialize CertProvisioner for unified certificate workflows
|
|
224
|
-
if (this.port80Handler) {
|
|
225
|
-
const acme = this.settings.acme!;
|
|
226
|
-
|
|
227
|
-
// Setup route forwards
|
|
228
|
-
const routeForwards = acme.routeForwards?.map(f => f) || [];
|
|
229
|
-
|
|
230
|
-
// Create CertProvisioner with appropriate parameters
|
|
231
|
-
// No longer need to support multiple configuration types
|
|
232
|
-
// Just pass the routes directly
|
|
233
|
-
this.certProvisioner = new CertProvisioner(
|
|
234
|
-
this.settings.routes,
|
|
235
|
-
this.port80Handler,
|
|
236
|
-
this.networkProxyBridge,
|
|
237
|
-
this.settings.certProvisionFunction,
|
|
238
|
-
acme.renewThresholdDays!,
|
|
239
|
-
acme.renewCheckIntervalHours!,
|
|
240
|
-
acme.autoRenew!,
|
|
241
|
-
routeForwards
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Register certificate event handler
|
|
245
|
-
this.certProvisioner.on('certificate', (certData) => {
|
|
246
|
-
this.emit('certificate', {
|
|
247
|
-
domain: certData.domain,
|
|
248
|
-
publicKey: certData.certificate,
|
|
249
|
-
privateKey: certData.privateKey,
|
|
250
|
-
expiryDate: certData.expiryDate,
|
|
251
|
-
source: certData.source,
|
|
252
|
-
isRenewal: certData.isRenewal
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
await this.certProvisioner.start();
|
|
257
|
-
console.log('CertProvisioner started');
|
|
258
|
-
}
|
|
235
|
+
// Initialize certificate manager before starting servers
|
|
236
|
+
await this.initializeCertificateManager();
|
|
259
237
|
|
|
260
238
|
// Initialize and start NetworkProxy if needed
|
|
261
239
|
if (this.settings.useNetworkProxy && this.settings.useNetworkProxy.length > 0) {
|
|
262
240
|
await this.networkProxyBridge.initialize();
|
|
241
|
+
|
|
242
|
+
// Connect NetworkProxy with certificate manager
|
|
243
|
+
if (this.certManager) {
|
|
244
|
+
this.certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
245
|
+
}
|
|
246
|
+
|
|
263
247
|
await this.networkProxyBridge.start();
|
|
264
248
|
}
|
|
265
249
|
|
|
@@ -371,27 +355,16 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
371
355
|
this.isShuttingDown = true;
|
|
372
356
|
this.portManager.setShuttingDown(true);
|
|
373
357
|
|
|
374
|
-
// Stop
|
|
375
|
-
if (this.
|
|
376
|
-
await this.
|
|
377
|
-
console.log('
|
|
358
|
+
// Stop certificate manager
|
|
359
|
+
if (this.certManager) {
|
|
360
|
+
await this.certManager.stop();
|
|
361
|
+
console.log('Certificate manager stopped');
|
|
378
362
|
}
|
|
379
363
|
|
|
380
364
|
// Stop NFTablesManager
|
|
381
365
|
await this.nftablesManager.stop();
|
|
382
366
|
console.log('NFTablesManager stopped');
|
|
383
367
|
|
|
384
|
-
// Stop the Port80Handler if running
|
|
385
|
-
if (this.port80Handler) {
|
|
386
|
-
try {
|
|
387
|
-
await this.port80Handler.stop();
|
|
388
|
-
console.log('Port80Handler stopped');
|
|
389
|
-
this.port80Handler = null;
|
|
390
|
-
} catch (err) {
|
|
391
|
-
console.log(`Error stopping Port80Handler: ${err}`);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
368
|
// Stop the connection logger
|
|
396
369
|
if (this.connectionLogger) {
|
|
397
370
|
clearInterval(this.connectionLogger);
|
|
@@ -498,104 +471,60 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
498
471
|
await this.networkProxyBridge.syncRoutesToNetworkProxy(newRoutes);
|
|
499
472
|
}
|
|
500
473
|
|
|
501
|
-
//
|
|
502
|
-
if (this.
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if (route.action.type !== 'forward') continue;
|
|
514
|
-
|
|
515
|
-
// Skip routes without TLS termination
|
|
516
|
-
if (!route.action.tls ||
|
|
517
|
-
route.action.tls.mode === 'passthrough' ||
|
|
518
|
-
!route.action.target) continue;
|
|
519
|
-
|
|
520
|
-
// Skip certificate provisioning if certificate is not auto
|
|
521
|
-
if (route.action.tls.certificate !== 'auto') continue;
|
|
522
|
-
|
|
523
|
-
const domains = Array.isArray(route.match.domains)
|
|
524
|
-
? route.match.domains
|
|
525
|
-
: [route.match.domains];
|
|
526
|
-
|
|
527
|
-
for (const domain of domains) {
|
|
528
|
-
try {
|
|
529
|
-
const provision = await this.settings.certProvisionFunction(domain);
|
|
530
|
-
|
|
531
|
-
// Skip http01 as those are handled by Port80Handler
|
|
532
|
-
if (provision !== 'http01') {
|
|
533
|
-
// Handle static certificate (e.g., DNS-01 provisioned)
|
|
534
|
-
const certObj = provision as plugins.tsclass.network.ICert;
|
|
535
|
-
const certData: ICertificateData = {
|
|
536
|
-
domain: certObj.domainName,
|
|
537
|
-
certificate: certObj.publicKey,
|
|
538
|
-
privateKey: certObj.privateKey,
|
|
539
|
-
expiryDate: new Date(certObj.validUntil),
|
|
540
|
-
routeReference: {
|
|
541
|
-
routeName: route.name
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
545
|
-
console.log(`Applied static certificate for ${domain} from certProvider`);
|
|
546
|
-
}
|
|
547
|
-
} catch (err) {
|
|
548
|
-
console.log(`certProvider error for ${domain}: ${err}`);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
474
|
+
// Update certificate manager with new routes
|
|
475
|
+
if (this.certManager) {
|
|
476
|
+
await this.certManager.stop();
|
|
477
|
+
|
|
478
|
+
this.certManager = new SmartCertManager(
|
|
479
|
+
newRoutes,
|
|
480
|
+
'./certs',
|
|
481
|
+
this.certManager.getAcmeOptions()
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
485
|
+
this.certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
552
486
|
}
|
|
553
|
-
|
|
554
|
-
|
|
487
|
+
|
|
488
|
+
await this.certManager.initialize();
|
|
555
489
|
}
|
|
556
490
|
}
|
|
557
491
|
|
|
558
492
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* @param domain The domain to request a certificate for
|
|
562
|
-
* @param routeName Optional route name to associate with the certificate
|
|
493
|
+
* Manually provision a certificate for a route
|
|
563
494
|
*/
|
|
564
|
-
public async
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
console.log(`Invalid domain format: ${domain}`);
|
|
568
|
-
return false;
|
|
495
|
+
public async provisionCertificate(routeName: string): Promise<void> {
|
|
496
|
+
if (!this.certManager) {
|
|
497
|
+
throw new Error('Certificate manager not initialized');
|
|
569
498
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
if (
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
499
|
+
|
|
500
|
+
const route = this.settings.routes.find(r => r.name === routeName);
|
|
501
|
+
if (!route) {
|
|
502
|
+
throw new Error(`Route ${routeName} not found`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
await this.certManager.provisionCertificate(route);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Force renewal of a certificate
|
|
510
|
+
*/
|
|
511
|
+
public async renewCertificate(routeName: string): Promise<void> {
|
|
512
|
+
if (!this.certManager) {
|
|
513
|
+
throw new Error('Certificate manager not initialized');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
await this.certManager.renewCertificate(routeName);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Get certificate status for a route
|
|
521
|
+
*/
|
|
522
|
+
public getCertificateStatus(routeName: string): ICertStatus | undefined {
|
|
523
|
+
if (!this.certManager) {
|
|
524
|
+
return undefined;
|
|
595
525
|
}
|
|
596
526
|
|
|
597
|
-
|
|
598
|
-
return this.networkProxyBridge.requestCertificate(domain);
|
|
527
|
+
return this.certManager.getCertificateStatus(routeName);
|
|
599
528
|
}
|
|
600
529
|
|
|
601
530
|
/**
|
|
@@ -685,8 +614,8 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
685
614
|
keepAliveConnections,
|
|
686
615
|
networkProxyConnections,
|
|
687
616
|
terminationStats,
|
|
688
|
-
acmeEnabled: !!this.
|
|
689
|
-
port80HandlerPort: this.
|
|
617
|
+
acmeEnabled: !!this.certManager,
|
|
618
|
+
port80HandlerPort: this.certManager ? 80 : null,
|
|
690
619
|
routes: this.routeManager.getListeningPorts().length,
|
|
691
620
|
listeningPorts: this.portManager.getListeningPorts(),
|
|
692
621
|
activePorts: this.portManager.getListeningPorts().length
|
|
@@ -735,51 +664,4 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
735
664
|
return this.nftablesManager.getStatus();
|
|
736
665
|
}
|
|
737
666
|
|
|
738
|
-
/**
|
|
739
|
-
* Get status of certificates managed by Port80Handler
|
|
740
|
-
*/
|
|
741
|
-
public getCertificateStatus(): any {
|
|
742
|
-
if (!this.port80Handler) {
|
|
743
|
-
return {
|
|
744
|
-
enabled: false,
|
|
745
|
-
message: 'Port80Handler is not enabled'
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
// Get eligible domains
|
|
750
|
-
const eligibleDomains = this.getEligibleDomainsForCertificates();
|
|
751
|
-
const certificateStatus: Record<string, any> = {};
|
|
752
|
-
|
|
753
|
-
// Check each domain
|
|
754
|
-
for (const domain of eligibleDomains) {
|
|
755
|
-
const cert = this.port80Handler.getCertificate(domain);
|
|
756
|
-
|
|
757
|
-
if (cert) {
|
|
758
|
-
const now = new Date();
|
|
759
|
-
const expiryDate = cert.expiryDate;
|
|
760
|
-
const daysRemaining = Math.floor((expiryDate.getTime() - now.getTime()) / (24 * 60 * 60 * 1000));
|
|
761
|
-
|
|
762
|
-
certificateStatus[domain] = {
|
|
763
|
-
status: 'valid',
|
|
764
|
-
expiryDate: expiryDate.toISOString(),
|
|
765
|
-
daysRemaining,
|
|
766
|
-
renewalNeeded: daysRemaining <= (this.settings.acme?.renewThresholdDays ?? 0)
|
|
767
|
-
};
|
|
768
|
-
} else {
|
|
769
|
-
certificateStatus[domain] = {
|
|
770
|
-
status: 'missing',
|
|
771
|
-
message: 'No certificate found'
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
const acme = this.settings.acme!;
|
|
777
|
-
return {
|
|
778
|
-
enabled: true,
|
|
779
|
-
port: acme.port!,
|
|
780
|
-
useProduction: acme.useProduction!,
|
|
781
|
-
autoRenew: acme.autoRenew!,
|
|
782
|
-
certificates: certificateStatus
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
667
|
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import type { IAcmeOptions } from '../models/certificate-types.js';
|
|
4
|
-
import { ensureCertificateDirectory } from '../utils/certificate-helpers.js';
|
|
5
|
-
// We'll need to update this import when we move the Port80Handler
|
|
6
|
-
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Factory to create a Port80Handler with common setup.
|
|
10
|
-
* Ensures the certificate store directory exists and instantiates the handler.
|
|
11
|
-
* @param options Port80Handler configuration options
|
|
12
|
-
* @returns A new Port80Handler instance
|
|
13
|
-
*/
|
|
14
|
-
export function buildPort80Handler(
|
|
15
|
-
options: IAcmeOptions
|
|
16
|
-
): Port80Handler {
|
|
17
|
-
if (options.certificateStore) {
|
|
18
|
-
ensureCertificateDirectory(options.certificateStore);
|
|
19
|
-
console.log(`Ensured certificate store directory: ${options.certificateStore}`);
|
|
20
|
-
}
|
|
21
|
-
return new Port80Handler(options);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Creates default ACME options with sensible defaults
|
|
26
|
-
* @param email Account email for ACME provider
|
|
27
|
-
* @param certificateStore Path to store certificates
|
|
28
|
-
* @param useProduction Whether to use production ACME servers
|
|
29
|
-
* @returns Configured ACME options
|
|
30
|
-
*/
|
|
31
|
-
export function createDefaultAcmeOptions(
|
|
32
|
-
email: string,
|
|
33
|
-
certificateStore: string,
|
|
34
|
-
useProduction: boolean = false
|
|
35
|
-
): IAcmeOptions {
|
|
36
|
-
return {
|
|
37
|
-
accountEmail: email,
|
|
38
|
-
enabled: true,
|
|
39
|
-
port: 80,
|
|
40
|
-
useProduction,
|
|
41
|
-
httpsRedirectPort: 443,
|
|
42
|
-
renewThresholdDays: 30,
|
|
43
|
-
renewCheckIntervalHours: 24,
|
|
44
|
-
autoRenew: true,
|
|
45
|
-
certificateStore,
|
|
46
|
-
skipConfiguredCerts: false
|
|
47
|
-
};
|
|
48
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import type { IAcmeOptions, ICertificateData } from '../models/certificate-types.js';
|
|
3
|
-
import { CertificateEvents } from '../events/certificate-events.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Manages ACME challenges and certificate validation
|
|
7
|
-
*/
|
|
8
|
-
export class AcmeChallengeHandler extends plugins.EventEmitter {
|
|
9
|
-
private options: IAcmeOptions;
|
|
10
|
-
private client: any; // ACME client from plugins
|
|
11
|
-
private pendingChallenges: Map<string, any>;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Creates a new ACME challenge handler
|
|
15
|
-
* @param options ACME configuration options
|
|
16
|
-
*/
|
|
17
|
-
constructor(options: IAcmeOptions) {
|
|
18
|
-
super();
|
|
19
|
-
this.options = options;
|
|
20
|
-
this.pendingChallenges = new Map();
|
|
21
|
-
|
|
22
|
-
// Initialize ACME client if needed
|
|
23
|
-
// This is just a placeholder implementation since we don't use the actual
|
|
24
|
-
// client directly in this implementation - it's handled by Port80Handler
|
|
25
|
-
this.client = null;
|
|
26
|
-
console.log('Created challenge handler with options:',
|
|
27
|
-
options.accountEmail,
|
|
28
|
-
options.useProduction ? 'production' : 'staging'
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Gets or creates the ACME account key
|
|
34
|
-
*/
|
|
35
|
-
private getAccountKey(): Buffer {
|
|
36
|
-
// Implementation details would depend on plugin requirements
|
|
37
|
-
// This is a simplified version
|
|
38
|
-
if (!this.options.certificateStore) {
|
|
39
|
-
throw new Error('Certificate store is required for ACME challenges');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// This is just a placeholder - actual implementation would check for
|
|
43
|
-
// existing account key and create one if needed
|
|
44
|
-
return Buffer.from('account-key-placeholder');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Validates a domain using HTTP-01 challenge
|
|
49
|
-
* @param domain Domain to validate
|
|
50
|
-
* @param challengeToken ACME challenge token
|
|
51
|
-
* @param keyAuthorization Key authorization for the challenge
|
|
52
|
-
*/
|
|
53
|
-
public async handleHttpChallenge(
|
|
54
|
-
domain: string,
|
|
55
|
-
challengeToken: string,
|
|
56
|
-
keyAuthorization: string
|
|
57
|
-
): Promise<void> {
|
|
58
|
-
// Store challenge for response
|
|
59
|
-
this.pendingChallenges.set(challengeToken, keyAuthorization);
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
// Wait for challenge validation - this would normally be handled by the ACME client
|
|
63
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
64
|
-
this.emit(CertificateEvents.CERTIFICATE_ISSUED, {
|
|
65
|
-
domain,
|
|
66
|
-
success: true
|
|
67
|
-
});
|
|
68
|
-
} catch (error) {
|
|
69
|
-
this.emit(CertificateEvents.CERTIFICATE_FAILED, {
|
|
70
|
-
domain,
|
|
71
|
-
error: error instanceof Error ? error.message : String(error),
|
|
72
|
-
isRenewal: false
|
|
73
|
-
});
|
|
74
|
-
throw error;
|
|
75
|
-
} finally {
|
|
76
|
-
// Clean up the challenge
|
|
77
|
-
this.pendingChallenges.delete(challengeToken);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Responds to an HTTP-01 challenge request
|
|
83
|
-
* @param token Challenge token from the request path
|
|
84
|
-
* @returns The key authorization if found
|
|
85
|
-
*/
|
|
86
|
-
public getChallengeResponse(token: string): string | null {
|
|
87
|
-
return this.pendingChallenges.get(token) || null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Checks if a request path is an ACME challenge
|
|
92
|
-
* @param path Request path
|
|
93
|
-
* @returns True if this is an ACME challenge request
|
|
94
|
-
*/
|
|
95
|
-
public isAcmeChallenge(path: string): boolean {
|
|
96
|
-
return path.startsWith('/.well-known/acme-challenge/');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Extracts the challenge token from an ACME challenge path
|
|
101
|
-
* @param path Request path
|
|
102
|
-
* @returns The challenge token if valid
|
|
103
|
-
*/
|
|
104
|
-
public extractChallengeToken(path: string): string | null {
|
|
105
|
-
if (!this.isAcmeChallenge(path)) return null;
|
|
106
|
-
|
|
107
|
-
const parts = path.split('/');
|
|
108
|
-
return parts[parts.length - 1] || null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Certificate-related events emitted by certificate management components
|
|
3
|
-
*/
|
|
4
|
-
export enum CertificateEvents {
|
|
5
|
-
CERTIFICATE_ISSUED = 'certificate-issued',
|
|
6
|
-
CERTIFICATE_RENEWED = 'certificate-renewed',
|
|
7
|
-
CERTIFICATE_FAILED = 'certificate-failed',
|
|
8
|
-
CERTIFICATE_EXPIRING = 'certificate-expiring',
|
|
9
|
-
CERTIFICATE_APPLIED = 'certificate-applied',
|
|
10
|
-
// Events moved from Port80Handler for compatibility
|
|
11
|
-
MANAGER_STARTED = 'manager-started',
|
|
12
|
-
MANAGER_STOPPED = 'manager-stopped',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Port80Handler-specific events including certificate-related ones
|
|
17
|
-
* @deprecated Use CertificateEvents and HttpEvents instead
|
|
18
|
-
*/
|
|
19
|
-
export enum Port80HandlerEvents {
|
|
20
|
-
CERTIFICATE_ISSUED = 'certificate-issued',
|
|
21
|
-
CERTIFICATE_RENEWED = 'certificate-renewed',
|
|
22
|
-
CERTIFICATE_FAILED = 'certificate-failed',
|
|
23
|
-
CERTIFICATE_EXPIRING = 'certificate-expiring',
|
|
24
|
-
MANAGER_STARTED = 'manager-started',
|
|
25
|
-
MANAGER_STOPPED = 'manager-stopped',
|
|
26
|
-
REQUEST_FORWARDED = 'request-forwarded',
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Certificate provider events
|
|
31
|
-
*/
|
|
32
|
-
export enum CertProvisionerEvents {
|
|
33
|
-
CERTIFICATE_ISSUED = 'certificate',
|
|
34
|
-
CERTIFICATE_RENEWED = 'certificate',
|
|
35
|
-
CERTIFICATE_FAILED = 'certificate-failed'
|
|
36
|
-
}
|