@push.rocks/smartproxy 19.6.6 → 19.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist_ts/core/models/wrapped-socket.d.ts +4 -0
  2. package/dist_ts/core/models/wrapped-socket.js +18 -1
  3. package/dist_ts/core/routing/matchers/path.js +3 -2
  4. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +4 -7
  5. package/dist_ts/proxies/smart-proxy/connection-manager.js +22 -22
  6. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +4 -3
  7. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +9 -9
  8. package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +68 -56
  9. package/dist_ts/proxies/smart-proxy/metrics-collector.js +252 -176
  10. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +6 -1
  11. package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +99 -47
  12. package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +4 -4
  13. package/dist_ts/proxies/smart-proxy/nftables-manager.js +6 -6
  14. package/dist_ts/proxies/smart-proxy/port-manager.d.ts +4 -7
  15. package/dist_ts/proxies/smart-proxy/port-manager.js +6 -9
  16. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -15
  17. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +133 -130
  18. package/dist_ts/proxies/smart-proxy/security-manager.d.ts +3 -3
  19. package/dist_ts/proxies/smart-proxy/security-manager.js +9 -9
  20. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +20 -13
  21. package/dist_ts/proxies/smart-proxy/smart-proxy.js +16 -13
  22. package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +36 -0
  23. package/dist_ts/proxies/smart-proxy/throughput-tracker.js +117 -0
  24. package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +5 -4
  25. package/dist_ts/proxies/smart-proxy/timeout-manager.js +20 -16
  26. package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +3 -3
  27. package/dist_ts/proxies/smart-proxy/tls-manager.js +12 -12
  28. package/dist_ts/routing/router/http-router.js +2 -2
  29. package/package.json +1 -1
  30. package/readme.hints.md +0 -0
  31. package/readme.md +239 -73
  32. package/readme.plan.md +364 -0
  33. package/ts/core/models/wrapped-socket.ts +18 -0
  34. package/ts/core/routing/matchers/path.ts +2 -1
  35. package/ts/proxies/smart-proxy/connection-manager.ts +23 -21
  36. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +9 -8
  37. package/ts/proxies/smart-proxy/metrics-collector.ts +305 -188
  38. package/ts/proxies/smart-proxy/models/interfaces.ts +8 -1
  39. package/ts/proxies/smart-proxy/models/metrics-types.ts +99 -41
  40. package/ts/proxies/smart-proxy/nftables-manager.ts +5 -5
  41. package/ts/proxies/smart-proxy/port-manager.ts +6 -14
  42. package/ts/proxies/smart-proxy/route-connection-handler.ts +141 -138
  43. package/ts/proxies/smart-proxy/security-manager.ts +8 -8
  44. package/ts/proxies/smart-proxy/smart-proxy.ts +26 -35
  45. package/ts/proxies/smart-proxy/throughput-tracker.ts +144 -0
  46. package/ts/proxies/smart-proxy/timeout-manager.ts +22 -16
  47. package/ts/proxies/smart-proxy/tls-manager.ts +11 -11
  48. package/ts/routing/router/http-router.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  import * as plugins from '../../plugins.js';
2
- import type { ISmartProxyOptions } from './models/interfaces.js';
2
+ import type { SmartProxy } from './smart-proxy.js';
3
3
 
