@push.rocks/smartproxy 18.0.2 → 18.2.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/http/index.d.ts +1 -9
- package/dist_ts/http/index.js +5 -11
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +4 -2
- package/dist_ts/proxies/network-proxy/network-proxy.js +3 -1
- 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 +41 -4
- 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/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 +79 -196
- package/package.json +7 -5
- package/readme.md +224 -10
- package/readme.plan.md +1405 -617
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/http/index.ts +5 -12
- package/ts/plugins.ts +4 -1
- package/ts/proxies/network-proxy/network-proxy.ts +3 -0
- package/ts/proxies/network-proxy/websocket-handler.ts +38 -3
- 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/route-types.ts +33 -3
- 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 +105 -222
|
@@ -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
|
|
@@ -180,29 +174,53 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
180
174
|
public settings: ISmartProxyOptions;
|
|
181
175
|
|
|
182
176
|
/**
|
|
183
|
-
* Initialize
|
|
177
|
+
* Initialize certificate manager
|
|
184
178
|
*/
|
|
185
|
-
private async
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
179
|
+
private async initializeCertificateManager(): Promise<void> {
|
|
180
|
+
// Extract global ACME options if any routes use auto certificates
|
|
181
|
+
const autoRoutes = this.settings.routes.filter(r =>
|
|
182
|
+
r.action.tls?.certificate === 'auto'
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (autoRoutes.length === 0 && !this.hasStaticCertRoutes()) {
|
|
186
|
+
console.log('No routes require certificate management');
|
|
189
187
|
return;
|
|
190
188
|
}
|
|
191
189
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
190
|
+
// Use the first auto route's ACME config as defaults
|
|
191
|
+
const defaultAcme = autoRoutes[0]?.action.tls?.acme;
|
|
192
|
+
|
|
193
|
+
this.certManager = new SmartCertManager(
|
|
194
|
+
this.settings.routes,
|
|
195
|
+
'./certs', // Certificate directory
|
|
196
|
+
defaultAcme ? {
|
|
197
|
+
email: defaultAcme.email,
|
|
198
|
+
useProduction: defaultAcme.useProduction,
|
|
199
|
+
port: defaultAcme.challengePort || 80
|
|
200
|
+
} : undefined
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Connect with NetworkProxy
|
|
204
|
+
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
205
|
+
this.certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
205
206
|
}
|
|
207
|
+
|
|
208
|
+
// Set route update callback for ACME challenges
|
|
209
|
+
this.certManager.setUpdateRoutesCallback(async (routes) => {
|
|
210
|
+
await this.updateRoutes(routes);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await this.certManager.initialize();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Check if we have routes with static certificates
|
|
218
|
+
*/
|
|
219
|
+
private hasStaticCertRoutes(): boolean {
|
|
220
|
+
return this.settings.routes.some(r =>
|
|
221
|
+
r.action.tls?.certificate &&
|
|
222
|
+
r.action.tls.certificate !== 'auto'
|
|
223
|
+
);
|
|
206
224
|
}
|
|
207
225
|
|
|
208
226
|
/**
|
|
@@ -215,51 +233,18 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
215
233
|
return;
|
|
216
234
|
}
|
|
217
235
|
|
|
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
|
-
}
|
|
236
|
+
// Initialize certificate manager before starting servers
|
|
237
|
+
await this.initializeCertificateManager();
|
|
259
238
|
|
|
260
239
|
// Initialize and start NetworkProxy if needed
|
|
261
240
|
if (this.settings.useNetworkProxy && this.settings.useNetworkProxy.length > 0) {
|
|
262
241
|
await this.networkProxyBridge.initialize();
|
|
242
|
+
|
|
243
|
+
// Connect NetworkProxy with certificate manager
|
|
244
|
+
if (this.certManager) {
|
|
245
|
+
this.certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
246
|
+
}
|
|
247
|
+
|
|
263
248
|
await this.networkProxyBridge.start();
|
|
264
249
|
}
|
|
265
250
|
|
|
@@ -371,27 +356,16 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
371
356
|
this.isShuttingDown = true;
|
|
372
357
|
this.portManager.setShuttingDown(true);
|
|
373
358
|
|
|
374
|
-
// Stop
|
|
375
|
-
if (this.
|
|
376
|
-
await this.
|
|
377
|
-
console.log('
|
|
359
|
+
// Stop certificate manager
|
|
360
|
+
if (this.certManager) {
|
|
361
|
+
await this.certManager.stop();
|
|
362
|
+
console.log('Certificate manager stopped');
|
|
378
363
|
}
|
|
379
364
|
|
|
380
365
|
// Stop NFTablesManager
|
|
381
366
|
await this.nftablesManager.stop();
|
|
382
367
|
console.log('NFTablesManager stopped');
|
|
383
368
|
|
|
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
369
|
// Stop the connection logger
|
|
396
370
|
if (this.connectionLogger) {
|
|
397
371
|
clearInterval(this.connectionLogger);
|
|
@@ -498,104 +472,60 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
498
472
|
await this.networkProxyBridge.syncRoutesToNetworkProxy(newRoutes);
|
|
499
473
|
}
|
|
500
474
|
|
|
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
|
-
}
|
|
475
|
+
// Update certificate manager with new routes
|
|
476
|
+
if (this.certManager) {
|
|
477
|
+
await this.certManager.stop();
|
|
478
|
+
|
|
479
|
+
this.certManager = new SmartCertManager(
|
|
480
|
+
newRoutes,
|
|
481
|
+
'./certs',
|
|
482
|
+
this.certManager.getAcmeOptions()
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
486
|
+
this.certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
552
487
|
}
|
|
553
|
-
|
|
554
|
-
|
|
488
|
+
|
|
489
|
+
await this.certManager.initialize();
|
|
555
490
|
}
|
|
556
491
|
}
|
|
557
492
|
|
|
558
493
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* @param domain The domain to request a certificate for
|
|
562
|
-
* @param routeName Optional route name to associate with the certificate
|
|
494
|
+
* Manually provision a certificate for a route
|
|
563
495
|
*/
|
|
564
|
-
public async
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
console.log(`Invalid domain format: ${domain}`);
|
|
568
|
-
return false;
|
|
496
|
+
public async provisionCertificate(routeName: string): Promise<void> {
|
|
497
|
+
if (!this.certManager) {
|
|
498
|
+
throw new Error('Certificate manager not initialized');
|
|
569
499
|
}
|
|
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
|
-
|
|
500
|
+
|
|
501
|
+
const route = this.settings.routes.find(r => r.name === routeName);
|
|
502
|
+
if (!route) {
|
|
503
|
+
throw new Error(`Route ${routeName} not found`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
await this.certManager.provisionCertificate(route);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Force renewal of a certificate
|
|
511
|
+
*/
|
|
512
|
+
public async renewCertificate(routeName: string): Promise<void> {
|
|
513
|
+
if (!this.certManager) {
|
|
514
|
+
throw new Error('Certificate manager not initialized');
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
await this.certManager.renewCertificate(routeName);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Get certificate status for a route
|
|
522
|
+
*/
|
|
523
|
+
public getCertificateStatus(routeName: string): ICertStatus | undefined {
|
|
524
|
+
if (!this.certManager) {
|
|
525
|
+
return undefined;
|
|
595
526
|
}
|
|
596
527
|
|
|
597
|
-
|
|
598
|
-
return this.networkProxyBridge.requestCertificate(domain);
|
|
528
|
+
return this.certManager.getCertificateStatus(routeName);
|
|
599
529
|
}
|
|
600
530
|
|
|
601
531
|
/**
|
|
@@ -685,8 +615,8 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
685
615
|
keepAliveConnections,
|
|
686
616
|
networkProxyConnections,
|
|
687
617
|
terminationStats,
|
|
688
|
-
acmeEnabled: !!this.
|
|
689
|
-
port80HandlerPort: this.
|
|
618
|
+
acmeEnabled: !!this.certManager,
|
|
619
|
+
port80HandlerPort: this.certManager ? 80 : null,
|
|
690
620
|
routes: this.routeManager.getListeningPorts().length,
|
|
691
621
|
listeningPorts: this.portManager.getListeningPorts(),
|
|
692
622
|
activePorts: this.portManager.getListeningPorts().length
|
|
@@ -735,51 +665,4 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
735
665
|
return this.nftablesManager.getStatus();
|
|
736
666
|
}
|
|
737
667
|
|
|
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
668
|
}
|