@push.rocks/smartproxy 15.0.2 → 16.0.2

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 (80) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/certificate/index.d.ts +10 -4
  3. package/dist_ts/certificate/index.js +5 -7
  4. package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
  5. package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
  6. package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
  7. package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
  8. package/dist_ts/forwarding/config/forwarding-types.js +19 -18
  9. package/dist_ts/forwarding/config/index.d.ts +4 -2
  10. package/dist_ts/forwarding/config/index.js +5 -3
  11. package/dist_ts/forwarding/handlers/base-handler.js +3 -1
  12. package/dist_ts/forwarding/index.d.ts +5 -6
  13. package/dist_ts/forwarding/index.js +3 -3
  14. package/dist_ts/http/models/http-types.js +1 -1
  15. package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
  16. package/dist_ts/http/port80/acme-interfaces.js +46 -1
  17. package/dist_ts/http/port80/port80-handler.d.ts +17 -2
  18. package/dist_ts/http/port80/port80-handler.js +49 -11
  19. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -61
  20. package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
  21. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +118 -4
  22. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +70 -4
  23. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +193 -43
  24. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -5
  25. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -146
  26. package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +7 -0
  27. package/dist_ts/proxies/smart-proxy/route-helpers/index.js +9 -0
  28. package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +54 -1
  29. package/dist_ts/proxies/smart-proxy/route-helpers.js +102 -1
  30. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +3 -9
  31. package/dist_ts/proxies/smart-proxy/route-manager.js +3 -115
  32. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +72 -10
  33. package/dist_ts/proxies/smart-proxy/smart-proxy.js +135 -268
  34. package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
  35. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
  36. package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
  37. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +174 -0
  38. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +332 -0
  39. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
  40. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
  41. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
  42. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
  43. package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
  44. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
  45. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
  46. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +242 -0
  47. package/package.json +1 -1
  48. package/readme.md +139 -111
  49. package/readme.plan.md +164 -312
  50. package/ts/00_commitinfo_data.ts +1 -1
  51. package/ts/certificate/index.ts +17 -9
  52. package/ts/certificate/models/certificate-types.ts +37 -16
  53. package/ts/certificate/providers/cert-provisioner.ts +247 -54
  54. package/ts/forwarding/config/forwarding-types.ts +79 -107
  55. package/ts/forwarding/config/index.ts +4 -2
  56. package/ts/forwarding/handlers/base-handler.ts +4 -2
  57. package/ts/forwarding/index.ts +3 -2
  58. package/ts/http/models/http-types.ts +0 -1
  59. package/ts/http/port80/acme-interfaces.ts +84 -0
  60. package/ts/http/port80/port80-handler.ts +61 -15
  61. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -64
  62. package/ts/proxies/smart-proxy/models/route-types.ts +152 -22
  63. package/ts/proxies/smart-proxy/network-proxy-bridge.ts +226 -55
  64. package/ts/proxies/smart-proxy/route-connection-handler.ts +36 -205
  65. package/ts/proxies/smart-proxy/route-helpers/index.ts +9 -0
  66. package/ts/proxies/smart-proxy/route-helpers.ts +165 -11
  67. package/ts/proxies/smart-proxy/route-manager.ts +3 -130
  68. package/ts/proxies/smart-proxy/smart-proxy.ts +157 -329
  69. package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
  70. package/ts/proxies/smart-proxy/utils/index.ts +40 -0
  71. package/ts/proxies/smart-proxy/utils/route-helpers.ts +455 -0
  72. package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
  73. package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
  74. package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
  75. package/ts/proxies/smart-proxy/utils/route-validators.ts +269 -0
  76. package/ts/forwarding/config/domain-config.ts +0 -28
  77. package/ts/forwarding/config/domain-manager.ts +0 -283
  78. package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
  79. package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
  80. /package/ts/proxies/smart-proxy/{domain-config-manager.ts → domain-config-manager.ts.bak} +0 -0