4
4
  /**
5
5
  * Handles security aspects like IP tracking, rate limiting, and authorization
@@ -8,7 +8,7 @@ export class SecurityManager {
8
8
  private connectionsByIP: Map<string, Set<string>> = new Map();
9
9
  private connectionRateByIP: Map<string, number[]> = new Map();
10
10
 
11
- constructor(private settings: ISmartProxyOptions) {}
11
+ constructor(private smartProxy: SmartProxy) {}
12
12
 
13
13
  /**
14
14
  * Get connections count by IP
@@ -36,7 +36,7 @@ export class SecurityManager {
36
36
  this.connectionRateByIP.set(ip, timestamps);
37
37
 
38
38
  // Check if rate exceeds limit
39
- return timestamps.length <= this.settings.connectionRateLimitPerMinute!;
39
+ return timestamps.length <= this.smartProxy.settings.connectionRateLimitPerMinute!;
40
40
  }
41
41
 
42
42
  /**
@@ -137,23 +137,23 @@ export class SecurityManager {
137
137
  public validateIP(ip: string): { allowed: boolean; reason?: string } {
138
138
  // Check connection count limit
139
139
  if (
140
- this.settings.maxConnectionsPerIP &&
141
- this.getConnectionCountByIP(ip) >= this.settings.maxConnectionsPerIP
140
+ this.smartProxy.settings.maxConnectionsPerIP &&
141
+ this.getConnectionCountByIP(ip) >= this.smartProxy.settings.maxConnectionsPerIP
142
142
  ) {
143
143
  return {
144
144
  allowed: false,
145
- reason: `Maximum connections per IP (${this.settings.maxConnectionsPerIP}) exceeded`
145
+ reason: `Maximum connections per IP (${this.smartProxy.settings.maxConnectionsPerIP}) exceeded`
146
146
  };
147
147
  }
148
148
 
149
149
  // Check connection rate limit
150
150
  if (
151
- this.settings.connectionRateLimitPerMinute &&
151
+ this.smartProxy.settings.connectionRateLimitPerMinute &&
152
152
  !this.checkConnectionRate(ip)
153
153
  ) {
154
154
  return {
155
155
  allowed: false,
156
- reason: `Connection rate limit (${this.settings.connectionRateLimitPerMinute}/min) exceeded`
156
+ reason: `Connection rate limit (${this.smartProxy.settings.connectionRateLimitPerMinute}/min) exceeded`
157
157
  };
158
158
  }
159
159
 
@@ -29,7 +29,7 @@ import { AcmeStateManager } from './acme-state-manager.js';
29
29
 
30
30
  // Import metrics collector
31
31
  import { MetricsCollector } from './metrics-collector.js';
32
- import type { IProxyStats } from './models/metrics-types.js';
32
+ import type { IMetrics } from './models/metrics-types.js';
33
33
 
34
34
  /**
35
35
  * SmartProxy - Pure route-based API
@@ -52,24 +52,24 @@ export class SmartProxy extends plugins.EventEmitter {
52
52
 
53
53
  // Component managers
54
54
  public connectionManager: ConnectionManager;
55
- private securityManager: SecurityManager;
56
- private tlsManager: TlsManager;
57
- private httpProxyBridge: HttpProxyBridge;
58
- private timeoutManager: TimeoutManager;
59
- public routeManager: RouteManager; // Made public for route management
60
- public routeConnectionHandler: RouteConnectionHandler; // Made public for metrics
61
- private nftablesManager: NFTablesManager;
55
+ public securityManager: SecurityManager;
56
+ public tlsManager: TlsManager;
57
+ public httpProxyBridge: HttpProxyBridge;
58
+ public timeoutManager: TimeoutManager;
59
+ public routeManager: RouteManager;
60
+ public routeConnectionHandler: RouteConnectionHandler;
61
+ public nftablesManager: NFTablesManager;
62
62
 
63
63
  // Certificate manager for ACME and static certificates
64
- private certManager: SmartCertManager | null = null;
64
+ public certManager: SmartCertManager | null = null;
65
65
 
66
66
  // Global challenge route tracking
67
67
  private globalChallengeRouteActive: boolean = false;
68
68
  private routeUpdateLock: any = null; // Will be initialized as AsyncMutex
69
- private acmeStateManager: AcmeStateManager;
69
+ public acmeStateManager: AcmeStateManager;
70
70
 
71
71
  // Metrics collector
72
- private metricsCollector: MetricsCollector;
72
+ public metricsCollector: MetricsCollector;
73
73
 
74
74
  // Track port usage across route updates
75
75
  private portUsageMap: Map<number, Set<string>> = new Map();
@@ -161,13 +161,9 @@ export class SmartProxy extends plugins.EventEmitter {
161
161
  }
162
162
 
163
163
  // Initialize component managers
164
- this.timeoutManager = new TimeoutManager(this.settings);
165
- this.securityManager = new SecurityManager(this.settings);
166
- this.connectionManager = new ConnectionManager(
167
- this.settings,
168
- this.securityManager,
169
- this.timeoutManager
170
- );
164
+ this.timeoutManager = new TimeoutManager(this);
165
+ this.securityManager = new SecurityManager(this);
166
+ this.connectionManager = new ConnectionManager(this);
171
167
 
172
168
  // Create the route manager with SharedRouteManager API
173
169
  // Create a logger adapter to match ILogger interface
@@ -186,25 +182,17 @@ export class SmartProxy extends plugins.EventEmitter {
186
182
 
187
183
 
188
184
  // Create other required components
189
- this.tlsManager = new TlsManager(this.settings);
190
- this.httpProxyBridge = new HttpProxyBridge(this.settings);
185
+ this.tlsManager = new TlsManager(this);
186
+ this.httpProxyBridge = new HttpProxyBridge(this);
191
187
 
192
188
  // Initialize connection handler with route support
193
- this.routeConnectionHandler = new RouteConnectionHandler(
194
- this.settings,
195
- this.connectionManager,
196
- this.securityManager,
197
- this.tlsManager,
198
- this.httpProxyBridge,
199
- this.timeoutManager,
200
- this.routeManager
201
- );
189
+ this.routeConnectionHandler = new RouteConnectionHandler(this);
202
190
 
203
191
  // Initialize port manager
204
- this.portManager = new PortManager(this.settings, this.routeConnectionHandler);
192
+ this.portManager = new PortManager(this);
205
193
 
206
194
  // Initialize NFTablesManager
207
- this.nftablesManager = new NFTablesManager(this.settings);
195
+ this.nftablesManager = new NFTablesManager(this);
208
196
 
209
197
  // Initialize route update mutex for synchronization
210
198
  this.routeUpdateLock = new Mutex();
@@ -213,7 +201,10 @@ export class SmartProxy extends plugins.EventEmitter {
213
201
  this.acmeStateManager = new AcmeStateManager();
214
202
 
215
203
  // Initialize metrics collector with reference to this SmartProxy instance
216
- this.metricsCollector = new MetricsCollector(this);
204
+ this.metricsCollector = new MetricsCollector(this, {
205
+ sampleIntervalMs: this.settings.metrics?.sampleIntervalMs,
206
+ retentionSeconds: this.settings.metrics?.retentionSeconds
207
+ });
217
208
  }
218
209
 
219
210
  /**
@@ -922,11 +913,11 @@ export class SmartProxy extends plugins.EventEmitter {
922
913
  }
923
914
 
924
915
  /**
925
- * Get proxy statistics and metrics
916
+ * Get proxy metrics with clean API
926
917
  *
927
- * @returns IProxyStats interface with various metrics methods
918
+ * @returns IMetrics interface with grouped metrics methods
928
919
  */
