@push.rocks/smartproxy 21.1.7 → 22.6.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/changelog.md +109 -0
- package/dist_rust/rustproxy +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/utils/shared-security-manager.d.ts +17 -0
- package/dist_ts/core/utils/shared-security-manager.js +66 -1
- package/dist_ts/index.d.ts +1 -5
- package/dist_ts/index.js +3 -9
- package/dist_ts/protocols/common/fragment-handler.js +5 -1
- package/dist_ts/proxies/http-proxy/default-certificates.d.ts +54 -0
- package/dist_ts/proxies/http-proxy/default-certificates.js +127 -0
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +1 -1
- package/dist_ts/proxies/http-proxy/http-proxy.js +9 -14
- package/dist_ts/proxies/http-proxy/index.d.ts +5 -1
- package/dist_ts/proxies/http-proxy/index.js +6 -2
- package/dist_ts/proxies/http-proxy/security-manager.d.ts +4 -12
- package/dist_ts/proxies/http-proxy/security-manager.js +66 -99
- package/dist_ts/proxies/index.d.ts +1 -5
- package/dist_ts/proxies/index.js +2 -6
- package/dist_ts/proxies/nftables-proxy/index.d.ts +1 -0
- package/dist_ts/proxies/nftables-proxy/index.js +2 -1
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +4 -26
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +84 -236
- package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +9 -0
- package/dist_ts/proxies/nftables-proxy/utils/index.js +12 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +66 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +131 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +39 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +112 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +59 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +130 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +4 -3
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +13 -2
- package/dist_ts/proxies/smart-proxy/connection-manager.js +16 -6
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +35 -10
- package/dist_ts/proxies/smart-proxy/index.d.ts +5 -10
- package/dist_ts/proxies/smart-proxy/index.js +7 -13
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -3
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +17 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +72 -9
- package/dist_ts/proxies/smart-proxy/route-preprocessor.d.ts +37 -0
- package/dist_ts/proxies/smart-proxy/route-preprocessor.js +103 -0
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +23 -0
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +104 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +74 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +146 -0
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +49 -0
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +259 -0
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +14 -12
- package/dist_ts/proxies/smart-proxy/security-manager.js +80 -74
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +39 -157
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +224 -622
- package/dist_ts/proxies/smart-proxy/socket-handler-server.d.ts +45 -0
- package/dist_ts/proxies/smart-proxy/socket-handler-server.js +253 -0
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +2 -9
- package/dist_ts/proxies/smart-proxy/tls-manager.js +3 -26
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.d.ts +49 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.js +108 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.d.ts +57 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.js +89 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.d.ts +17 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.js +32 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.d.ts +68 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.js +117 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.d.ts +17 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.js +27 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.d.ts +63 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.js +105 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.d.ts +83 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.js +126 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.d.ts +47 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.js +66 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +70 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +287 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.d.ts +46 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.js +67 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +4 -457
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +6 -950
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +2 -2
- package/dist_ts/proxies/smart-proxy/utils/route-validator.d.ts +67 -1
- package/dist_ts/proxies/smart-proxy/utils/route-validator.js +251 -3
- package/dist_ts/routing/index.d.ts +1 -1
- package/dist_ts/routing/index.js +3 -3
- package/dist_ts/routing/models/http-types.d.ts +119 -4
- package/dist_ts/routing/models/http-types.js +93 -5
- package/npmextra.json +12 -6
- package/package.json +34 -24
- package/readme.hints.md +184 -1
- package/readme.md +580 -266
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/utils/shared-security-manager.ts +98 -13
- package/ts/index.ts +4 -12
- package/ts/protocols/common/fragment-handler.ts +4 -0
- package/ts/proxies/index.ts +1 -9
- package/ts/proxies/nftables-proxy/index.ts +1 -0
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +116 -290
- package/ts/proxies/nftables-proxy/utils/index.ts +38 -0
- package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +162 -0
- package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +125 -0
- package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +156 -0
- package/ts/proxies/smart-proxy/index.ts +6 -13
- package/ts/proxies/smart-proxy/models/interfaces.ts +6 -5
- package/ts/proxies/smart-proxy/route-preprocessor.ts +122 -0
- package/ts/proxies/smart-proxy/rust-binary-locator.ts +112 -0
- package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +161 -0
- package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +310 -0
- package/ts/proxies/smart-proxy/smart-proxy.ts +282 -800
- package/ts/proxies/smart-proxy/socket-handler-server.ts +279 -0
- package/ts/proxies/smart-proxy/utils/index.ts +3 -5
- package/ts/proxies/smart-proxy/utils/route-helpers/api-helpers.ts +144 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.ts +124 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/http-helpers.ts +40 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/https-helpers.ts +163 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/index.ts +62 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.ts +154 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.ts +202 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/security-helpers.ts +96 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +337 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.ts +98 -0
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +5 -1302
- package/ts/proxies/smart-proxy/utils/route-utils.ts +1 -1
- package/ts/proxies/smart-proxy/utils/route-validator.ts +274 -4
- package/ts/routing/index.ts +2 -2
- package/ts/routing/models/http-types.ts +147 -4
- package/ts/proxies/http-proxy/certificate-manager.ts +0 -244
- package/ts/proxies/http-proxy/connection-pool.ts +0 -228
- package/ts/proxies/http-proxy/context-creator.ts +0 -145
- package/ts/proxies/http-proxy/function-cache.ts +0 -279
- package/ts/proxies/http-proxy/handlers/index.ts +0 -5
- package/ts/proxies/http-proxy/http-proxy.ts +0 -675
- package/ts/proxies/http-proxy/http-request-handler.ts +0 -331
- package/ts/proxies/http-proxy/http2-request-handler.ts +0 -255
- package/ts/proxies/http-proxy/index.ts +0 -13
- package/ts/proxies/http-proxy/models/http-types.ts +0 -148
- package/ts/proxies/http-proxy/models/index.ts +0 -5
- package/ts/proxies/http-proxy/models/types.ts +0 -125
- package/ts/proxies/http-proxy/request-handler.ts +0 -878
- package/ts/proxies/http-proxy/security-manager.ts +0 -433
- package/ts/proxies/http-proxy/websocket-handler.ts +0 -581
- package/ts/proxies/smart-proxy/acme-state-manager.ts +0 -112
- package/ts/proxies/smart-proxy/cert-store.ts +0 -92
- package/ts/proxies/smart-proxy/certificate-manager.ts +0 -894
- package/ts/proxies/smart-proxy/connection-manager.ts +0 -796
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +0 -187
- package/ts/proxies/smart-proxy/metrics-collector.ts +0 -453
- package/ts/proxies/smart-proxy/nftables-manager.ts +0 -271
- package/ts/proxies/smart-proxy/port-manager.ts +0 -358
- package/ts/proxies/smart-proxy/route-connection-handler.ts +0 -1640
- package/ts/proxies/smart-proxy/route-orchestrator.ts +0 -297
- package/ts/proxies/smart-proxy/security-manager.ts +0 -257
- package/ts/proxies/smart-proxy/throughput-tracker.ts +0 -138
- package/ts/proxies/smart-proxy/timeout-manager.ts +0 -196
- package/ts/proxies/smart-proxy/tls-manager.ts +0 -207
- package/ts/proxies/smart-proxy/utils/route-validators.ts +0 -283
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { AsyncFileSystem } from '../../core/utils/fs-utils.js';
|
|
6
|
-
import { type IHttpProxyOptions, type ICertificateEntry, type ILogger, createLogger } from './models/types.js';
|
|
7
|
-
import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @deprecated This class is deprecated. Use SmartCertManager instead.
|
|
11
|
-
*
|
|
12
|
-
* This is a stub implementation that maintains backward compatibility
|
|
13
|
-
* while the functionality has been moved to SmartCertManager.
|
|
14
|
-
*/
|
|
15
|
-
export class CertificateManager {
|
|
16
|
-
private defaultCertificates: { key: string; cert: string };
|
|
17
|
-
private certificateCache: Map<string, ICertificateEntry> = new Map();
|
|
18
|
-
private certificateStoreDir: string;
|
|
19
|
-
private logger: ILogger;
|
|
20
|
-
private httpsServer: plugins.https.Server | null = null;
|
|
21
|
-
private initialized = false;
|
|
22
|
-
|
|
23
|
-
constructor(private options: IHttpProxyOptions) {
|
|
24
|
-
this.certificateStoreDir = path.resolve(options.acme?.certificateStore || './certs');
|
|
25
|
-
this.logger = createLogger(options.logLevel || 'info');
|
|
26
|
-
|
|
27
|
-
this.logger.warn('CertificateManager is deprecated - use SmartCertManager instead');
|
|
28
|
-
|
|
29
|
-
// Initialize synchronously for backward compatibility but log warning
|
|
30
|
-
this.initializeSync();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Synchronous initialization for backward compatibility
|
|
35
|
-
* @deprecated This uses sync filesystem operations which block the event loop
|
|
36
|
-
*/
|
|
37
|
-
private initializeSync(): void {
|
|
38
|
-
// Ensure certificate store directory exists
|
|
39
|
-
try {
|
|
40
|
-
if (!fs.existsSync(this.certificateStoreDir)) {
|
|
41
|
-
fs.mkdirSync(this.certificateStoreDir, { recursive: true });
|
|
42
|
-
this.logger.info(`Created certificate store directory: ${this.certificateStoreDir}`);
|
|
43
|
-
}
|
|
44
|
-
} catch (error) {
|
|
45
|
-
this.logger.warn(`Failed to create certificate store directory: ${error}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.loadDefaultCertificates();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Async initialization - preferred method
|
|
53
|
-
*/
|
|
54
|
-
public async initialize(): Promise<void> {
|
|
55
|
-
if (this.initialized) return;
|
|
56
|
-
|
|
57
|
-
// Ensure certificate store directory exists
|
|
58
|
-
try {
|
|
59
|
-
await AsyncFileSystem.ensureDir(this.certificateStoreDir);
|
|
60
|
-
this.logger.info(`Ensured certificate store directory: ${this.certificateStoreDir}`);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
this.logger.warn(`Failed to create certificate store directory: ${error}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
await this.loadDefaultCertificatesAsync();
|
|
66
|
-
this.initialized = true;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Loads default certificates from the filesystem
|
|
71
|
-
* @deprecated This uses sync filesystem operations which block the event loop
|
|
72
|
-
*/
|
|
73
|
-
public loadDefaultCertificates(): void {
|
|
74
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
75
|
-
const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
this.defaultCertificates = {
|
|
79
|
-
key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
|
|
80
|
-
cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
|
|
81
|
-
};
|
|
82
|
-
this.logger.info('Loaded default certificates from filesystem (sync - deprecated)');
|
|
83
|
-
} catch (error) {
|
|
84
|
-
this.logger.error(`Failed to load default certificates: ${error}`);
|
|
85
|
-
this.generateSelfSignedCertificate();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Loads default certificates from the filesystem asynchronously
|
|
91
|
-
*/
|
|
92
|
-
public async loadDefaultCertificatesAsync(): Promise<void> {
|
|
93
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
94
|
-
const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
const [key, cert] = await Promise.all([
|
|
98
|
-
AsyncFileSystem.readFile(path.join(certPath, 'key.pem')),
|
|
99
|
-
AsyncFileSystem.readFile(path.join(certPath, 'cert.pem'))
|
|
100
|
-
]);
|
|
101
|
-
|
|
102
|
-
this.defaultCertificates = { key, cert };
|
|
103
|
-
this.logger.info('Loaded default certificates from filesystem (async)');
|
|
104
|
-
} catch (error) {
|
|
105
|
-
this.logger.error(`Failed to load default certificates: ${error}`);
|
|
106
|
-
this.generateSelfSignedCertificate();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Generates self-signed certificates as fallback
|
|
112
|
-
*/
|
|
113
|
-
private generateSelfSignedCertificate(): void {
|
|
114
|
-
// Generate a self-signed certificate using forge or similar
|
|
115
|
-
// For now, just use a placeholder
|
|
116
|
-
const selfSignedCert = `-----BEGIN CERTIFICATE-----
|
|
117
|
-
MIIBkTCB+wIJAKHHIgIIA0/cMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAYTAlVT
|
|
118
|
-
MB4XDTE0MDEwMTAwMDAwMFoXDTI0MDEwMTAwMDAwMFowDTELMAkGA1UEBhMCVVMw
|
|
119
|
-
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRiH0VwnOH3jCV7c6JFZWYrvuqy
|
|
120
|
-
-----END CERTIFICATE-----`;
|
|
121
|
-
|
|
122
|
-
const selfSignedKey = `-----BEGIN PRIVATE KEY-----
|
|
123
|
-
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMRiH0VwnOH3jCV7
|
|
124
|
-
c6JFZWYrvuqyALCLXj0pcr1iqNdHjegNXnkl5zjdaUjq4edNOKl7M1AlFiYjG2xk
|
|
125
|
-
-----END PRIVATE KEY-----`;
|
|
126
|
-
|
|
127
|
-
this.defaultCertificates = {
|
|
128
|
-
key: selfSignedKey,
|
|
129
|
-
cert: selfSignedCert
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
this.logger.warn('Using self-signed certificate as fallback');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Gets the default certificates
|
|
137
|
-
*/
|
|
138
|
-
public getDefaultCertificates(): { key: string; cert: string } {
|
|
139
|
-
return this.defaultCertificates;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* @deprecated Use SmartCertManager instead
|
|
144
|
-
*/
|
|
145
|
-
public setExternalPort80Handler(handler: any): void {
|
|
146
|
-
this.logger.warn('setExternalPort80Handler is deprecated - use SmartCertManager instead');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* @deprecated Use SmartCertManager instead
|
|
151
|
-
*/
|
|
152
|
-
public async updateRoutes(routes: IRouteConfig[]): Promise<void> {
|
|
153
|
-
this.logger.warn('updateRoutes is deprecated - use SmartCertManager instead');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Handles SNI callback to provide appropriate certificate
|
|
158
|
-
*/
|
|
159
|
-
public handleSNI(domain: string, cb: (err: Error | null, ctx: plugins.tls.SecureContext) => void): void {
|
|
160
|
-
const certificate = this.getCachedCertificate(domain);
|
|
161
|
-
|
|
162
|
-
if (certificate) {
|
|
163
|
-
const context = plugins.tls.createSecureContext({
|
|
164
|
-
key: certificate.key,
|
|
165
|
-
cert: certificate.cert
|
|
166
|
-
});
|
|
167
|
-
cb(null, context);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Use default certificate if no domain-specific certificate found
|
|
172
|
-
const defaultContext = plugins.tls.createSecureContext({
|
|
173
|
-
key: this.defaultCertificates.key,
|
|
174
|
-
cert: this.defaultCertificates.cert
|
|
175
|
-
});
|
|
176
|
-
cb(null, defaultContext);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Updates a certificate in the cache
|
|
181
|
-
*/
|
|
182
|
-
public updateCertificate(domain: string, cert: string, key: string): void {
|
|
183
|
-
this.certificateCache.set(domain, {
|
|
184
|
-
cert,
|
|
185
|
-
key,
|
|
186
|
-
expires: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
this.logger.info(`Certificate updated for ${domain}`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Gets a cached certificate
|
|
194
|
-
*/
|
|
195
|
-
private getCachedCertificate(domain: string): ICertificateEntry | null {
|
|
196
|
-
return this.certificateCache.get(domain) || null;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @deprecated Use SmartCertManager instead
|
|
201
|
-
*/
|
|
202
|
-
public async initializePort80Handler(): Promise<any> {
|
|
203
|
-
this.logger.warn('initializePort80Handler is deprecated - use SmartCertManager instead');
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* @deprecated Use SmartCertManager instead
|
|
209
|
-
*/
|
|
210
|
-
public async stopPort80Handler(): Promise<void> {
|
|
211
|
-
this.logger.warn('stopPort80Handler is deprecated - use SmartCertManager instead');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* @deprecated Use SmartCertManager instead
|
|
216
|
-
*/
|
|
217
|
-
public registerDomainsWithPort80Handler(domains: string[]): void {
|
|
218
|
-
this.logger.warn('registerDomainsWithPort80Handler is deprecated - use SmartCertManager instead');
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* @deprecated Use SmartCertManager instead
|
|
223
|
-
*/
|
|
224
|
-
public registerRoutesWithPort80Handler(routes: IRouteConfig[]): void {
|
|
225
|
-
this.logger.warn('registerRoutesWithPort80Handler is deprecated - use SmartCertManager instead');
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Sets the HTTPS server for certificate updates
|
|
230
|
-
*/
|
|
231
|
-
public setHttpsServer(server: plugins.https.Server): void {
|
|
232
|
-
this.httpsServer = server;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Gets statistics for metrics
|
|
237
|
-
*/
|
|
238
|
-
public getStats() {
|
|
239
|
-
return {
|
|
240
|
-
cachedCertificates: this.certificateCache.size,
|
|
241
|
-
defaultCertEnabled: true
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
}
|
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import { type IHttpProxyOptions, type IConnectionEntry, type ILogger, createLogger } from './models/types.js';
|
|
3
|
-
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Manages a pool of backend connections for efficient reuse
|
|
7
|
-
*/
|
|
8
|
-
export class ConnectionPool {
|
|
9
|
-
private connectionPool: Map<string, Array<IConnectionEntry>> = new Map();
|
|
10
|
-
private roundRobinPositions: Map<string, number> = new Map();
|
|
11
|
-
private logger: ILogger;
|
|
12
|
-
|
|
13
|
-
constructor(private options: IHttpProxyOptions) {
|
|
14
|
-
this.logger = createLogger(options.logLevel || 'info');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Get a connection from the pool or create a new one
|
|
19
|
-
*/
|
|
20
|
-
public getConnection(host: string, port: number): Promise<plugins.net.Socket> {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
const poolKey = `${host}:${port}`;
|
|
23
|
-
const connectionList = this.connectionPool.get(poolKey) || [];
|
|
24
|
-
|
|
25
|
-
// Look for an idle connection
|
|
26
|
-
const idleConnectionIndex = connectionList.findIndex(c => c.isIdle);
|
|
27
|
-
|
|
28
|
-
if (idleConnectionIndex >= 0) {
|
|
29
|
-
// Get existing connection from pool
|
|
30
|
-
const connection = connectionList[idleConnectionIndex];
|
|
31
|
-
connection.isIdle = false;
|
|
32
|
-
connection.lastUsed = Date.now();
|
|
33
|
-
this.logger.debug(`Reusing connection from pool for ${poolKey}`);
|
|
34
|
-
|
|
35
|
-
// Update the pool
|
|
36
|
-
this.connectionPool.set(poolKey, connectionList);
|
|
37
|
-
|
|
38
|
-
resolve(connection.socket);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// No idle connection available, create a new one if pool isn't full
|
|
43
|
-
const poolSize = this.options.connectionPoolSize || 50;
|
|
44
|
-
if (connectionList.length < poolSize) {
|
|
45
|
-
this.logger.debug(`Creating new connection to ${host}:${port}`);
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const socket = plugins.net.connect({
|
|
49
|
-
host,
|
|
50
|
-
port,
|
|
51
|
-
keepAlive: true,
|
|
52
|
-
keepAliveInitialDelay: 30000 // 30 seconds
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
socket.once('connect', () => {
|
|
56
|
-
// Add to connection pool
|
|
57
|
-
const connection = {
|
|
58
|
-
socket,
|
|
59
|
-
lastUsed: Date.now(),
|
|
60
|
-
isIdle: false
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
connectionList.push(connection);
|
|
64
|
-
this.connectionPool.set(poolKey, connectionList);
|
|
65
|
-
|
|
66
|
-
// Setup cleanup when the connection is closed
|
|
67
|
-
socket.once('close', () => {
|
|
68
|
-
const idx = connectionList.findIndex(c => c.socket === socket);
|
|
69
|
-
if (idx >= 0) {
|
|
70
|
-
connectionList.splice(idx, 1);
|
|
71
|
-
this.connectionPool.set(poolKey, connectionList);
|
|
72
|
-
this.logger.debug(`Removed closed connection from pool for ${poolKey}`);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
resolve(socket);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
socket.once('error', (err) => {
|
|
80
|
-
this.logger.error(`Error creating connection to ${host}:${port}`, err);
|
|
81
|
-
reject(err);
|
|
82
|
-
});
|
|
83
|
-
} catch (err) {
|
|
84
|
-
this.logger.error(`Failed to create connection to ${host}:${port}`, err);
|
|
85
|
-
reject(err);
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
// Pool is full, wait for an idle connection or reject
|
|
89
|
-
this.logger.warn(`Connection pool for ${poolKey} is full (${connectionList.length})`);
|
|
90
|
-
reject(new Error(`Connection pool for ${poolKey} is full`));
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Return a connection to the pool for reuse
|
|
97
|
-
*/
|
|
98
|
-
public returnConnection(socket: plugins.net.Socket, host: string, port: number): void {
|
|
99
|
-
const poolKey = `${host}:${port}`;
|
|
100
|
-
const connectionList = this.connectionPool.get(poolKey) || [];
|
|
101
|
-
|
|
102
|
-
// Find this connection in the pool
|
|
103
|
-
const connectionIndex = connectionList.findIndex(c => c.socket === socket);
|
|
104
|
-
|
|
105
|
-
if (connectionIndex >= 0) {
|
|
106
|
-
// Mark as idle and update last used time
|
|
107
|
-
connectionList[connectionIndex].isIdle = true;
|
|
108
|
-
connectionList[connectionIndex].lastUsed = Date.now();
|
|
109
|
-
|
|
110
|
-
this.logger.debug(`Returned connection to pool for ${poolKey}`);
|
|
111
|
-
} else {
|
|
112
|
-
this.logger.warn(`Attempted to return unknown connection to pool for ${poolKey}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Cleanup the connection pool by removing idle connections
|
|
118
|
-
* or reducing pool size if it exceeds the configured maximum
|
|
119
|
-
*/
|
|
120
|
-
public cleanupConnectionPool(): void {
|
|
121
|
-
const now = Date.now();
|
|
122
|
-
const idleTimeout = this.options.keepAliveTimeout || 120000; // 2 minutes default
|
|
123
|
-
|
|
124
|
-
for (const [host, connections] of this.connectionPool.entries()) {
|
|
125
|
-
// Sort by last used time (oldest first)
|
|
126
|
-
connections.sort((a, b) => a.lastUsed - b.lastUsed);
|
|
127
|
-
|
|
128
|
-
// Remove idle connections older than the idle timeout
|
|
129
|
-
let removed = 0;
|
|
130
|
-
while (connections.length > 0) {
|
|
131
|
-
const connection = connections[0];
|
|
132
|
-
|
|
133
|
-
// Remove if idle and exceeds timeout, or if pool is too large
|
|
134
|
-
if ((connection.isIdle && now - connection.lastUsed > idleTimeout) ||
|
|
135
|
-
connections.length > (this.options.connectionPoolSize || 50)) {
|
|
136
|
-
|
|
137
|
-
cleanupSocket(connection.socket, `pool-${host}-idle`, { immediate: true }).catch(() => {});
|
|
138
|
-
|
|
139
|
-
connections.shift(); // Remove from pool
|
|
140
|
-
removed++;
|
|
141
|
-
} else {
|
|
142
|
-
break; // Stop removing if we've reached active or recent connections
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (removed > 0) {
|
|
147
|
-
this.logger.debug(`Removed ${removed} idle connections from pool for ${host}, ${connections.length} remaining`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Update the pool with the remaining connections
|
|
151
|
-
if (connections.length === 0) {
|
|
152
|
-
this.connectionPool.delete(host);
|
|
153
|
-
} else {
|
|
154
|
-
this.connectionPool.set(host, connections);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Close all connections in the pool
|
|
161
|
-
*/
|
|
162
|
-
public closeAllConnections(): void {
|
|
163
|
-
for (const [host, connections] of this.connectionPool.entries()) {
|
|
164
|
-
this.logger.debug(`Closing ${connections.length} connections to ${host}`);
|
|
165
|
-
|
|
166
|
-
for (const connection of connections) {
|
|
167
|
-
cleanupSocket(connection.socket, `pool-${host}-close`, { immediate: true }).catch(() => {});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.connectionPool.clear();
|
|
172
|
-
this.roundRobinPositions.clear();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Get load balancing target using round-robin
|
|
177
|
-
*/
|
|
178
|
-
public getNextTarget(targets: string[], port: number): { host: string, port: number } {
|
|
179
|
-
const targetKey = targets.join(',');
|
|
180
|
-
|
|
181
|
-
// Initialize position if not exists
|
|
182
|
-
if (!this.roundRobinPositions.has(targetKey)) {
|
|
183
|
-
this.roundRobinPositions.set(targetKey, 0);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Get current position and increment for next time
|
|
187
|
-
const currentPosition = this.roundRobinPositions.get(targetKey)!;
|
|
188
|
-
const nextPosition = (currentPosition + 1) % targets.length;
|
|
189
|
-
this.roundRobinPositions.set(targetKey, nextPosition);
|
|
190
|
-
|
|
191
|
-
// Return the selected target
|
|
192
|
-
return {
|
|
193
|
-
host: targets[currentPosition],
|
|
194
|
-
port
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Gets the connection pool status
|
|
200
|
-
*/
|
|
201
|
-
public getPoolStatus(): Record<string, { total: number, idle: number }> {
|
|
202
|
-
return Object.fromEntries(
|
|
203
|
-
Array.from(this.connectionPool.entries()).map(([host, connections]) => [
|
|
204
|
-
host,
|
|
205
|
-
{
|
|
206
|
-
total: connections.length,
|
|
207
|
-
idle: connections.filter(c => c.isIdle).length
|
|
208
|
-
}
|
|
209
|
-
])
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Setup a periodic cleanup task
|
|
215
|
-
*/
|
|
216
|
-
public setupPeriodicCleanup(interval: number = 60000): NodeJS.Timeout {
|
|
217
|
-
const timer = setInterval(() => {
|
|
218
|
-
this.cleanupConnectionPool();
|
|
219
|
-
}, interval);
|
|
220
|
-
|
|
221
|
-
// Don't prevent process exit
|
|
222
|
-
if (timer.unref) {
|
|
223
|
-
timer.unref();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return timer;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import '../../core/models/socket-augmentation.js';
|
|
3
|
-
import type { IRouteContext, IHttpRouteContext, IHttp2RouteContext } from '../../core/models/route-context.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Context creator for NetworkProxy
|
|
7
|
-
* Creates route contexts for matching and function evaluation
|
|
8
|
-
*/
|
|
9
|
-
export class ContextCreator {
|
|
10
|
-
/**
|
|
11
|
-
* Create a route context from HTTP request information
|
|
12
|
-
*/
|
|
13
|
-
public createHttpRouteContext(req: any, options: {
|
|
14
|
-
tlsVersion?: string;
|
|
15
|
-
connectionId: string;
|
|
16
|
-
clientIp: string;
|
|
17
|
-
serverIp: string;
|
|
18
|
-
}): IHttpRouteContext {
|
|
19
|
-
// Parse headers
|
|
20
|
-
const headers: Record<string, string> = {};
|
|
21
|
-
for (const [key, value] of Object.entries(req.headers)) {
|
|
22
|
-
if (typeof value === 'string') {
|
|
23
|
-
headers[key.toLowerCase()] = value;
|
|
24
|
-
} else if (Array.isArray(value) && value.length > 0) {
|
|
25
|
-
headers[key.toLowerCase()] = value[0];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Parse domain from Host header
|
|
30
|
-
const domain = headers['host']?.split(':')[0] || '';
|
|
31
|
-
|
|
32
|
-
// Parse URL
|
|
33
|
-
const url = new URL(`http://${domain}${req.url || '/'}`);
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
// Connection basics
|
|
37
|
-
port: req.socket.localPort || 0,
|
|
38
|
-
domain,
|
|
39
|
-
clientIp: options.clientIp,
|
|
40
|
-
serverIp: options.serverIp,
|
|
41
|
-
|
|
42
|
-
// HTTP specifics
|
|
43
|
-
path: url.pathname,
|
|
44
|
-
query: url.search ? url.search.substring(1) : '',
|
|
45
|
-
headers,
|
|
46
|
-
|
|
47
|
-
// TLS information
|
|
48
|
-
isTls: !!req.socket.encrypted,
|
|
49
|
-
tlsVersion: options.tlsVersion,
|
|
50
|
-
|
|
51
|
-
// Request objects
|
|
52
|
-
req,
|
|
53
|
-
|
|
54
|
-
// Metadata
|
|
55
|
-
timestamp: Date.now(),
|
|
56
|
-
connectionId: options.connectionId
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Create a route context from HTTP/2 stream and headers
|
|
62
|
-
*/
|
|
63
|
-
public createHttp2RouteContext(
|
|
64
|
-
stream: plugins.http2.ServerHttp2Stream,
|
|
65
|
-
headers: plugins.http2.IncomingHttpHeaders,
|
|
66
|
-
options: {
|
|
67
|
-
connectionId: string;
|
|
68
|
-
clientIp: string;
|
|
69
|
-
serverIp: string;
|
|
70
|
-
}
|
|
71
|
-
): IHttp2RouteContext {
|
|
72
|
-
// Parse headers, excluding HTTP/2 pseudo-headers
|
|
73
|
-
const processedHeaders: Record<string, string> = {};
|
|
74
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
75
|
-
if (!key.startsWith(':') && typeof value === 'string') {
|
|
76
|
-
processedHeaders[key.toLowerCase()] = value;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Get domain from :authority pseudo-header
|
|
81
|
-
const authority = headers[':authority'] as string || '';
|
|
82
|
-
const domain = authority.split(':')[0];
|
|
83
|
-
|
|
84
|
-
// Get path from :path pseudo-header
|
|
85
|
-
const path = headers[':path'] as string || '/';
|
|
86
|
-
|
|
87
|
-
// Parse the path to extract query string
|
|
88
|
-
const pathParts = path.split('?');
|
|
89
|
-
const pathname = pathParts[0];
|
|
90
|
-
const query = pathParts.length > 1 ? pathParts[1] : '';
|
|
91
|
-
|
|
92
|
-
// Get the socket from the session
|
|
93
|
-
const socket = (stream.session as any)?.socket;
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
// Connection basics
|
|
97
|
-
port: socket?.localPort || 0,
|
|
98
|
-
domain,
|
|
99
|
-
clientIp: options.clientIp,
|
|
100
|
-
serverIp: options.serverIp,
|
|
101
|
-
|
|
102
|
-
// HTTP specifics
|
|
103
|
-
path: pathname,
|
|
104
|
-
query,
|
|
105
|
-
headers: processedHeaders,
|
|
106
|
-
|
|
107
|
-
// HTTP/2 specific properties
|
|
108
|
-
method: headers[':method'] as string,
|
|
109
|
-
stream,
|
|
110
|
-
|
|
111
|
-
// TLS information - HTTP/2 is always on TLS in browsers
|
|
112
|
-
isTls: true,
|
|
113
|
-
tlsVersion: socket?.getTLSVersion?.() || 'TLSv1.3',
|
|
114
|
-
|
|
115
|
-
// Metadata
|
|
116
|
-
timestamp: Date.now(),
|
|
117
|
-
connectionId: options.connectionId
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Create a basic route context from socket information
|
|
123
|
-
*/
|
|
124
|
-
public createSocketRouteContext(socket: plugins.net.Socket, options: {
|
|
125
|
-
domain?: string;
|
|
126
|
-
tlsVersion?: string;
|
|
127
|
-
connectionId: string;
|
|
128
|
-
}): IRouteContext {
|
|
129
|
-
return {
|
|
130
|
-
// Connection basics
|
|
131
|
-
port: socket.localPort || 0,
|
|
132
|
-
domain: options.domain,
|
|
133
|
-
clientIp: socket.remoteAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
134
|
-
serverIp: socket.localAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
135
|
-
|
|
136
|
-
// TLS information
|
|
137
|
-
isTls: options.tlsVersion !== undefined,
|
|
138
|
-
tlsVersion: options.tlsVersion,
|
|
139
|
-
|
|
140
|
-
// Metadata
|
|
141
|
-
timestamp: Date.now(),
|
|
142
|
-
connectionId: options.connectionId
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|