@@ -3,11 +3,10 @@ import * as plugins from '../../plugins.js';
3
3
  // Importing required components
4
4
  import { ConnectionManager } from './connection-manager.js';
5
5
  import { SecurityManager } from './security-manager.js';
6
- import { DomainConfigManager } from './domain-config-manager.js';
7
6
  import { TlsManager } from './tls-manager.js';
8
7
  import { NetworkProxyBridge } from './network-proxy-bridge.js';
9
8
  import { TimeoutManager } from './timeout-manager.js';
10
- import { PortRangeManager } from './port-range-manager.js';
9
+ // import { PortRangeManager } from './port-range-manager.js';
11
10
  import { RouteManager } from './route-manager.js';
12
11
  import { RouteConnectionHandler } from './route-connection-handler.js';
13
12
 
@@ -19,16 +18,25 @@ import { buildPort80Handler } from '../../certificate/acme/acme-factory.js';
19
18
  import { createPort80HandlerOptions } from '../../common/port80-adapter.js';
20
19
 
21
20
  // Import types and utilities
22
- import type {
23
- ISmartProxyOptions,
24
- IRoutedSmartProxyOptions,
25
- IDomainConfig
21
+ import type {
22
+ ISmartProxyOptions,
23
+ IRoutedSmartProxyOptions
26
24
  } from './models/interfaces.js';
27
25
  import { isRoutedOptions, isLegacyOptions } from './models/interfaces.js';
28
26
  import type { IRouteConfig } from './models/route-types.js';
29
27
 
30
28
  /**
31
- * SmartProxy - Unified route-based API
29
+ * SmartProxy - Pure route-based API
30
+ *
31
+ * SmartProxy is a unified proxy system that works with routes to define connection handling behavior.
32
+ * Each route contains matching criteria (ports, domains, etc.) and an action to take (forward, redirect, block).
33
+ *
34
+ * Configuration is provided through a set of routes, with each route defining:
35
+ * - What to match (ports, domains, paths, client IPs)
36
+ * - What to do with matching traffic (forward, redirect, block)
37
+ * - How to handle TLS (passthrough, terminate, terminate-and-reencrypt)
38
+ * - Security settings (IP restrictions, connection limits)
39
+ * - Advanced options (timeout, headers, etc.)
32
40
  */
33
41
  export class SmartProxy extends plugins.EventEmitter {
34
42
  private netServers: plugins.net.Server[] = [];
@@ -38,11 +46,10 @@ export class SmartProxy extends plugins.EventEmitter {
38
46
  // Component managers
39
47
  private connectionManager: ConnectionManager;
40
48
  private securityManager: SecurityManager;
41
- private domainConfigManager: DomainConfigManager;
42
49
  private tlsManager: TlsManager;
43
50
  private networkProxyBridge: NetworkProxyBridge;
44
51
  private timeoutManager: TimeoutManager;
45
- private portRangeManager: PortRangeManager;
52
+ // private portRangeManager: PortRangeManager;
46
53
  private routeManager: RouteManager;
47
54
  private routeConnectionHandler: RouteConnectionHandler;
48
55
 
@@ -52,7 +59,35 @@ export class SmartProxy extends plugins.EventEmitter {
52
59
  private certProvisioner?: CertProvisioner;
53
60
 
54
61
  /**
55
- * Constructor that supports both legacy and route-based configuration
62
+ * Constructor for SmartProxy
63
+ *
64
+ * @param settingsArg Configuration options containing routes and other settings
65
+ * Routes define how traffic is matched and handled, with each route having:
66
+ * - match: criteria for matching traffic (ports, domains, paths, IPs)
67
+ * - action: what to do with matched traffic (forward, redirect, block)
68
+ *
69
+ * Example:
70
+ * ```ts
71
+ * const proxy = new SmartProxy({
72
+ * routes: [
73
+ * {
74
+ * match: {
75
+ * ports: 443,
76
+ * domains: ['example.com', '*.example.com']
77
+ * },
78
+ * action: {
79
+ * type: 'forward',
80
+ * target: { host: '10.0.0.1', port: 8443 },
81
+ * tls: { mode: 'passthrough' }
82
+ * }
83
+ * }
84
+ * ],
85
+ * defaults: {
86
+ * target: { host: 'localhost', port: 8080 },
87
+ * security: { allowedIps: ['*'] }
88
+ * }
89
+ * });
90
+ * ```
56
91
  */
57
92
  constructor(settingsArg: ISmartProxyOptions) {
58
93
  super();
@@ -98,9 +133,9 @@ export class SmartProxy extends plugins.EventEmitter {
98
133
  autoRenew: true,
99
134
  certificateStore: './certs',
100
135
  skipConfiguredCerts: false,
101
- httpsRedirectPort: this.settings.fromPort || 443,
136
+ httpsRedirectPort: 443,
102
137
  renewCheckIntervalHours: 24,
103
- domainForwards: []
138
+ routeForwards: []
104
139
  };
105
140
  }
106
141
 
@@ -113,18 +148,11 @@ export class SmartProxy extends plugins.EventEmitter {
113
148
  this.timeoutManager
114
149
  );
115
150
 
116
- // Create the new route manager first
151
+ // Create the route manager
117
152
  this.routeManager = new RouteManager(this.settings);
118
153
 
119
- // Create domain config manager and port range manager
120
- this.domainConfigManager = new DomainConfigManager(this.settings);
121
-
122
- // Share the route manager with the domain config manager
123
- if (typeof this.domainConfigManager.setRouteManager === 'function') {
124
- this.domainConfigManager.setRouteManager(this.routeManager);
125
- }
126
-
127
- this.portRangeManager = new PortRangeManager(this.settings);
154
+ // Create port range manager
155
+ // this.portRangeManager = new PortRangeManager(this.settings);
128
156
 
129
157
  // Create other required components
130
158
  this.tlsManager = new TlsManager(this.settings);
@@ -135,7 +163,6 @@ export class SmartProxy extends plugins.EventEmitter {
135
163
  this.settings,
136
164
  this.connectionManager,
137
165
  this.securityManager,
138
- this.domainConfigManager,
139
166
  this.tlsManager,
140
167
  this.networkProxyBridge,
141
168
  this.timeoutManager,
@@ -162,7 +189,7 @@ export class SmartProxy extends plugins.EventEmitter {
162
189
  // Build and start the Port80Handler
163
190
  this.port80Handler = buildPort80Handler({
164
191
  ...config,
165
- httpsRedirectPort: config.httpsRedirectPort || (isLegacyOptions(this.settings) ? this.settings.fromPort : 443)
192
+ httpsRedirectPort: config.httpsRedirectPort || 443
166
193
  });
167
194
 
168
195
  // Share Port80Handler with NetworkProxyBridge before start
@@ -184,17 +211,7 @@ export class SmartProxy extends plugins.EventEmitter {
184
211
  return;
185
212
  }
186
213
 
187
- // Initialize domain config based on configuration type
188
- if (isLegacyOptions(this.settings)) {
189
- // Initialize domain config manager with the legacy domain configs
190
- this.domainConfigManager.updateDomainConfigs(this.settings.domainConfigs || []);
191
- } else if (isRoutedOptions(this.settings)) {
192
- // For pure route-based configuration, the domain config is already initialized
193
- // in the constructor, but we might need to regenerate it
194
- if (typeof this.domainConfigManager.generateDomainConfigsFromRoutes === 'function') {
195
- this.domainConfigManager.generateDomainConfigsFromRoutes();
196
- }
197
- }
214
+ // Pure route-based configuration - no domain configs needed
198
215
 
199
216
  // Initialize Port80Handler if enabled
200
217
  await this.initializePort80Handler();
@@ -203,80 +220,22 @@ export class SmartProxy extends plugins.EventEmitter {
203
220
  if (this.port80Handler) {
204
221
  const acme = this.settings.acme!;
205
222
 
206
- // Setup domain forwards based on configuration type
207
- const domainForwards = acme.domainForwards?.map(f => {
208
- if (isLegacyOptions(this.settings)) {
209
- // If using legacy mode, check if domain config exists
210
- const domainConfig = this.settings.domainConfigs.find(
211
- dc => dc.domains.some(d => d === f.domain)
212
- );
213
-
214
- if (domainConfig?.forwarding) {
215
- return {
216
- domain: f.domain,
217
- forwardConfig: f.forwardConfig,
218
- acmeForwardConfig: f.acmeForwardConfig,
219
- sslRedirect: f.sslRedirect || domainConfig.forwarding.http?.redirectToHttps || false
220
- };
221
- }
222
- } else {
223
- // In route mode, look for matching route
224
- const route = this.routeManager.findMatchingRoute({
225
- port: 443,
226
- domain: f.domain,
227
- clientIp: '127.0.0.1' // Dummy IP for finding routes
228
- })?.route;
229
-
230
- if (route && route.action.type === 'forward' && route.action.tls) {
231
- // If we found a matching route with TLS settings
232
- return {
233
- domain: f.domain,
234
- forwardConfig: f.forwardConfig,
235
- acmeForwardConfig: f.acmeForwardConfig,
236
- sslRedirect: f.sslRedirect || false
237
- };
238
- }
239
- }
240
-
241
- // Otherwise use the existing configuration
242
- return {
243
- domain: f.domain,
244
- forwardConfig: f.forwardConfig,
245
- acmeForwardConfig: f.acmeForwardConfig,
246
- sslRedirect: f.sslRedirect || false
247
- };
248
- }) || [];
223
+ // Setup route forwards
224
+ const routeForwards = acme.routeForwards?.map(f => f) || [];
249
225
 
250
226
  // Create CertProvisioner with appropriate parameters
251
- if (isLegacyOptions(this.settings)) {
252
- this.certProvisioner = new CertProvisioner(
253
- this.settings.domainConfigs,
254
- this.port80Handler,
255
- this.networkProxyBridge,
256
- this.settings.certProvisionFunction,
257
- acme.renewThresholdDays!,
258
- acme.renewCheckIntervalHours!,
259
- acme.autoRenew!,
260
- domainForwards
261
- );
262
- } else {
263
- // For route-based configuration, we need to adapt the interface
264
- // Convert routes to domain configs for CertProvisioner
265
- const domainConfigs: IDomainConfig[] = this.extractDomainConfigsFromRoutes(
266
- (this.settings as IRoutedSmartProxyOptions).routes
267
- );
268
-
269
- this.certProvisioner = new CertProvisioner(
270
- domainConfigs,
271
- this.port80Handler,
272
- this.networkProxyBridge,
273
- this.settings.certProvisionFunction,
274
- acme.renewThresholdDays!,
275
- acme.renewCheckIntervalHours!,
276
- acme.autoRenew!,
277
- domainForwards
278
- );
279
- }
227
+ // No longer need to support multiple configuration types
228
+ // Just pass the routes directly
229
+ this.certProvisioner = new CertProvisioner(
230
+ this.settings.routes,
231
+ this.port80Handler,
232
+ this.networkProxyBridge,
233
+ this.settings.certProvisionFunction,
234
+ acme.renewThresholdDays!,
235
+ acme.renewCheckIntervalHours!,
236
+ acme.autoRenew!,
237
+ routeForwards
238
+ );
280
239
 
281
240
  // Register certificate event handler
282
241
  this.certProvisioner.on('certificate', (certData) => {
@@ -332,10 +291,8 @@ export class SmartProxy extends plugins.EventEmitter {
332
291
  const isNetworkProxyPort = this.settings.useNetworkProxy?.includes(port);
333
292
  console.log(
334
293
  `SmartProxy -> OK: Now listening on port ${port}${
335
- isLegacyOptions(this.settings) && this.settings.sniEnabled && !isNetworkProxyPort ?
336
- ' (SNI passthrough enabled)' :
337
- ''
338
- }${isNetworkProxyPort ? ' (NetworkProxy forwarding enabled)' : ''}`
294
+ isNetworkProxyPort ? ' (NetworkProxy forwarding enabled)' : ''
295
+ }`
339
296
  );
340
297
  });
341
298
 
@@ -416,60 +373,9 @@ export class SmartProxy extends plugins.EventEmitter {
416
373
 
417
374
  /**
418
375
  * Extract domain configurations from routes for certificate provisioning
376
+ *
377
+ * Note: This method has been removed as we now work directly with routes
419
378
  */
420
- private extractDomainConfigsFromRoutes(routes: IRouteConfig[]): IDomainConfig[] {
421
- const domainConfigs: IDomainConfig[] = [];
422
-
423
- for (const route of routes) {
424
- // Skip routes without domain specs
425
- if (!route.match.domains) continue;
426
-
427
- // Skip non-forward routes
428
- if (route.action.type !== 'forward') continue;
429
-
430
- // Only process routes that need TLS termination (those with certificates)
431
- if (!route.action.tls ||
432
- route.action.tls.mode === 'passthrough' ||
433
- !route.action.target) continue;
434
-
435
- const domains = Array.isArray(route.match.domains)
436
- ? route.match.domains
437
- : [route.match.domains];
438
-
439
- // Determine forwarding type based on TLS mode
440
- const forwardingType = route.action.tls.mode === 'terminate'
441
- ? 'https-terminate-to-http'
442
- : 'https-terminate-to-https';
443
-
444
- // Create a forwarding config
445
- const forwarding = {
446
- type: forwardingType as any,
447
- target: {
448
- host: Array.isArray(route.action.target.host)
449
- ? route.action.target.host[0]
450
- : route.action.target.host,
451
- port: route.action.target.port
452
- },
453
- // Add TLS settings
454
- https: {
455
- customCert: route.action.tls.certificate !== 'auto'
456
- ? route.action.tls.certificate
457
- : undefined
458
- },
459
- // Add security settings if present
460
- security: route.action.security,
461
- // Add advanced settings if present
462
- advanced: route.action.advanced
463
- };
464
-
465
- domainConfigs.push({
466
- domains,
467
- forwarding
468
- });
469
- }
470
-
471
- return domainConfigs;
472
- }
473
379
 
474
380
  /**
475
381
  * Stop the proxy server
@@ -535,188 +441,119 @@ export class SmartProxy extends plugins.EventEmitter {
535
441
  }
536
442
 
537
443
  /**
538
- * Updates the domain configurations for the proxy (legacy support)
444
+ * Updates the domain configurations for the proxy
445
+ *
446
+ * Note: This legacy method has been removed. Use updateRoutes instead.
539
447
  */
540
- public async updateDomainConfigs(newDomainConfigs: IDomainConfig[]): Promise<void> {
541
- console.log(`Updating domain configurations (${newDomainConfigs.length} configs)`);
542
-
543
- // Update domain configs in DomainConfigManager (legacy)
544
- this.domainConfigManager.updateDomainConfigs(newDomainConfigs);
545
-
546
- // Also update the RouteManager with these domain configs
547
- this.routeManager.updateFromDomainConfigs(newDomainConfigs);
548
-
549
- // If NetworkProxy is initialized, resync the configurations
550
- if (this.networkProxyBridge.getNetworkProxy()) {
551
- await this.networkProxyBridge.syncDomainConfigsToNetworkProxy();
552
- }
553
-
554
- // If Port80Handler is running, provision certificates based on forwarding type
555
- if (this.port80Handler && this.settings.acme?.enabled) {
556
- for (const domainConfig of newDomainConfigs) {
557
- // Skip certificate provisioning for http-only or passthrough configs that don't need certs
558
- const forwardingType = this.domainConfigManager.getForwardingType(domainConfig);
559
- const needsCertificate =
560
- forwardingType === 'https-terminate-to-http' ||
561
- forwardingType === 'https-terminate-to-https';
562
-
563
- // Skip certificate provisioning if ACME is explicitly disabled for this domain
564
- const acmeDisabled = domainConfig.forwarding.acme?.enabled === false;
565
-
566
- if (!needsCertificate || acmeDisabled) {
567
- if (this.settings.enableDetailedLogging) {
568
- console.log(`Skipping certificate provisioning for ${domainConfig.domains.join(', ')} (${forwardingType})`);
569
- }
570
- continue;
571
- }
572
-
573
- for (const domain of domainConfig.domains) {
574
- const isWildcard = domain.includes('*');
575
- let provision: string | plugins.tsclass.network.ICert = 'http01';
576
-
577
- // Check for ACME forwarding configuration in the domain
578
- const forwardAcmeChallenges = domainConfig.forwarding.acme?.forwardChallenges;
579
-
580
- if (this.settings.certProvisionFunction) {
581
- try {
582
- provision = await this.settings.certProvisionFunction(domain);
583
- } catch (err) {
584
- console.log(`certProvider error for ${domain}: ${err}`);
585
- }
586
- } else if (isWildcard) {
587
- console.warn(`Skipping wildcard domain without certProvisionFunction: ${domain}`);
588
- continue;
589
- }
590
-
591
- if (provision === 'http01') {
592
- if (isWildcard) {
593
- console.warn(`Skipping HTTP-01 for wildcard domain: ${domain}`);
594
- continue;
595
- }
596
-
597
- // Create Port80Handler options from the forwarding configuration
598
- const port80Config = createPort80HandlerOptions(domain, domainConfig.forwarding);
599
-
600
- this.port80Handler.addDomain(port80Config);
601
- console.log(`Registered domain ${domain} with Port80Handler for HTTP-01`);
602
- } else {
603
- // Static certificate (e.g., DNS-01 provisioned) supports wildcards
604
- const certObj = provision as plugins.tsclass.network.ICert;
605
- const certData: ICertificateData = {
606
- domain: certObj.domainName,
607
- certificate: certObj.publicKey,
608
- privateKey: certObj.privateKey,
609
- expiryDate: new Date(certObj.validUntil)
610
- };
611
- this.networkProxyBridge.applyExternalCertificate(certData);
612
- console.log(`Applied static certificate for ${domain} from certProvider`);
613
- }
614
- }
615
- }
616
- console.log('Provisioned certificates for new domains');
617
- }
448
+ public async updateDomainConfigs(): Promise<void> {
449
+ console.warn('Method updateDomainConfigs() is deprecated. Use updateRoutes() instead.');
450
+ throw new Error('updateDomainConfigs() is deprecated - use updateRoutes() instead');
618
451
  }
619
452
 
620
453
  /**
621
- * Update routes with new configuration (new API)
454
+ * Update routes with new configuration
455
+ *
456
+ * This method replaces the current route configuration with the provided routes.
457
+ * It also provisions certificates for routes that require TLS termination and have
458
+ * `certificate: 'auto'` set in their TLS configuration.
459
+ *
460
+ * @param newRoutes Array of route configurations to use
461
+ *
462
+ * Example:
463
+ * ```ts
464
+ * proxy.updateRoutes([
465
+ * {
466
+ * match: { ports: 443, domains: 'secure.example.com' },
467
+ * action: {
468
+ * type: 'forward',
469
+ * target: { host: '10.0.0.1', port: 8443 },
470
+ * tls: { mode: 'terminate', certificate: 'auto' }
471
+ * }
472
+ * }
473
+ * ]);
474
+ * ```
622
475
  */
623
476
  public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
624
477
  console.log(`Updating routes (${newRoutes.length} routes)`);
625
-
478
+
626
479
  // Update routes in RouteManager
627
480
  this.routeManager.updateRoutes(newRoutes);
628
-
481
+
629
482
  // If NetworkProxy is initialized, resync the configurations
630
483
  if (this.networkProxyBridge.getNetworkProxy()) {
631
- // Create equivalent domain configs for NetworkProxy
632
- const domainConfigs = this.extractDomainConfigsFromRoutes(newRoutes);
633
-
634
- // Update domain configs in DomainConfigManager for sync
635
- this.domainConfigManager.updateDomainConfigs(domainConfigs);
636
-
637
- // Sync with NetworkProxy
638
- await this.networkProxyBridge.syncDomainConfigsToNetworkProxy();
484
+ await this.networkProxyBridge.syncRoutesToNetworkProxy(newRoutes);
639
485
  }
640
-
486
+
641
487
  // If Port80Handler is running, provision certificates based on routes
642
488
  if (this.port80Handler && this.settings.acme?.enabled) {
643
- for (const route of newRoutes) {
644
- // Skip routes without domains
645
- if (!route.match.domains) continue;
646
-
647
- // Skip non-forward routes
648
- if (route.action.type !== 'forward') continue;
649
-
650
- // Skip routes without TLS termination
651
- if (!route.action.tls ||
652
- route.action.tls.mode === 'passthrough' ||
653
- !route.action.target) continue;
654
-
655
- // Skip certificate provisioning if certificate is not auto
656
- if (route.action.tls.certificate !== 'auto') continue;
657
-
658
- const domains = Array.isArray(route.match.domains)
659
- ? route.match.domains
660
- : [route.match.domains];
661
-
662
- for (const domain of domains) {
663
- const isWildcard = domain.includes('*');
664
- let provision: string | plugins.tsclass.network.ICert = 'http01';
665
-
666
- if (this.settings.certProvisionFunction) {
489
+ // Register all eligible domains from routes
490
+ this.port80Handler.addDomainsFromRoutes(newRoutes);
491
+
492
+ // Handle static certificates from certProvisionFunction if available
493
+ if (this.settings.certProvisionFunction) {
494
+ for (const route of newRoutes) {
495
+ // Skip routes without domains
496
+ if (!route.match.domains) continue;
497
+
498
+ // Skip non-forward routes
499
+ if (route.action.type !== 'forward') continue;
500
+
501
+ // Skip routes without TLS termination
502
+ if (!route.action.tls ||
503
+ route.action.tls.mode === 'passthrough' ||
504
+ !route.action.target) continue;
505
+
506
+ // Skip certificate provisioning if certificate is not auto
507
+ if (route.action.tls.certificate !== 'auto') continue;
508
+
509
+ const domains = Array.isArray(route.match.domains)
510
+ ? route.match.domains
511
+ : [route.match.domains];
512
+
513
+ for (const domain of domains) {
667
514
  try {
668
- provision = await this.settings.certProvisionFunction(domain);
515
+ const provision = await this.settings.certProvisionFunction(domain);
516
+
517
+ // Skip http01 as those are handled by Port80Handler
518
+ if (provision !== 'http01') {
519
+ // Handle static certificate (e.g., DNS-01 provisioned)
520
+ const certObj = provision as plugins.tsclass.network.ICert;
521
+ const certData: ICertificateData = {
522
+ domain: certObj.domainName,
523
+ certificate: certObj.publicKey,
524
+ privateKey: certObj.privateKey,
525
+ expiryDate: new Date(certObj.validUntil),
526
+ routeReference: {
527
+ routeName: route.name
528
+ }
529
+ };
530
+ this.networkProxyBridge.applyExternalCertificate(certData);
531
+ console.log(`Applied static certificate for ${domain} from certProvider`);
532
+ }
669
533
  } catch (err) {
670
534
  console.log(`certProvider error for ${domain}: ${err}`);
671
535
  }
672
- } else if (isWildcard) {
673
- console.warn(`Skipping wildcard domain without certProvisionFunction: ${domain}`);
674
- continue;
675
- }
676
-
677
- if (provision === 'http01') {
678
- if (isWildcard) {
679
- console.warn(`Skipping HTTP-01 for wildcard domain: ${domain}`);
680
- continue;
681
- }
682
-
683
- // Register domain with Port80Handler
684
- this.port80Handler.addDomain({
685
- domainName: domain,
686
- sslRedirect: true,
687
- acmeMaintenance: true
688
- });
689
-
690
- console.log(`Registered domain ${domain} with Port80Handler for HTTP-01`);
691
- } else {
692
- // Handle static certificate (e.g., DNS-01 provisioned)
693
- const certObj = provision as plugins.tsclass.network.ICert;
694
- const certData: ICertificateData = {
695
- domain: certObj.domainName,
696
- certificate: certObj.publicKey,
697
- privateKey: certObj.privateKey,
698
- expiryDate: new Date(certObj.validUntil)
699
- };
700
- this.networkProxyBridge.applyExternalCertificate(certData);
701
- console.log(`Applied static certificate for ${domain} from certProvider`);
702
536
  }
703
537
  }
704
538
  }
705
-
539
+
706
540
  console.log('Provisioned certificates for new routes');
707
541
  }
708
542
  }
709
543
 
710
544
  /**
711
545
  * Request a certificate for a specific domain
546
+ *
547
+ * @param domain The domain to request a certificate for
548
+ * @param routeName Optional route name to associate with the certificate
712
549
  */
713
- public async requestCertificate(domain: string): Promise<boolean> {
550
+ public async requestCertificate(domain: string, routeName?: string): Promise<boolean> {
714
551
  // Validate domain format
715
552
  if (!this.isValidDomain(domain)) {
716
553
  console.log(`Invalid domain format: ${domain}`);
717
554
  return false;
718
555
  }
719
-
556
+
720
557
  // Use Port80Handler if available
721
558
  if (this.port80Handler) {
722
559
  try {
@@ -726,15 +563,16 @@ export class SmartProxy extends plugins.EventEmitter {
726
563
  console.log(`Certificate already exists for ${domain}, valid until ${cert.expiryDate.toISOString()}`);
727
564
  return true;
728
565
  }
729
-
566
+
730
567
  // Register domain for certificate issuance
731
568
  this.port80Handler.addDomain({
732
- domainName: domain,
569
+ domain,
733
570
  sslRedirect: true,
734
- acmeMaintenance: true
571
+ acmeMaintenance: true,
572
+ routeReference: routeName ? { routeName } : undefined
735
573
  });
736
-
737
- console.log(`Domain ${domain} registered for certificate issuance`);
574
+
575
+ console.log(`Domain ${domain} registered for certificate issuance` + (routeName ? ` for route '${routeName}'` : ''));
738
576
  return true;
739
577
  } catch (err) {
740
578
  console.log(`Error registering domain with Port80Handler: ${err}`);
@@ -834,17 +672,7 @@ export class SmartProxy extends plugins.EventEmitter {
834
672
  domains.push(...eligibleDomains);
835
673
  }
836
674
 
837
- // For legacy mode, also get domains from domain configs
838
- if (isLegacyOptions(this.settings)) {
839
- for (const config of this.settings.domainConfigs) {
840
- // Skip domains that can't be used with ACME
841
- const eligibleDomains = config.domains.filter(domain =>
842
- !domain.includes('*') && this.isValidDomain(domain)
843
- );
844
-
845
- domains.push(...eligibleDomains);
846
- }
847
- }
675
+ // Legacy mode is no longer supported
848
676
 
849
677
  return domains;
850
678
  }
@@ -61,8 +61,8 @@ export class TimeoutManager {
61
61
  * Calculate effective max lifetime based on connection type
62
62
  */
63
63
  public getEffectiveMaxLifetime(record: IConnectionRecord): number {
64
- // Use domain-specific timeout from forwarding.advanced if available
65
- const baseTimeout = record.domainConfig?.forwarding?.advanced?.timeout ||
64
+ // Use route-specific timeout if available from the routeConfig
65
+ const baseTimeout = record.routeConfig?.action.advanced?.timeout ||
66
66
  this.settings.maxConnectionLifetime ||
67
67
  86400000; // 24 hours default
68
68