929
- public getStats(): IProxyStats {
920
+ public getMetrics(): IMetrics {
930
921
  return this.metricsCollector;
931
922
  }
932
923
 
@@ -0,0 +1,144 @@
1
+ import type { IThroughputSample, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
2
+
3
+ /**
4
+ * Tracks throughput data using time-series sampling
5
+ */
6
+ export class ThroughputTracker {
7
+ private samples: IThroughputSample[] = [];
8
+ private readonly maxSamples: number;
9
+ private accumulatedBytesIn: number = 0;
10
+ private accumulatedBytesOut: number = 0;
11
+ private lastSampleTime: number = 0;
12
+
13
+ constructor(retentionSeconds: number = 3600) {
14
+ // Keep samples for the retention period at 1 sample per second
15
+ this.maxSamples = retentionSeconds;
16
+ }
17
+
18
+ /**
19
+ * Record bytes transferred (called on every data transfer)
20
+ */
21
+ public recordBytes(bytesIn: number, bytesOut: number): void {
22
+ this.accumulatedBytesIn += bytesIn;
23
+ this.accumulatedBytesOut += bytesOut;
24
+ }
25
+
26
+ /**
27
+ * Take a sample of accumulated bytes (called every second)
28
+ */
29
+ public takeSample(): void {
30
+ const now = Date.now();
31
+
32
+ // Record accumulated bytes since last sample
33
+ this.samples.push({
34
+ timestamp: now,
35
+ bytesIn: this.accumulatedBytesIn,
36
+ bytesOut: this.accumulatedBytesOut
37
+ });
38
+
39
+ // Reset accumulators
40
+ this.accumulatedBytesIn = 0;
41
+ this.accumulatedBytesOut = 0;
42
+ this.lastSampleTime = now;
43
+
44
+ // Maintain circular buffer - remove oldest samples
45
+ if (this.samples.length > this.maxSamples) {
46
+ this.samples.shift();
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Get throughput rate over specified window (bytes per second)
52
+ */
53
+ public getRate(windowSeconds: number): IThroughputData {
54
+ if (this.samples.length === 0) {
55
+ return { in: 0, out: 0 };
56
+ }
57
+
58
+ const now = Date.now();
59
+ const windowStart = now - (windowSeconds * 1000);
60
+
61
+ // Find samples within the window
62
+ const relevantSamples = this.samples.filter(s => s.timestamp > windowStart);
63
+
64
+ if (relevantSamples.length === 0) {
65
+ return { in: 0, out: 0 };
66
+ }
67
+
68
+ // Sum bytes in the window
69
+ const totalBytesIn = relevantSamples.reduce((sum, s) => sum + s.bytesIn, 0);
70
+ const totalBytesOut = relevantSamples.reduce((sum, s) => sum + s.bytesOut, 0);
71
+
72
+ // Calculate actual window duration (might be less than requested if not enough data)
73
+ const actualWindowSeconds = Math.min(
74
+ windowSeconds,
75
+ (now - relevantSamples[0].timestamp) / 1000
76
+ );
77
+
78
+ // Avoid division by zero
79
+ if (actualWindowSeconds === 0) {
80
+ return { in: 0, out: 0 };
81
+ }
82
+
83
+ return {
84
+ in: Math.round(totalBytesIn / actualWindowSeconds),
85
+ out: Math.round(totalBytesOut / actualWindowSeconds)
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Get throughput history for specified duration
91
+ */
92
+ public getHistory(durationSeconds: number): IThroughputHistoryPoint[] {
93
+ const now = Date.now();
94
+ const startTime = now - (durationSeconds * 1000);
95
+
96
+ // Filter samples within duration
97
+ const relevantSamples = this.samples.filter(s => s.timestamp > startTime);
98
+
99
+ // Convert to history points with per-second rates
100
+ const history: IThroughputHistoryPoint[] = [];
101
+
102
+ for (let i = 0; i < relevantSamples.length; i++) {
103
+ const sample = relevantSamples[i];
104
+
105
+ // For the first sample or samples after gaps, we can't calculate rate
106
+ if (i === 0 || sample.timestamp - relevantSamples[i - 1].timestamp > 2000) {
107
+ history.push({
108
+ timestamp: sample.timestamp,
109
+ in: sample.bytesIn,
110
+ out: sample.bytesOut
111
+ });
112
+ } else {
113
+ // Calculate rate based on time since previous sample
114
+ const prevSample = relevantSamples[i - 1];
115
+ const timeDelta = (sample.timestamp - prevSample.timestamp) / 1000;
116
+
117
+ history.push({
118
+ timestamp: sample.timestamp,
119
+ in: Math.round(sample.bytesIn / timeDelta),
120
+ out: Math.round(sample.bytesOut / timeDelta)
121
+ });
122
+ }
123
+ }
124
+
125
+ return history;
126
+ }
127
+
128
+ /**
129
+ * Clear all samples
130
+ */
131
+ public clear(): void {
132
+ this.samples = [];
133
+ this.accumulatedBytesIn = 0;
134
+ this.accumulatedBytesOut = 0;
135
+ this.lastSampleTime = 0;
136
+ }
137
+
138
+ /**
139
+ * Get sample count for debugging
140
+ */
141
+ public getSampleCount(): number {
142
+ return this.samples.length;
143
+ }
144
+ }
@@ -1,10 +1,11 @@
1
- import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
1
+ import type { IConnectionRecord } from './models/interfaces.js';
2
+ import type { SmartProxy } from './smart-proxy.js';
2
3
 
3
4
  /**
4
5
  * Manages timeouts and inactivity tracking for connections
5
6
  */
6
7
  export class TimeoutManager {
7
- constructor(private settings: ISmartProxyOptions) {}
8
+ constructor(private smartProxy: SmartProxy) {}
8
9
 
9
10
  /**
10
11
  * Ensure timeout values don't exceed Node.js max safe integer
@@ -41,16 +42,16 @@ export class TimeoutManager {
41
42
  * Calculate effective inactivity timeout based on connection type
42
43
  */
43
44
  public getEffectiveInactivityTimeout(record: IConnectionRecord): number {
44
- let effectiveTimeout = this.settings.inactivityTimeout || 14400000; // 4 hours default
45
+ let effectiveTimeout = this.smartProxy.settings.inactivityTimeout || 14400000; // 4 hours default
45
46
 
46
47
  // For immortal keep-alive connections, use an extremely long timeout
47
- if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
48
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
48
49
  return Number.MAX_SAFE_INTEGER;
49
50
  }
50
51
 
51
52
  // For extended keep-alive connections, apply multiplier
52
- if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'extended') {
53
- const multiplier = this.settings.keepAliveInactivityMultiplier || 6;
53
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'extended') {
54
+ const multiplier = this.smartProxy.settings.keepAliveInactivityMultiplier || 6;
54
55
  effectiveTimeout = effectiveTimeout * multiplier;
55
56
  }
56
57
 
@@ -63,23 +64,23 @@ export class TimeoutManager {
63
64
  public getEffectiveMaxLifetime(record: IConnectionRecord): number {
64
65
  // Use route-specific timeout if available from the routeConfig
65
66
  const baseTimeout = record.routeConfig?.action.advanced?.timeout ||
66
- this.settings.maxConnectionLifetime ||
67
+ this.smartProxy.settings.maxConnectionLifetime ||
67
68
  86400000; // 24 hours default
68
69
 
69
70
  // For immortal keep-alive connections, use an extremely long lifetime
70
- if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
71
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
71
72
  return Number.MAX_SAFE_INTEGER;
72
73
  }
73
74
 
74
75
  // For extended keep-alive connections, use the extended lifetime setting
75
- if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'extended') {
76
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'extended') {
76
77
  return this.ensureSafeTimeout(
77
- this.settings.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000 // 7 days default
78
+ this.smartProxy.settings.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000 // 7 days default
78
79
  );
79
80
  }
80
81
 
81
82
  // Apply randomization if enabled
82
- if (this.settings.enableRandomizedTimeouts) {
83
+ if (this.smartProxy.settings.enableRandomizedTimeouts) {
83
84
  return this.randomizeTimeout(baseTimeout);
84
85
  }
85
86
 
@@ -93,12 +94,17 @@ export class TimeoutManager {
93
94
  public setupConnectionTimeout(
94
95
  record: IConnectionRecord,
95
96
  onTimeout: (record: IConnectionRecord, reason: string) => void
96
- ): NodeJS.Timeout {
97
+ ): NodeJS.Timeout | null {
97
98
  // Clear any existing timer
98
99
  if (record.cleanupTimer) {
99
100
  clearTimeout(record.cleanupTimer);
100
101
  }
101
102
 
103
+ // Skip timeout for immortal keep-alive connections
104
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
105
+ return null;
106
+ }
107
+
102
108
  // Calculate effective timeout
103
109
  const effectiveLifetime = this.getEffectiveMaxLifetime(record);
104
110
 
@@ -127,7 +133,7 @@ export class TimeoutManager {
127
133
  effectiveTimeout: number;
128
134
  } {
129
135
  // Skip for connections with inactivity check disabled
130
- if (this.settings.disableInactivityCheck) {
136
+ if (this.smartProxy.settings.disableInactivityCheck) {
131
137
  return {
132
138
  isInactive: false,
133
139
  shouldWarn: false,
@@ -137,7 +143,7 @@ export class TimeoutManager {
137
143
  }
138
144
 
139
145
  // Skip for immortal keep-alive connections
140
- if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
146
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
141
147
  return {
142
148
  isInactive: false,
143
149
  shouldWarn: false,
@@ -171,7 +177,7 @@ export class TimeoutManager {
171
177
  */
172
178
  public applySocketTimeouts(record: IConnectionRecord): void {
173
179
  // Skip for immortal keep-alive connections
174
- if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
180
+ if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
175
181
  // Disable timeouts completely for immortal connections
176
182
  record.incoming.setTimeout(0);
177
183
  if (record.outgoing) {
@@ -181,7 +187,7 @@ export class TimeoutManager {
181
187
  }
182
188
 
183
189
  // Apply normal timeouts
184
- const timeout = this.ensureSafeTimeout(this.settings.socketTimeout || 3600000); // 1 hour default
190
+ const timeout = this.ensureSafeTimeout(this.smartProxy.settings.socketTimeout || 3600000); // 1 hour default
185
191
  record.incoming.setTimeout(timeout);
186
192
  if (record.outgoing) {
187
193
  record.outgoing.setTimeout(timeout);
@@ -1,6 +1,6 @@
1
1
  import * as plugins from '../../plugins.js';
2
- import type { ISmartProxyOptions } from './models/interfaces.js';
3
2
  import { SniHandler } from '../../tls/sni/sni-handler.js';
3
+ import type { SmartProxy } from './smart-proxy.js';
4
4
 
5
5
  /**
6
6
  * Interface for connection information used for SNI extraction
@@ -16,7 +16,7 @@ interface IConnectionInfo {
16
16
  * Manages TLS-related operations including SNI extraction and validation
17
17
  */
18
18
  export class TlsManager {
19
- constructor(private settings: ISmartProxyOptions) {}
19
+ constructor(private smartProxy: SmartProxy) {}
20
20
 
21
21
  /**
22
22
  * Check if a data chunk appears to be a TLS handshake
@@ -44,7 +44,7 @@ export class TlsManager {
44
44
  return SniHandler.processTlsPacket(
45
45
  chunk,
46
46
  connInfo,
47
- this.settings.enableTlsDebugLogging || false,
47
+ this.smartProxy.settings.enableTlsDebugLogging || false,
48
48
  previousDomain
49
49
  );
50
50
  }
@@ -58,19 +58,19 @@ export class TlsManager {
58
58
  hasSNI: boolean
59
59
  ): { shouldBlock: boolean; reason?: string } {
60
60
  // Skip if session tickets are allowed
61
- if (this.settings.allowSessionTicket !== false) {
61
+ if (this.smartProxy.settings.allowSessionTicket !== false) {
62
62
  return { shouldBlock: false };
63
63
  }
64
64
 
65
65
  // Check for session resumption attempt
66
66
  const resumptionInfo = SniHandler.hasSessionResumption(
67
67
  chunk,
68
- this.settings.enableTlsDebugLogging || false
68
+ this.smartProxy.settings.enableTlsDebugLogging || false
69
69
  );
70
70
 
71
71
  // If this is a resumption attempt without SNI, block it
72
72
  if (resumptionInfo.isResumption && !hasSNI && !resumptionInfo.hasSNI) {
73
- if (this.settings.enableTlsDebugLogging) {
73
+ if (this.smartProxy.settings.enableTlsDebugLogging) {
74
74
  console.log(
75
75
  `[${connectionId}] Session resumption detected without SNI and allowSessionTicket=false. ` +
76
76
  `Terminating connection to force new TLS handshake.`
@@ -104,7 +104,7 @@ export class TlsManager {
104
104
  const newSNI = SniHandler.extractSNIWithResumptionSupport(
105
105
  chunk,
106
106
  connInfo,
107
- this.settings.enableTlsDebugLogging || false
107
+ this.smartProxy.settings.enableTlsDebugLogging || false
108
108
  );
109
109
 
110
110
  // Skip if no SNI was found
@@ -112,14 +112,14 @@ export class TlsManager {
112
112
 
113
113
  // Check for SNI mismatch
114
114
  if (newSNI !== expectedDomain) {
115
- if (this.settings.enableTlsDebugLogging) {
115
+ if (this.smartProxy.settings.enableTlsDebugLogging) {
116
116
  console.log(
117
117
  `[${connectionId}] Renegotiation with different SNI: ${expectedDomain} -> ${newSNI}. ` +
118
118
  `Terminating connection - SNI domain switching is not allowed.`
119
119
  );
120
120
  }
121
121
  return { hasMismatch: true, extractedSNI: newSNI };
122
- } else if (this.settings.enableTlsDebugLogging) {
122
+ } else if (this.smartProxy.settings.enableTlsDebugLogging) {
123
123
  console.log(
124
124
  `[${connectionId}] Renegotiation detected with same SNI: ${newSNI}. Allowing.`
125
125
  );
@@ -175,13 +175,13 @@ export class TlsManager {
175
175
  // Check for session resumption
176
176
  const resumptionInfo = SniHandler.hasSessionResumption(
177
177
  chunk,
178
- this.settings.enableTlsDebugLogging || false
178
+ this.smartProxy.settings.enableTlsDebugLogging || false
179
179
  );
180
180
 
181
181
  // Extract SNI
182
182
  const sni = SniHandler.extractSNI(
183
183
  chunk,
184
- this.settings.enableTlsDebugLogging || false
184
+ this.smartProxy.settings.enableTlsDebugLogging || false
185
185
  );
186
186
 
187
187
  // Update result
@@ -168,7 +168,7 @@ export class HttpRouter {
168
168
  if (pathResult.matches) {
169
169
  return {
170
170
  route,
171
- pathMatch: path,
171
+ pathMatch: pathResult.pathMatch || path,
172
172
  pathParams: pathResult.params,
173
173
  pathRemainder: pathResult.pathRemainder
174
174
  };