@push.rocks/smartproxy 5.0.0 → 6.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.
Files changed (78) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/classes.pp.interfaces.d.ts +23 -0
  3. package/dist_ts/classes.pp.networkproxybridge.d.ts +15 -1
  4. package/dist_ts/classes.pp.networkproxybridge.js +116 -21
  5. package/dist_ts/classes.pp.portproxy.d.ts +20 -4
  6. package/dist_ts/classes.pp.portproxy.js +321 -22
  7. package/dist_ts/index.d.ts +6 -6
  8. package/dist_ts/index.js +7 -7
  9. package/dist_ts/networkproxy/classes.np.certificatemanager.d.ts +77 -0
  10. package/dist_ts/networkproxy/classes.np.certificatemanager.js +354 -0
  11. package/dist_ts/networkproxy/classes.np.connectionpool.d.ts +47 -0
  12. package/dist_ts/networkproxy/classes.np.connectionpool.js +210 -0
  13. package/dist_ts/networkproxy/classes.np.networkproxy.d.ts +117 -0
  14. package/dist_ts/networkproxy/classes.np.networkproxy.js +375 -0
  15. package/dist_ts/networkproxy/classes.np.requesthandler.d.ts +51 -0
  16. package/dist_ts/networkproxy/classes.np.requesthandler.js +210 -0
  17. package/dist_ts/networkproxy/classes.np.types.d.ts +82 -0
  18. package/dist_ts/networkproxy/classes.np.types.js +35 -0
  19. package/dist_ts/networkproxy/classes.np.websockethandler.d.ts +38 -0
  20. package/dist_ts/networkproxy/classes.np.websockethandler.js +188 -0
  21. package/dist_ts/networkproxy/index.d.ts +6 -0
  22. package/dist_ts/networkproxy/index.js +8 -0
  23. package/dist_ts/nfttablesproxy/classes.nftablesproxy.d.ts +219 -0
  24. package/dist_ts/nfttablesproxy/classes.nftablesproxy.js +1542 -0
  25. package/dist_ts/port80handler/classes.port80handler.d.ts +260 -0
  26. package/dist_ts/port80handler/classes.port80handler.js +928 -0
  27. package/dist_ts/smartproxy/classes.pp.connectionhandler.d.ts +39 -0
  28. package/dist_ts/smartproxy/classes.pp.connectionhandler.js +754 -0
  29. package/dist_ts/smartproxy/classes.pp.connectionmanager.d.ts +78 -0
  30. package/dist_ts/smartproxy/classes.pp.connectionmanager.js +378 -0
  31. package/dist_ts/smartproxy/classes.pp.domainconfigmanager.d.ts +55 -0
  32. package/dist_ts/smartproxy/classes.pp.domainconfigmanager.js +103 -0
  33. package/dist_ts/smartproxy/classes.pp.interfaces.d.ts +133 -0
  34. package/dist_ts/smartproxy/classes.pp.interfaces.js +2 -0
  35. package/dist_ts/smartproxy/classes.pp.networkproxybridge.d.ts +57 -0
  36. package/dist_ts/smartproxy/classes.pp.networkproxybridge.js +306 -0
  37. package/dist_ts/smartproxy/classes.pp.portrangemanager.d.ts +56 -0
  38. package/dist_ts/smartproxy/classes.pp.portrangemanager.js +179 -0
  39. package/dist_ts/smartproxy/classes.pp.securitymanager.d.ts +47 -0
  40. package/dist_ts/smartproxy/classes.pp.securitymanager.js +126 -0
  41. package/dist_ts/smartproxy/classes.pp.snihandler.d.ts +153 -0
  42. package/dist_ts/smartproxy/classes.pp.snihandler.js +1053 -0
  43. package/dist_ts/smartproxy/classes.pp.timeoutmanager.d.ts +47 -0
  44. package/dist_ts/smartproxy/classes.pp.timeoutmanager.js +154 -0
  45. package/dist_ts/smartproxy/classes.pp.tlsalert.d.ts +149 -0
  46. package/dist_ts/smartproxy/classes.pp.tlsalert.js +225 -0
  47. package/dist_ts/smartproxy/classes.pp.tlsmanager.d.ts +57 -0
  48. package/dist_ts/smartproxy/classes.pp.tlsmanager.js +132 -0
  49. package/dist_ts/smartproxy/classes.smartproxy.d.ts +64 -0
  50. package/dist_ts/smartproxy/classes.smartproxy.js +567 -0
  51. package/package.json +1 -1
  52. package/readme.md +77 -27
  53. package/ts/00_commitinfo_data.ts +1 -1
  54. package/ts/index.ts +6 -6
  55. package/ts/networkproxy/classes.np.certificatemanager.ts +398 -0
  56. package/ts/networkproxy/classes.np.connectionpool.ts +241 -0
  57. package/ts/networkproxy/classes.np.networkproxy.ts +469 -0
  58. package/ts/networkproxy/classes.np.requesthandler.ts +278 -0
  59. package/ts/networkproxy/classes.np.types.ts +123 -0
  60. package/ts/networkproxy/classes.np.websockethandler.ts +226 -0
  61. package/ts/networkproxy/index.ts +7 -0
  62. package/ts/{classes.port80handler.ts → port80handler/classes.port80handler.ts} +249 -1
  63. package/ts/{classes.pp.connectionhandler.ts → smartproxy/classes.pp.connectionhandler.ts} +1 -1
  64. package/ts/{classes.pp.connectionmanager.ts → smartproxy/classes.pp.connectionmanager.ts} +1 -1
  65. package/ts/{classes.pp.domainconfigmanager.ts → smartproxy/classes.pp.domainconfigmanager.ts} +1 -1
  66. package/ts/{classes.pp.interfaces.ts → smartproxy/classes.pp.interfaces.ts} +31 -5
  67. package/ts/{classes.pp.networkproxybridge.ts → smartproxy/classes.pp.networkproxybridge.ts} +129 -28
  68. package/ts/{classes.pp.securitymanager.ts → smartproxy/classes.pp.securitymanager.ts} +1 -1
  69. package/ts/{classes.pp.tlsmanager.ts → smartproxy/classes.pp.tlsmanager.ts} +1 -1
  70. package/ts/smartproxy/classes.smartproxy.ts +679 -0
  71. package/ts/classes.networkproxy.ts +0 -1730
  72. package/ts/classes.pp.acmemanager.ts +0 -149
  73. package/ts/classes.pp.portproxy.ts +0 -344
  74. /package/ts/{classes.nftablesproxy.ts → nfttablesproxy/classes.nftablesproxy.ts} +0 -0
  75. /package/ts/{classes.pp.portrangemanager.ts → smartproxy/classes.pp.portrangemanager.ts} +0 -0
  76. /package/ts/{classes.pp.snihandler.ts → smartproxy/classes.pp.snihandler.ts} +0 -0
  77. /package/ts/{classes.pp.timeoutmanager.ts → smartproxy/classes.pp.timeoutmanager.ts} +0 -0
  78. /package/ts/{classes.pp.tlsalert.ts → smartproxy/classes.pp.tlsalert.ts} +0 -0
@@ -1,5 +1,7 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
  import { IncomingMessage, ServerResponse } from 'http';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
3
5
 
4
6
  /**
5
7
  * Custom error classes for better error handling
@@ -73,6 +75,10 @@ interface IPort80HandlerOptions {
73
75
  renewThresholdDays?: number;
74
76
  httpsRedirectPort?: number;
75
77
  renewCheckIntervalHours?: number;
78
+ enabled?: boolean; // Whether ACME is enabled at all
79
+ autoRenew?: boolean; // Whether to automatically renew certificates
80
+ certificateStore?: string; // Directory to store certificates
81
+ skipConfiguredCerts?: boolean; // Skip domains that already have certificates
76
82
  }
77
83
 
78
84
  /**
@@ -145,6 +151,10 @@ export class Port80Handler extends plugins.EventEmitter {
145
151
  renewThresholdDays: options.renewThresholdDays ?? 10, // Changed to 10 days as per requirements
146
152
  httpsRedirectPort: options.httpsRedirectPort ?? 443,
147
153
  renewCheckIntervalHours: options.renewCheckIntervalHours ?? 24,
154
+ enabled: options.enabled ?? true, // Enable by default
155
+ autoRenew: options.autoRenew ?? true, // Auto-renew by default
156
+ certificateStore: options.certificateStore ?? './certs', // Default store location
157
+ skipConfiguredCerts: options.skipConfiguredCerts ?? false
148
158
  };
149
159
  }
150
160
 
@@ -160,8 +170,19 @@ export class Port80Handler extends plugins.EventEmitter {
160
170
  throw new ServerError('Server is shutting down');
161
171
  }
162
172
 
173
+ // Skip if disabled
174
+ if (this.options.enabled === false) {
175
+ console.log('Port80Handler is disabled, skipping start');
176
+ return;
177
+ }
178
+
163
179
  return new Promise((resolve, reject) => {
164
180
  try {
181
+ // Load certificates from store if enabled
182
+ if (this.options.certificateStore) {
183
+ this.loadCertificatesFromStore();
184
+ }
185
+
165
186
  this.server = plugins.http.createServer((req, res) => this.handleRequest(req, res));
166
187
 
167
188
  this.server.on('error', (error: NodeJS.ErrnoException) => {
@@ -332,6 +353,11 @@ export class Port80Handler extends plugins.EventEmitter {
332
353
 
333
354
  console.log(`Certificate set for ${domain}`);
334
355
 
356
+ // Save certificate to store if enabled
357
+ if (this.options.certificateStore) {
358
+ this.saveCertificateToStore(domain, certificate, privateKey);
359
+ }
360
+
335
361
  // Emit certificate event
336
362
  this.emitCertificateEvent(Port80HandlerEvents.CERTIFICATE_ISSUED, {
337
363
  domain,
@@ -365,6 +391,135 @@ export class Port80Handler extends plugins.EventEmitter {
365
391
  };
366
392
  }
367
393
 
394
+ /**
395
+ * Saves a certificate to the filesystem store
396
+ * @param domain The domain for the certificate
397
+ * @param certificate The certificate (PEM format)
398
+ * @param privateKey The private key (PEM format)
399
+ * @private
400
+ */
401
+ private saveCertificateToStore(domain: string, certificate: string, privateKey: string): void {
402
+ // Skip if certificate store is not enabled
403
+ if (!this.options.certificateStore) return;
404
+
405
+ try {
406
+ const storePath = this.options.certificateStore;
407
+
408
+ // Ensure the directory exists
409
+ if (!fs.existsSync(storePath)) {
410
+ fs.mkdirSync(storePath, { recursive: true });
411
+ console.log(`Created certificate store directory: ${storePath}`);
412
+ }
413
+
414
+ const certPath = path.join(storePath, `${domain}.cert.pem`);
415
+ const keyPath = path.join(storePath, `${domain}.key.pem`);
416
+
417
+ // Write certificate and private key files
418
+ fs.writeFileSync(certPath, certificate);
419
+ fs.writeFileSync(keyPath, privateKey);
420
+
421
+ // Set secure permissions for private key
422
+ try {
423
+ fs.chmodSync(keyPath, 0o600);
424
+ } catch (err) {
425
+ console.log(`Warning: Could not set secure permissions on ${keyPath}`);
426
+ }
427
+
428
+ console.log(`Saved certificate for ${domain} to ${certPath}`);
429
+ } catch (err) {
430
+ console.error(`Error saving certificate for ${domain}:`, err);
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Loads certificates from the certificate store
436
+ * @private
437
+ */
438
+ private loadCertificatesFromStore(): void {
439
+ if (!this.options.certificateStore) return;
440
+
441
+ try {
442
+ const storePath = this.options.certificateStore;
443
+
444
+ // Ensure the directory exists
445
+ if (!fs.existsSync(storePath)) {
446
+ fs.mkdirSync(storePath, { recursive: true });
447
+ console.log(`Created certificate store directory: ${storePath}`);
448
+ return;
449
+ }
450
+
451
+ // Get list of certificate files
452
+ const files = fs.readdirSync(storePath);
453
+ const certFiles = files.filter(file => file.endsWith('.cert.pem'));
454
+
455
+ // Load each certificate
456
+ for (const certFile of certFiles) {
457
+ const domain = certFile.replace('.cert.pem', '');
458
+ const keyFile = `${domain}.key.pem`;
459
+
460
+ // Skip if key file doesn't exist
461
+ if (!files.includes(keyFile)) {
462
+ console.log(`Warning: Found certificate for ${domain} but no key file`);
463
+ continue;
464
+ }
465
+
466
+ // Skip if we should skip configured certs
467
+ if (this.options.skipConfiguredCerts) {
468
+ const domainInfo = this.domainCertificates.get(domain);
469
+ if (domainInfo && domainInfo.certObtained) {
470
+ console.log(`Skipping already configured certificate for ${domain}`);
471
+ continue;
472
+ }
473
+ }
474
+
475
+ // Load certificate and key
476
+ try {
477
+ const certificate = fs.readFileSync(path.join(storePath, certFile), 'utf8');
478
+ const privateKey = fs.readFileSync(path.join(storePath, keyFile), 'utf8');
479
+
480
+ // Extract expiry date
481
+ let expiryDate: Date | undefined;
482
+ try {
483
+ const matches = certificate.match(/Not After\s*:\s*(.*?)(?:\n|$)/i);
484
+ if (matches && matches[1]) {
485
+ expiryDate = new Date(matches[1]);
486
+ }
487
+ } catch (err) {
488
+ console.log(`Warning: Could not extract expiry date from certificate for ${domain}`);
489
+ }
490
+
491
+ // Check if domain is already registered
492
+ let domainInfo = this.domainCertificates.get(domain);
493
+ if (!domainInfo) {
494
+ // Register domain if not already registered
495
+ domainInfo = {
496
+ options: {
497
+ domainName: domain,
498
+ sslRedirect: true,
499
+ acmeMaintenance: true
500
+ },
501
+ certObtained: false,
502
+ obtainingInProgress: false
503
+ };
504
+ this.domainCertificates.set(domain, domainInfo);
505
+ }
506
+
507
+ // Set certificate
508
+ domainInfo.certificate = certificate;
509
+ domainInfo.privateKey = privateKey;
510
+ domainInfo.certObtained = true;
511
+ domainInfo.expiryDate = expiryDate;
512
+
513
+ console.log(`Loaded certificate for ${domain} from store, valid until ${expiryDate?.toISOString() || 'unknown'}`);
514
+ } catch (err) {
515
+ console.error(`Error loading certificate for ${domain}:`, err);
516
+ }
517
+ }
518
+ } catch (err) {
519
+ console.error('Error loading certificates from store:', err);
520
+ }
521
+ }
522
+
368
523
  /**
369
524
  * Check if a domain is a glob pattern
370
525
  * @param domain Domain to check
@@ -710,6 +865,11 @@ export class Port80Handler extends plugins.EventEmitter {
710
865
 
711
866
  console.log(`Certificate ${isRenewal ? 'renewed' : 'obtained'} for ${domain}`);
712
867
 
868
+ // Save the certificate to the store if enabled
869
+ if (this.options.certificateStore) {
870
+ this.saveCertificateToStore(domain, certificate, privateKey);
871
+ }
872
+
713
873
  // Emit the appropriate event
714
874
  const eventType = isRenewal
715
875
  ? Port80HandlerEvents.CERTIFICATE_RENEWED
@@ -834,6 +994,12 @@ export class Port80Handler extends plugins.EventEmitter {
834
994
  return;
835
995
  }
836
996
 
997
+ // Skip renewal if auto-renewal is disabled
998
+ if (this.options.autoRenew === false) {
999
+ console.log('Auto-renewal is disabled, skipping certificate renewal check');
1000
+ return;
1001
+ }
1002
+
837
1003
  console.log('Checking for certificates that need renewal...');
838
1004
 
839
1005
  const now = new Date();
@@ -928,4 +1094,86 @@ export class Port80Handler extends plugins.EventEmitter {
928
1094
  private emitCertificateEvent(eventType: Port80HandlerEvents, data: ICertificateData): void {
929
1095
  this.emit(eventType, data);
930
1096
  }
1097
+
1098
+ /**
1099
+ * Gets all domains and their certificate status
1100
+ * @returns Map of domains to certificate status
1101
+ */
1102
+ public getDomainCertificateStatus(): Map<string, {
1103
+ certObtained: boolean;
1104
+ expiryDate?: Date;
1105
+ daysRemaining?: number;
1106
+ obtainingInProgress: boolean;
1107
+ lastRenewalAttempt?: Date;
1108
+ }> {
1109
+ const result = new Map<string, {
1110
+ certObtained: boolean;
1111
+ expiryDate?: Date;
1112
+ daysRemaining?: number;
1113
+ obtainingInProgress: boolean;
1114
+ lastRenewalAttempt?: Date;
1115
+ }>();
1116
+
1117
+ const now = new Date();
1118
+
1119
+ for (const [domain, domainInfo] of this.domainCertificates.entries()) {
1120
+ // Skip glob patterns
1121
+ if (this.isGlobPattern(domain)) continue;
1122
+
1123
+ const status: {
1124
+ certObtained: boolean;
1125
+ expiryDate?: Date;
1126
+ daysRemaining?: number;
1127
+ obtainingInProgress: boolean;
1128
+ lastRenewalAttempt?: Date;
1129
+ } = {
1130
+ certObtained: domainInfo.certObtained,
1131
+ expiryDate: domainInfo.expiryDate,
1132
+ obtainingInProgress: domainInfo.obtainingInProgress,
1133
+ lastRenewalAttempt: domainInfo.lastRenewalAttempt
1134
+ };
1135
+
1136
+ // Calculate days remaining if expiry date is available
1137
+ if (domainInfo.expiryDate) {
1138
+ const daysRemaining = Math.ceil(
1139
+ (domainInfo.expiryDate.getTime() - now.getTime()) / (24 * 60 * 60 * 1000)
1140
+ );
1141
+ status.daysRemaining = daysRemaining;
1142
+ }
1143
+
1144
+ result.set(domain, status);
1145
+ }
1146
+
1147
+ return result;
1148
+ }
1149
+
1150
+ /**
1151
+ * Gets information about managed domains
1152
+ * @returns Array of domain information
1153
+ */
1154
+ public getManagedDomains(): Array<{
1155
+ domain: string;
1156
+ isGlobPattern: boolean;
1157
+ hasCertificate: boolean;
1158
+ hasForwarding: boolean;
1159
+ sslRedirect: boolean;
1160
+ acmeMaintenance: boolean;
1161
+ }> {
1162
+ return Array.from(this.domainCertificates.entries()).map(([domain, info]) => ({
1163
+ domain,
1164
+ isGlobPattern: this.isGlobPattern(domain),
1165
+ hasCertificate: info.certObtained,
1166
+ hasForwarding: !!info.options.forward,
1167
+ sslRedirect: info.options.sslRedirect,
1168
+ acmeMaintenance: info.options.acmeMaintenance
1169
+ }));
1170
+ }
1171
+
1172
+ /**
1173
+ * Gets configuration details
1174
+ * @returns Current configuration
1175
+ */
1176
+ public getConfig(): Required<IPort80HandlerOptions> {
1177
+ return { ...this.options };
1178
+ }
931
1179
  }
@@ -1,4 +1,4 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
  import type {
3
3
  IConnectionRecord,
4
4
  IDomainConfig,
@@ -1,4 +1,4 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
  import type { IConnectionRecord, IPortProxySettings } from './classes.pp.interfaces.js';
3
3
  import { SecurityManager } from './classes.pp.securitymanager.js';
4
4
  import { TimeoutManager } from './classes.pp.timeoutmanager.js';
@@ -1,4 +1,4 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
  import type { IDomainConfig, IPortProxySettings } from './classes.pp.interfaces.js';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
 
3
3
  /** Domain configuration with per-domain allowed port ranges */
4
4
  export interface IDomainConfig {
@@ -78,16 +78,42 @@ export interface IPortProxySettings {
78
78
  useNetworkProxy?: number[]; // Array of ports to forward to NetworkProxy
79
79
  networkProxyPort?: number; // Port where NetworkProxy is listening (default: 8443)
80
80
 
81
- // ACME certificate management options
82
- acme?: {
81
+ // Port80Handler configuration (replaces ACME configuration)
82
+ port80HandlerConfig?: {
83
83
  enabled?: boolean; // Whether to enable automatic certificate management
84
- port?: number; // Port to listen on for ACME challenges (default: 80)
84
+ port?: number; // Port to listen on for ACME challenges (default: 80)
85
85
  contactEmail?: string; // Email for Let's Encrypt account
86
86
  useProduction?: boolean; // Whether to use Let's Encrypt production (default: false for staging)
87
87
  renewThresholdDays?: number; // Days before expiry to renew certificates (default: 30)
88
88
  autoRenew?: boolean; // Whether to automatically renew certificates (default: true)
89
89
  certificateStore?: string; // Directory to store certificates (default: ./certs)
90
- skipConfiguredCerts?: boolean; // Skip domains that already have certificates configured
90
+ skipConfiguredCerts?: boolean; // Skip domains that already have certificates
91
+ httpsRedirectPort?: number; // Port to redirect HTTP requests to HTTPS (default: 443)
92
+ renewCheckIntervalHours?: number; // How often to check for renewals (default: 24)
93
+ // Domain-specific forwarding configurations
94
+ domainForwards?: Array<{
95
+ domain: string;
96
+ forwardConfig?: {
97
+ ip: string;
98
+ port: number;
99
+ };
100
+ acmeForwardConfig?: {
101
+ ip: string;
102
+ port: number;
103
+ };
104
+ }>;
105
+ };
106
+
107
+ // Legacy ACME configuration (deprecated, use port80HandlerConfig instead)
108
+ acme?: {
109
+ enabled?: boolean;
110
+ port?: number;
111
+ contactEmail?: string;
112
+ useProduction?: boolean;
113
+ renewThresholdDays?: number;
114
+ autoRenew?: boolean;
115
+ certificateStore?: string;
116
+ skipConfiguredCerts?: boolean;
91
117
  };
92
118
  }
93
119
 
@@ -1,5 +1,6 @@
1
- import * as plugins from './plugins.js';
2
- import { NetworkProxy } from './classes.networkproxy.js';
1
+ import * as plugins from '../plugins.js';
2
+ import { NetworkProxy } from '../networkproxy/classes.np.networkproxy.js';
3
+ import { Port80Handler, Port80HandlerEvents, type ICertificateData } from '../port80handler/classes.port80handler.js';
3
4
  import type { IConnectionRecord, IPortProxySettings, IDomainConfig } from './classes.pp.interfaces.js';
4
5
 
5
6
  /**
@@ -7,9 +8,28 @@ import type { IConnectionRecord, IPortProxySettings, IDomainConfig } from './cla
7
8
  */
8
9
  export class NetworkProxyBridge {
9
10
  private networkProxy: NetworkProxy | null = null;
11
+ private port80Handler: Port80Handler | null = null;
10
12
 
11
13
  constructor(private settings: IPortProxySettings) {}
12
14
 
15
+ /**
16
+ * Set the Port80Handler to use for certificate management
17
+ */
18
+ public setPort80Handler(handler: Port80Handler): void {
19
+ this.port80Handler = handler;
20
+
21
+ // Register for certificate events
22
+ handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, this.handleCertificateEvent.bind(this));
23
+ handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, this.handleCertificateEvent.bind(this));
24
+
25
+ // If NetworkProxy is already initialized, connect it with Port80Handler
26
+ if (this.networkProxy) {
27
+ this.networkProxy.setExternalPort80Handler(handler);
28
+ }
29
+
30
+ console.log('Port80Handler connected to NetworkProxyBridge');
31
+ }
32
+
13
33
  /**
14
34
  * Initialize NetworkProxy instance
15
35
  */
@@ -20,22 +40,61 @@ export class NetworkProxyBridge {
20
40
  port: this.settings.networkProxyPort!,
21
41
  portProxyIntegration: true,
22
42
  logLevel: this.settings.enableDetailedLogging ? 'debug' : 'info',
43
+ useExternalPort80Handler: !!this.port80Handler // Use Port80Handler if available
23
44
  };
24
45
 
25
- // Add ACME settings if configured
26
- if (this.settings.acme) {
46
+ // Copy ACME settings for backward compatibility (if port80HandlerConfig not set)
47
+ if (!this.settings.port80HandlerConfig && this.settings.acme) {
27
48
  networkProxyOptions.acme = { ...this.settings.acme };
28
49
  }
29
50
 
30
51
  this.networkProxy = new NetworkProxy(networkProxyOptions);
31
52
 
32
53
  console.log(`Initialized NetworkProxy on port ${this.settings.networkProxyPort}`);
54
+
55
+ // Connect Port80Handler if available
56
+ if (this.port80Handler) {
57
+ this.networkProxy.setExternalPort80Handler(this.port80Handler);
58
+ }
33
59
 
34
60
  // Convert and apply domain configurations to NetworkProxy
35
61
  await this.syncDomainConfigsToNetworkProxy();
36
62
  }
37
63
  }
38
64
 
65
+ /**
66
+ * Handle certificate issuance or renewal events
67
+ */
68
+ private handleCertificateEvent(data: ICertificateData): void {
69
+ if (!this.networkProxy) return;
70
+
71
+ console.log(`Received certificate for ${data.domain} from Port80Handler, updating NetworkProxy`);
72
+
73
+ try {
74
+ // Find existing config for this domain
75
+ const existingConfigs = this.networkProxy.getProxyConfigs()
76
+ .filter(config => config.hostName === data.domain);
77
+
78
+ if (existingConfigs.length > 0) {
79
+ // Update existing configs with new certificate
80
+ for (const config of existingConfigs) {
81
+ config.privateKey = data.privateKey;
82
+ config.publicKey = data.certificate;
83
+ }
84
+
85
+ // Apply updated configs
86
+ this.networkProxy.updateProxyConfigs(existingConfigs)
87
+ .then(() => console.log(`Updated certificate for ${data.domain} in NetworkProxy`))
88
+ .catch(err => console.log(`Error updating certificate in NetworkProxy: ${err}`));
89
+ } else {
90
+ // Create a new config for this domain
91
+ console.log(`No existing config found for ${data.domain}, creating new config in NetworkProxy`);
92
+ }
93
+ } catch (err) {
94
+ console.log(`Error handling certificate event: ${err}`);
95
+ }
96
+ }
97
+
39
98
  /**
40
99
  * Get the NetworkProxy instance
41
100
  */
@@ -57,22 +116,6 @@ export class NetworkProxyBridge {
57
116
  if (this.networkProxy) {
58
117
  await this.networkProxy.start();
59
118
  console.log(`NetworkProxy started on port ${this.settings.networkProxyPort}`);
60
-
61
- // Log ACME status
62
- if (this.settings.acme?.enabled) {
63
- console.log(
64
- `ACME certificate management is enabled (${
65
- this.settings.acme.useProduction ? 'Production' : 'Staging'
66
- } mode)`
67
- );
68
- console.log(`ACME HTTP challenge server on port ${this.settings.acme.port}`);
69
-
70
- // Register domains for ACME certificates if enabled
71
- if (this.networkProxy.options.acme?.enabled) {
72
- console.log('Registering domains with ACME certificate manager...');
73
- // The NetworkProxy will handle this internally via registerDomainsWithAcmeManager()
74
- }
75
- }
76
119
  }
77
120
  }
78
121
 
@@ -85,17 +128,43 @@ export class NetworkProxyBridge {
85
128
  console.log('Stopping NetworkProxy...');
86
129
  await this.networkProxy.stop();
87
130
  console.log('NetworkProxy stopped successfully');
88
-
89
- // Log ACME shutdown if it was enabled
90
- if (this.settings.acme?.enabled) {
91
- console.log('ACME certificate manager stopped');
92
- }
93
131
  } catch (err) {
94
132
  console.log(`Error stopping NetworkProxy: ${err}`);
95
133
  }
96
134
  }
97
135
  }
98
136
 
137
+ /**
138
+ * Register domains with Port80Handler
139
+ */
140
+ public registerDomainsWithPort80Handler(domains: string[]): void {
141
+ if (!this.port80Handler) {
142
+ console.log('Cannot register domains - Port80Handler not initialized');
143
+ return;
144
+ }
145
+
146
+ for (const domain of domains) {
147
+ // Skip wildcards
148
+ if (domain.includes('*')) {
149
+ console.log(`Skipping wildcard domain for ACME: ${domain}`);
150
+ continue;
151
+ }
152
+
153
+ // Register the domain
154
+ try {
155
+ this.port80Handler.addDomain({
156
+ domainName: domain,
157
+ sslRedirect: true,
158
+ acmeMaintenance: true
159
+ });
160
+
161
+ console.log(`Registered domain with Port80Handler: ${domain}`);
162
+ } catch (err) {
163
+ console.log(`Error registering domain ${domain} with Port80Handler: ${err}`);
164
+ }
165
+ }
166
+ }
167
+
99
168
  /**
100
169
  * Forwards a TLS connection to a NetworkProxy for handling
101
170
  */
@@ -207,14 +276,20 @@ export class NetworkProxyBridge {
207
276
  certPair
208
277
  );
209
278
 
210
- // Log ACME-eligible domains if ACME is enabled
211
- if (this.settings.acme?.enabled) {
279
+ // Log ACME-eligible domains
280
+ const acmeEnabled = this.settings.port80HandlerConfig?.enabled || this.settings.acme?.enabled;
281
+ if (acmeEnabled) {
212
282
  const acmeEligibleDomains = proxyConfigs
213
283
  .filter((config) => !config.hostName.includes('*')) // Exclude wildcards
214
284
  .map((config) => config.hostName);
215
285
 
216
286
  if (acmeEligibleDomains.length > 0) {
217
287
  console.log(`Domains eligible for ACME certificates: ${acmeEligibleDomains.join(', ')}`);
288
+
289
+ // Register these domains with Port80Handler if available
290
+ if (this.port80Handler) {
291
+ this.registerDomainsWithPort80Handler(acmeEligibleDomains);
292
+ }
218
293
  } else {
219
294
  console.log('No domains eligible for ACME certificates found in configuration');
220
295
  }
@@ -232,12 +307,38 @@ export class NetworkProxyBridge {
232
307
  * Request a certificate for a specific domain
233
308
  */
234
309
  public async requestCertificate(domain: string): Promise<boolean> {
310
+ // Delegate to Port80Handler if available
311
+ if (this.port80Handler) {
312
+ try {
313
+ // Check if the domain is already registered
314
+ const cert = this.port80Handler.getCertificate(domain);
315
+ if (cert) {
316
+ console.log(`Certificate already exists for ${domain}`);
317
+ return true;
318
+ }
319
+
320
+ // Register the domain for certificate issuance
321
+ this.port80Handler.addDomain({
322
+ domainName: domain,
323
+ sslRedirect: true,
324
+ acmeMaintenance: true
325
+ });
326
+
327
+ console.log(`Domain ${domain} registered for certificate issuance`);
328
+ return true;
329
+ } catch (err) {
330
+ console.log(`Error requesting certificate: ${err}`);
331
+ return false;
332
+ }
333
+ }
334
+
335
+ // Fall back to NetworkProxy if Port80Handler is not available
235
336
  if (!this.networkProxy) {
236
337
  console.log('Cannot request certificate - NetworkProxy not initialized');
237
338
  return false;
238
339
  }
239
340
 
240
- if (!this.settings.acme?.enabled) {
341
+ if (!this.settings.port80HandlerConfig?.enabled && !this.settings.acme?.enabled) {
241
342
  console.log('Cannot request certificate - ACME is not enabled');
242
343
  return false;
243
344
  }
@@ -1,4 +1,4 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
  import type { IPortProxySettings } from './classes.pp.interfaces.js';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import * as plugins from './plugins.js';
1
+ import * as plugins from '../plugins.js';
2
2
  import type { IPortProxySettings } from './classes.pp.interfaces.js';
3
3
  import { SniHandler } from './classes.pp.snihandler.js';
4
4