@push.rocks/smartproxy 22.6.0 → 23.1.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 +18 -0
- package/dist_rust/{rustproxy → rustproxy_linux_amd64} +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +0 -1
- package/dist_ts/index.js +1 -3
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/proxies/index.d.ts +0 -1
- package/dist_ts/proxies/index.js +1 -3
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +9 -21
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +83 -212
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +2 -3
- package/npmextra.json +3 -0
- package/package.json +13 -11
- package/readme.md +35 -31
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +0 -3
- package/ts/plugins.ts +2 -0
- package/ts/proxies/index.ts +0 -3
- package/ts/proxies/smart-proxy/models/route-types.ts +0 -2
- package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +102 -233
- package/ts/proxies/smart-proxy/smart-proxy.ts +1 -2
- package/dist_ts/common/eventUtils.d.ts +0 -14
- package/dist_ts/common/eventUtils.js +0 -20
- package/dist_ts/common/types.d.ts +0 -82
- package/dist_ts/common/types.js +0 -15
- package/dist_ts/core/utils/event-system.d.ts +0 -200
- package/dist_ts/core/utils/event-system.js +0 -224
- package/dist_ts/core/utils/event-utils.d.ts +0 -15
- package/dist_ts/core/utils/event-utils.js +0 -11
- package/dist_ts/core/utils/route-manager.d.ts +0 -88
- package/dist_ts/core/utils/route-manager.js +0 -342
- package/dist_ts/core/utils/route-utils.d.ts +0 -28
- package/dist_ts/core/utils/route-utils.js +0 -67
- package/dist_ts/detection/detectors/http-detector-v2.d.ts +0 -33
- package/dist_ts/detection/detectors/http-detector-v2.js +0 -87
- package/dist_ts/detection/detectors/tls-detector-v2.d.ts +0 -33
- package/dist_ts/detection/detectors/tls-detector-v2.js +0 -80
- package/dist_ts/detection/protocol-detector-v2.d.ts +0 -46
- package/dist_ts/detection/protocol-detector-v2.js +0 -116
- package/dist_ts/forwarding/config/forwarding-types.d.ts +0 -42
- package/dist_ts/forwarding/config/forwarding-types.js +0 -18
- package/dist_ts/forwarding/config/index.d.ts +0 -9
- package/dist_ts/forwarding/config/index.js +0 -10
- package/dist_ts/forwarding/factory/forwarding-factory.d.ts +0 -25
- package/dist_ts/forwarding/factory/forwarding-factory.js +0 -172
- package/dist_ts/forwarding/factory/index.d.ts +0 -4
- package/dist_ts/forwarding/factory/index.js +0 -5
- package/dist_ts/forwarding/handlers/base-handler.d.ts +0 -62
- package/dist_ts/forwarding/handlers/base-handler.js +0 -121
- package/dist_ts/forwarding/handlers/http-handler.d.ts +0 -30
- package/dist_ts/forwarding/handlers/http-handler.js +0 -143
- package/dist_ts/forwarding/handlers/https-passthrough-handler.d.ts +0 -29
- package/dist_ts/forwarding/handlers/https-passthrough-handler.js +0 -156
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.d.ts +0 -36
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +0 -276
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.d.ts +0 -35
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +0 -261
- package/dist_ts/forwarding/handlers/index.d.ts +0 -8
- package/dist_ts/forwarding/handlers/index.js +0 -9
- package/dist_ts/forwarding/index.d.ts +0 -13
- package/dist_ts/forwarding/index.js +0 -16
- package/dist_ts/http/index.d.ts +0 -5
- package/dist_ts/http/index.js +0 -8
- package/dist_ts/http/models/http-types.d.ts +0 -6
- package/dist_ts/http/models/http-types.js +0 -7
- package/dist_ts/http/router/index.d.ts +0 -8
- package/dist_ts/http/router/index.js +0 -7
- package/dist_ts/http/router/proxy-router.d.ts +0 -115
- package/dist_ts/http/router/proxy-router.js +0 -325
- package/dist_ts/http/router/route-router.d.ts +0 -108
- package/dist_ts/http/router/route-router.js +0 -393
- package/dist_ts/protocols/tls/constants.d.ts +0 -122
- package/dist_ts/protocols/tls/constants.js +0 -135
- package/dist_ts/protocols/tls/parser.d.ts +0 -53
- package/dist_ts/protocols/tls/parser.js +0 -294
- package/dist_ts/protocols/tls/types.d.ts +0 -65
- package/dist_ts/protocols/tls/types.js +0 -5
- package/dist_ts/proxies/http-proxy/certificate-manager.d.ts +0 -95
- package/dist_ts/proxies/http-proxy/certificate-manager.js +0 -214
- package/dist_ts/proxies/http-proxy/connection-pool.d.ts +0 -47
- package/dist_ts/proxies/http-proxy/connection-pool.js +0 -195
- package/dist_ts/proxies/http-proxy/context-creator.d.ts +0 -34
- package/dist_ts/proxies/http-proxy/context-creator.js +0 -108
- package/dist_ts/proxies/http-proxy/default-certificates.d.ts +0 -54
- package/dist_ts/proxies/http-proxy/default-certificates.js +0 -127
- package/dist_ts/proxies/http-proxy/function-cache.d.ts +0 -95
- package/dist_ts/proxies/http-proxy/function-cache.js +0 -215
- package/dist_ts/proxies/http-proxy/handlers/index.d.ts +0 -4
- package/dist_ts/proxies/http-proxy/handlers/index.js +0 -6
- package/dist_ts/proxies/http-proxy/handlers/redirect-handler.d.ts +0 -18
- package/dist_ts/proxies/http-proxy/handlers/redirect-handler.js +0 -78
- package/dist_ts/proxies/http-proxy/handlers/static-handler.d.ts +0 -19
- package/dist_ts/proxies/http-proxy/handlers/static-handler.js +0 -211
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -117
- package/dist_ts/proxies/http-proxy/http-proxy.js +0 -521
- package/dist_ts/proxies/http-proxy/http-request-handler.d.ts +0 -40
- package/dist_ts/proxies/http-proxy/http-request-handler.js +0 -257
- package/dist_ts/proxies/http-proxy/http2-request-handler.d.ts +0 -24
- package/dist_ts/proxies/http-proxy/http2-request-handler.js +0 -201
- package/dist_ts/proxies/http-proxy/index.d.ts +0 -14
- package/dist_ts/proxies/http-proxy/index.js +0 -16
- package/dist_ts/proxies/http-proxy/models/http-types.d.ts +0 -117
- package/dist_ts/proxies/http-proxy/models/http-types.js +0 -92
- package/dist_ts/proxies/http-proxy/models/index.d.ts +0 -5
- package/dist_ts/proxies/http-proxy/models/index.js +0 -6
- package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -75
- package/dist_ts/proxies/http-proxy/models/types.js +0 -35
- package/dist_ts/proxies/http-proxy/request-handler.d.ts +0 -97
- package/dist_ts/proxies/http-proxy/request-handler.js +0 -737
- package/dist_ts/proxies/http-proxy/security-manager.d.ts +0 -98
- package/dist_ts/proxies/http-proxy/security-manager.js +0 -341
- package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +0 -50
- package/dist_ts/proxies/http-proxy/websocket-handler.js +0 -505
- package/dist_ts/proxies/nftables-proxy/index.d.ts +0 -6
- package/dist_ts/proxies/nftables-proxy/index.js +0 -7
- package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +0 -15
- package/dist_ts/proxies/nftables-proxy/models/errors.js +0 -28
- package/dist_ts/proxies/nftables-proxy/models/index.d.ts +0 -5
- package/dist_ts/proxies/nftables-proxy/models/index.js +0 -6
- package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +0 -75
- package/dist_ts/proxies/nftables-proxy/models/interfaces.js +0 -5
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +0 -124
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +0 -1374
- package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +0 -9
- package/dist_ts/proxies/nftables-proxy/utils/index.js +0 -12
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +0 -66
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +0 -131
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +0 -39
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +0 -112
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +0 -59
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +0 -130
- package/dist_ts/proxies/smart-proxy/acme-state-manager.d.ts +0 -42
- package/dist_ts/proxies/smart-proxy/acme-state-manager.js +0 -101
- package/dist_ts/proxies/smart-proxy/cert-store.d.ts +0 -10
- package/dist_ts/proxies/smart-proxy/cert-store.js +0 -72
- package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +0 -164
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +0 -745
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +0 -128
- package/dist_ts/proxies/smart-proxy/connection-manager.js +0 -689
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +0 -43
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +0 -180
- package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +0 -98
- package/dist_ts/proxies/smart-proxy/metrics-collector.js +0 -355
- package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +0 -82
- package/dist_ts/proxies/smart-proxy/nftables-manager.js +0 -237
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +0 -117
- package/dist_ts/proxies/smart-proxy/port-manager.js +0 -318
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +0 -60
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +0 -1407
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +0 -112
- package/dist_ts/proxies/smart-proxy/route-manager.js +0 -453
- package/dist_ts/proxies/smart-proxy/route-orchestrator.d.ts +0 -56
- package/dist_ts/proxies/smart-proxy/route-orchestrator.js +0 -204
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +0 -23
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +0 -104
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +0 -74
- package/dist_ts/proxies/smart-proxy/security-manager.js +0 -227
- package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +0 -36
- package/dist_ts/proxies/smart-proxy/throughput-tracker.js +0 -115
- package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +0 -48
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +0 -158
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +0 -50
- package/dist_ts/proxies/smart-proxy/tls-manager.js +0 -110
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +0 -161
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +0 -282
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +0 -73
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +0 -259
- package/dist_ts/routing/router/proxy-router.d.ts +0 -115
- package/dist_ts/routing/router/proxy-router.js +0 -325
- package/dist_ts/routing/router/route-router.d.ts +0 -108
- package/dist_ts/routing/router/route-router.js +0 -393
- package/dist_ts/tls/alerts/index.d.ts +0 -4
- package/dist_ts/tls/alerts/index.js +0 -5
- package/dist_ts/tls/alerts/tls-alert.d.ts +0 -150
- package/dist_ts/tls/alerts/tls-alert.js +0 -226
- package/dist_ts/tls/sni/client-hello-parser.d.ts +0 -100
- package/dist_ts/tls/sni/client-hello-parser.js +0 -464
- package/dist_ts/tls/sni/sni-extraction.d.ts +0 -58
- package/dist_ts/tls/sni/sni-extraction.js +0 -275
- package/dist_ts/tls/utils/index.d.ts +0 -4
- package/dist_ts/tls/utils/index.js +0 -5
- package/dist_ts/tls/utils/tls-utils.d.ts +0 -49
- package/dist_ts/tls/utils/tls-utils.js +0 -75
- package/ts/proxies/nftables-proxy/index.ts +0 -6
- package/ts/proxies/nftables-proxy/models/errors.ts +0 -30
- package/ts/proxies/nftables-proxy/models/index.ts +0 -5
- package/ts/proxies/nftables-proxy/models/interfaces.ts +0 -94
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +0 -1754
- package/ts/proxies/nftables-proxy/utils/index.ts +0 -38
- package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +0 -162
- package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +0 -125
- package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +0 -156
- package/ts/proxies/smart-proxy/rust-binary-locator.ts +0 -112
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Tracks throughput data using time-series sampling
|
|
4
|
-
*/
|
|
5
|
-
export declare class ThroughputTracker {
|
|
6
|
-
private samples;
|
|
7
|
-
private readonly maxSamples;
|
|
8
|
-
private accumulatedBytesIn;
|
|
9
|
-
private accumulatedBytesOut;
|
|
10
|
-
private lastSampleTime;
|
|
11
|
-
constructor(retentionSeconds?: number);
|
|
12
|
-
/**
|
|
13
|
-
* Record bytes transferred (called on every data transfer)
|
|
14
|
-
*/
|
|
15
|
-
recordBytes(bytesIn: number, bytesOut: number): void;
|
|
16
|
-
/**
|
|
17
|
-
* Take a sample of accumulated bytes (called every second)
|
|
18
|
-
*/
|
|
19
|
-
takeSample(): void;
|
|
20
|
-
/**
|
|
21
|
-
* Get throughput rate over specified window (bytes per second)
|
|
22
|
-
*/
|
|
23
|
-
getRate(windowSeconds: number): IThroughputData;
|
|
24
|
-
/**
|
|
25
|
-
* Get throughput history for specified duration
|
|
26
|
-
*/
|
|
27
|
-
getHistory(durationSeconds: number): IThroughputHistoryPoint[];
|
|
28
|
-
/**
|
|
29
|
-
* Clear all samples
|
|
30
|
-
*/
|
|
31
|
-
clear(): void;
|
|
32
|
-
/**
|
|
33
|
-
* Get sample count for debugging
|
|
34
|
-
*/
|
|
35
|
-
getSampleCount(): number;
|
|
36
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tracks throughput data using time-series sampling
|
|
3
|
-
*/
|
|
4
|
-
export class ThroughputTracker {
|
|
5
|
-
constructor(retentionSeconds = 3600) {
|
|
6
|
-
this.samples = [];
|
|
7
|
-
this.accumulatedBytesIn = 0;
|
|
8
|
-
this.accumulatedBytesOut = 0;
|
|
9
|
-
this.lastSampleTime = 0;
|
|
10
|
-
// Keep samples for the retention period at 1 sample per second
|
|
11
|
-
this.maxSamples = retentionSeconds;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Record bytes transferred (called on every data transfer)
|
|
15
|
-
*/
|
|
16
|
-
recordBytes(bytesIn, bytesOut) {
|
|
17
|
-
this.accumulatedBytesIn += bytesIn;
|
|
18
|
-
this.accumulatedBytesOut += bytesOut;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Take a sample of accumulated bytes (called every second)
|
|
22
|
-
*/
|
|
23
|
-
takeSample() {
|
|
24
|
-
const now = Date.now();
|
|
25
|
-
// Record accumulated bytes since last sample
|
|
26
|
-
this.samples.push({
|
|
27
|
-
timestamp: now,
|
|
28
|
-
bytesIn: this.accumulatedBytesIn,
|
|
29
|
-
bytesOut: this.accumulatedBytesOut
|
|
30
|
-
});
|
|
31
|
-
// Reset accumulators
|
|
32
|
-
this.accumulatedBytesIn = 0;
|
|
33
|
-
this.accumulatedBytesOut = 0;
|
|
34
|
-
this.lastSampleTime = now;
|
|
35
|
-
// Maintain circular buffer - remove oldest samples
|
|
36
|
-
if (this.samples.length > this.maxSamples) {
|
|
37
|
-
this.samples.shift();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Get throughput rate over specified window (bytes per second)
|
|
42
|
-
*/
|
|
43
|
-
getRate(windowSeconds) {
|
|
44
|
-
if (this.samples.length === 0) {
|
|
45
|
-
return { in: 0, out: 0 };
|
|
46
|
-
}
|
|
47
|
-
const now = Date.now();
|
|
48
|
-
const windowStart = now - (windowSeconds * 1000);
|
|
49
|
-
// Find samples within the window
|
|
50
|
-
const relevantSamples = this.samples.filter(s => s.timestamp > windowStart);
|
|
51
|
-
if (relevantSamples.length === 0) {
|
|
52
|
-
return { in: 0, out: 0 };
|
|
53
|
-
}
|
|
54
|
-
// Calculate total bytes in window
|
|
55
|
-
const totalBytesIn = relevantSamples.reduce((sum, s) => sum + s.bytesIn, 0);
|
|
56
|
-
const totalBytesOut = relevantSamples.reduce((sum, s) => sum + s.bytesOut, 0);
|
|
57
|
-
// Use actual number of seconds covered by samples for accurate rate
|
|
58
|
-
const oldestSampleTime = relevantSamples[0].timestamp;
|
|
59
|
-
const newestSampleTime = relevantSamples[relevantSamples.length - 1].timestamp;
|
|
60
|
-
const actualSeconds = Math.max(1, (newestSampleTime - oldestSampleTime) / 1000 + 1);
|
|
61
|
-
return {
|
|
62
|
-
in: Math.round(totalBytesIn / actualSeconds),
|
|
63
|
-
out: Math.round(totalBytesOut / actualSeconds)
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Get throughput history for specified duration
|
|
68
|
-
*/
|
|
69
|
-
getHistory(durationSeconds) {
|
|
70
|
-
const now = Date.now();
|
|
71
|
-
const startTime = now - (durationSeconds * 1000);
|
|
72
|
-
// Filter samples within duration
|
|
73
|
-
const relevantSamples = this.samples.filter(s => s.timestamp > startTime);
|
|
74
|
-
// Convert to history points with per-second rates
|
|
75
|
-
const history = [];
|
|
76
|
-
for (let i = 0; i < relevantSamples.length; i++) {
|
|
77
|
-
const sample = relevantSamples[i];
|
|
78
|
-
// For the first sample or samples after gaps, we can't calculate rate
|
|
79
|
-
if (i === 0 || sample.timestamp - relevantSamples[i - 1].timestamp > 2000) {
|
|
80
|
-
history.push({
|
|
81
|
-
timestamp: sample.timestamp,
|
|
82
|
-
in: sample.bytesIn,
|
|
83
|
-
out: sample.bytesOut
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
// Calculate rate based on time since previous sample
|
|
88
|
-
const prevSample = relevantSamples[i - 1];
|
|
89
|
-
const timeDelta = (sample.timestamp - prevSample.timestamp) / 1000;
|
|
90
|
-
history.push({
|
|
91
|
-
timestamp: sample.timestamp,
|
|
92
|
-
in: Math.round(sample.bytesIn / timeDelta),
|
|
93
|
-
out: Math.round(sample.bytesOut / timeDelta)
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return history;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Clear all samples
|
|
101
|
-
*/
|
|
102
|
-
clear() {
|
|
103
|
-
this.samples = [];
|
|
104
|
-
this.accumulatedBytesIn = 0;
|
|
105
|
-
this.accumulatedBytesOut = 0;
|
|
106
|
-
this.lastSampleTime = 0;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Get sample count for debugging
|
|
110
|
-
*/
|
|
111
|
-
getSampleCount() {
|
|
112
|
-
return this.samples.length;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyb3VnaHB1dC10cmFja2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS90aHJvdWdocHV0LXRyYWNrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7O0dBRUc7QUFDSCxNQUFNLE9BQU8saUJBQWlCO0lBTzVCLFlBQVksbUJBQTJCLElBQUk7UUFObkMsWUFBTyxHQUF3QixFQUFFLENBQUM7UUFFbEMsdUJBQWtCLEdBQVcsQ0FBQyxDQUFDO1FBQy9CLHdCQUFtQixHQUFXLENBQUMsQ0FBQztRQUNoQyxtQkFBYyxHQUFXLENBQUMsQ0FBQztRQUdqQywrREFBK0Q7UUFDL0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQztJQUNyQyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxXQUFXLENBQUMsT0FBZSxFQUFFLFFBQWdCO1FBQ2xELElBQUksQ0FBQyxrQkFBa0IsSUFBSSxPQUFPLENBQUM7UUFDbkMsSUFBSSxDQUFDLG1CQUFtQixJQUFJLFFBQVEsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxVQUFVO1FBQ2YsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRXZCLDZDQUE2QztRQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztZQUNoQixTQUFTLEVBQUUsR0FBRztZQUNkLE9BQU8sRUFBRSxJQUFJLENBQUMsa0JBQWtCO1lBQ2hDLFFBQVEsRUFBRSxJQUFJLENBQUMsbUJBQW1CO1NBQ25DLENBQUMsQ0FBQztRQUVILHFCQUFxQjtRQUNyQixJQUFJLENBQUMsa0JBQWtCLEdBQUcsQ0FBQyxDQUFDO1FBQzVCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxHQUFHLENBQUM7UUFFMUIsbURBQW1EO1FBQ25ELElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdB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
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { IConnectionRecord } from './models/interfaces.js';
|
|
2
|
-
import type { SmartProxy } from './smart-proxy.js';
|
|
3
|
-
/**
|
|
4
|
-
* Manages timeouts and inactivity tracking for connections
|
|
5
|
-
*/
|
|
6
|
-
export declare class TimeoutManager {
|
|
7
|
-
private smartProxy;
|
|
8
|
-
constructor(smartProxy: SmartProxy);
|
|
9
|
-
/**
|
|
10
|
-
* Ensure timeout values don't exceed Node.js max safe integer
|
|
11
|
-
*/
|
|
12
|
-
ensureSafeTimeout(timeout: number): number;
|
|
13
|
-
/**
|
|
14
|
-
* Generate a slightly randomized timeout to prevent thundering herd
|
|
15
|
-
*/
|
|
16
|
-
randomizeTimeout(baseTimeout: number, variationPercent?: number): number;
|
|
17
|
-
/**
|
|
18
|
-
* Update connection activity timestamp
|
|
19
|
-
*/
|
|
20
|
-
updateActivity(record: IConnectionRecord): void;
|
|
21
|
-
/**
|
|
22
|
-
* Calculate effective inactivity timeout based on connection type
|
|
23
|
-
*/
|
|
24
|
-
getEffectiveInactivityTimeout(record: IConnectionRecord): number;
|
|
25
|
-
/**
|
|
26
|
-
* Calculate effective max lifetime based on connection type
|
|
27
|
-
*/
|
|
28
|
-
getEffectiveMaxLifetime(record: IConnectionRecord): number;
|
|
29
|
-
/**
|
|
30
|
-
* Setup connection timeout
|
|
31
|
-
* @returns The cleanup timer
|
|
32
|
-
*/
|
|
33
|
-
setupConnectionTimeout(record: IConnectionRecord, onTimeout: (record: IConnectionRecord, reason: string) => void): NodeJS.Timeout | null;
|
|
34
|
-
/**
|
|
35
|
-
* Check for inactivity on a connection
|
|
36
|
-
* @returns Object with check results
|
|
37
|
-
*/
|
|
38
|
-
checkInactivity(record: IConnectionRecord): {
|
|
39
|
-
isInactive: boolean;
|
|
40
|
-
shouldWarn: boolean;
|
|
41
|
-
inactivityTime: number;
|
|
42
|
-
effectiveTimeout: number;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Apply socket timeout settings
|
|
46
|
-
*/
|
|
47
|
-
applySocketTimeouts(record: IConnectionRecord): void;
|
|
48
|
-
}
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Manages timeouts and inactivity tracking for connections
|
|
3
|
-
*/
|
|
4
|
-
export class TimeoutManager {
|
|
5
|
-
constructor(smartProxy) {
|
|
6
|
-
this.smartProxy = smartProxy;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Ensure timeout values don't exceed Node.js max safe integer
|
|
10
|
-
*/
|
|
11
|
-
ensureSafeTimeout(timeout) {
|
|
12
|
-
const MAX_SAFE_TIMEOUT = 2147483647; // Maximum safe value (2^31 - 1)
|
|
13
|
-
return Math.min(Math.floor(timeout), MAX_SAFE_TIMEOUT);
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Generate a slightly randomized timeout to prevent thundering herd
|
|
17
|
-
*/
|
|
18
|
-
randomizeTimeout(baseTimeout, variationPercent = 5) {
|
|
19
|
-
const safeBaseTimeout = this.ensureSafeTimeout(baseTimeout);
|
|
20
|
-
const variation = safeBaseTimeout * (variationPercent / 100);
|
|
21
|
-
return this.ensureSafeTimeout(safeBaseTimeout + Math.floor(Math.random() * variation * 2) - variation);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Update connection activity timestamp
|
|
25
|
-
*/
|
|
26
|
-
updateActivity(record) {
|
|
27
|
-
record.lastActivity = Date.now();
|
|
28
|
-
// Clear any inactivity warning
|
|
29
|
-
if (record.inactivityWarningIssued) {
|
|
30
|
-
record.inactivityWarningIssued = false;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Calculate effective inactivity timeout based on connection type
|
|
35
|
-
*/
|
|
36
|
-
getEffectiveInactivityTimeout(record) {
|
|
37
|
-
let effectiveTimeout = this.smartProxy.settings.inactivityTimeout || 14400000; // 4 hours default
|
|
38
|
-
// For immortal keep-alive connections, use an extremely long timeout
|
|
39
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
40
|
-
return Number.MAX_SAFE_INTEGER;
|
|
41
|
-
}
|
|
42
|
-
// For extended keep-alive connections, apply multiplier
|
|
43
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'extended') {
|
|
44
|
-
const multiplier = this.smartProxy.settings.keepAliveInactivityMultiplier || 6;
|
|
45
|
-
effectiveTimeout = effectiveTimeout * multiplier;
|
|
46
|
-
}
|
|
47
|
-
return this.ensureSafeTimeout(effectiveTimeout);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Calculate effective max lifetime based on connection type
|
|
51
|
-
*/
|
|
52
|
-
getEffectiveMaxLifetime(record) {
|
|
53
|
-
// Use route-specific timeout if available from the routeConfig
|
|
54
|
-
const baseTimeout = record.routeConfig?.action.advanced?.timeout ||
|
|
55
|
-
this.smartProxy.settings.maxConnectionLifetime ||
|
|
56
|
-
86400000; // 24 hours default
|
|
57
|
-
// For immortal keep-alive connections, use an extremely long lifetime
|
|
58
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
59
|
-
return Number.MAX_SAFE_INTEGER;
|
|
60
|
-
}
|
|
61
|
-
// For extended keep-alive connections, use the extended lifetime setting
|
|
62
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'extended') {
|
|
63
|
-
return this.ensureSafeTimeout(this.smartProxy.settings.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000 // 7 days default
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
// Apply randomization if enabled
|
|
67
|
-
if (this.smartProxy.settings.enableRandomizedTimeouts) {
|
|
68
|
-
return this.randomizeTimeout(baseTimeout);
|
|
69
|
-
}
|
|
70
|
-
return this.ensureSafeTimeout(baseTimeout);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Setup connection timeout
|
|
74
|
-
* @returns The cleanup timer
|
|
75
|
-
*/
|
|
76
|
-
setupConnectionTimeout(record, onTimeout) {
|
|
77
|
-
// Clear any existing timer
|
|
78
|
-
if (record.cleanupTimer) {
|
|
79
|
-
clearTimeout(record.cleanupTimer);
|
|
80
|
-
}
|
|
81
|
-
// Skip timeout for immortal keep-alive connections
|
|
82
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
// Calculate effective timeout
|
|
86
|
-
const effectiveLifetime = this.getEffectiveMaxLifetime(record);
|
|
87
|
-
// Set up the timeout
|
|
88
|
-
const timer = setTimeout(() => {
|
|
89
|
-
// Call the provided callback
|
|
90
|
-
onTimeout(record, 'connection_timeout');
|
|
91
|
-
}, effectiveLifetime);
|
|
92
|
-
// Make sure timeout doesn't keep the process alive
|
|
93
|
-
if (timer.unref) {
|
|
94
|
-
timer.unref();
|
|
95
|
-
}
|
|
96
|
-
return timer;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Check for inactivity on a connection
|
|
100
|
-
* @returns Object with check results
|
|
101
|
-
*/
|
|
102
|
-
checkInactivity(record) {
|
|
103
|
-
// Skip for connections with inactivity check disabled
|
|
104
|
-
if (this.smartProxy.settings.disableInactivityCheck) {
|
|
105
|
-
return {
|
|
106
|
-
isInactive: false,
|
|
107
|
-
shouldWarn: false,
|
|
108
|
-
inactivityTime: 0,
|
|
109
|
-
effectiveTimeout: 0
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// Skip for immortal keep-alive connections
|
|
113
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
114
|
-
return {
|
|
115
|
-
isInactive: false,
|
|
116
|
-
shouldWarn: false,
|
|
117
|
-
inactivityTime: 0,
|
|
118
|
-
effectiveTimeout: 0
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
const now = Date.now();
|
|
122
|
-
const inactivityTime = now - record.lastActivity;
|
|
123
|
-
const effectiveTimeout = this.getEffectiveInactivityTimeout(record);
|
|
124
|
-
// Check if inactive
|
|
125
|
-
const isInactive = inactivityTime > effectiveTimeout;
|
|
126
|
-
// For keep-alive connections, we should warn first
|
|
127
|
-
const shouldWarn = record.hasKeepAlive &&
|
|
128
|
-
isInactive &&
|
|
129
|
-
!record.inactivityWarningIssued;
|
|
130
|
-
return {
|
|
131
|
-
isInactive,
|
|
132
|
-
shouldWarn,
|
|
133
|
-
inactivityTime,
|
|
134
|
-
effectiveTimeout
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Apply socket timeout settings
|
|
139
|
-
*/
|
|
140
|
-
applySocketTimeouts(record) {
|
|
141
|
-
// Skip for immortal keep-alive connections
|
|
142
|
-
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
143
|
-
// Disable timeouts completely for immortal connections
|
|
144
|
-
record.incoming.setTimeout(0);
|
|
145
|
-
if (record.outgoing) {
|
|
146
|
-
record.outgoing.setTimeout(0);
|
|
147
|
-
}
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
// Apply normal timeouts
|
|
151
|
-
const timeout = this.ensureSafeTimeout(this.smartProxy.settings.socketTimeout || 3600000); // 1 hour default
|
|
152
|
-
record.incoming.setTimeout(timeout);
|
|
153
|
-
if (record.outgoing) {
|
|
154
|
-
record.outgoing.setTimeout(timeout);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZW91dC1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS90aW1lb3V0LW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0E7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQUN6QixZQUFvQixVQUFzQjtRQUF0QixlQUFVLEdBQVYsVUFBVSxDQUFZO0lBQUcsQ0FBQztJQUU5Qzs7T0FFRztJQUNJLGlCQUFpQixDQUFDLE9BQWU7UUFDdEMsTUFBTSxnQkFBZ0IsR0FBRyxVQUFVLENBQUMsQ0FBQyxnQ0FBZ0M7UUFDckUsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxnQkFBZ0IsQ0FBQyxXQUFtQixFQUFFLG1CQUEyQixDQUFDO1FBQ3ZFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1RCxNQUFNLFNBQVMsR0FBRyxlQUFlLEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRyxHQUFHLENBQUMsQ0FBQztRQUM3RCxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FDM0IsZUFBZSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUMsR0FBRyxTQUFTLENBQ3hFLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxjQUFjLENBQUMsTUFBeUI7UUFDN0MsTUFBTSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFakMsK0JBQStCO1FBQy9CLElBQUksTUFBTSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDbkMsTUFBTSxDQUFDLHVCQUF1QixHQUFHLEtBQUssQ0FBQztRQUN6QyxDQUFDO0lB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
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { SmartProxy } from './smart-proxy.js';
|
|
2
|
-
/**
|
|
3
|
-
* Interface for connection information used for SNI extraction
|
|
4
|
-
*/
|
|
5
|
-
interface IConnectionInfo {
|
|
6
|
-
sourceIp: string;
|
|
7
|
-
sourcePort: number;
|
|
8
|
-
destIp: string;
|
|
9
|
-
destPort: number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Manages TLS-related operations including SNI extraction and validation
|
|
13
|
-
*/
|
|
14
|
-
export declare class TlsManager {
|
|
15
|
-
private smartProxy;
|
|
16
|
-
constructor(smartProxy: SmartProxy);
|
|
17
|
-
/**
|
|
18
|
-
* Check if a data chunk appears to be a TLS handshake
|
|
19
|
-
*/
|
|
20
|
-
isTlsHandshake(chunk: Buffer): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Check if a data chunk appears to be a TLS ClientHello
|
|
23
|
-
*/
|
|
24
|
-
isClientHello(chunk: Buffer): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Extract Server Name Indication (SNI) from TLS handshake
|
|
27
|
-
*/
|
|
28
|
-
extractSNI(chunk: Buffer, connInfo: IConnectionInfo, previousDomain?: string): string | undefined;
|
|
29
|
-
/**
|
|
30
|
-
* Check for SNI mismatch during renegotiation
|
|
31
|
-
*/
|
|
32
|
-
checkRenegotiationSNI(chunk: Buffer, connInfo: IConnectionInfo, expectedDomain: string, connectionId: string): {
|
|
33
|
-
hasMismatch: boolean;
|
|
34
|
-
extractedSNI?: string;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Create a renegotiation handler function for a connection
|
|
38
|
-
*/
|
|
39
|
-
createRenegotiationHandler(connectionId: string, lockedDomain: string, connInfo: IConnectionInfo, onMismatch: (connectionId: string, reason: string) => void): (chunk: Buffer) => void;
|
|
40
|
-
/**
|
|
41
|
-
* Analyze TLS connection for browser fingerprinting
|
|
42
|
-
* This helps identify browser vs non-browser connections
|
|
43
|
-
*/
|
|
44
|
-
analyzeClientHello(chunk: Buffer): {
|
|
45
|
-
isBrowserConnection: boolean;
|
|
46
|
-
isRenewal: boolean;
|
|
47
|
-
hasSNI: boolean;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
export {};
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import { SniHandler } from '../../tls/sni/sni-handler.js';
|
|
3
|
-
import { ProtocolDetector, TlsDetector } from '../../detection/index.js';
|
|
4
|
-
/**
|
|
5
|
-
* Manages TLS-related operations including SNI extraction and validation
|
|
6
|
-
*/
|
|
7
|
-
export class TlsManager {
|
|
8
|
-
constructor(smartProxy) {
|
|
9
|
-
this.smartProxy = smartProxy;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Check if a data chunk appears to be a TLS handshake
|
|
13
|
-
*/
|
|
14
|
-
isTlsHandshake(chunk) {
|
|
15
|
-
return SniHandler.isTlsHandshake(chunk);
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Check if a data chunk appears to be a TLS ClientHello
|
|
19
|
-
*/
|
|
20
|
-
isClientHello(chunk) {
|
|
21
|
-
return SniHandler.isClientHello(chunk);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Extract Server Name Indication (SNI) from TLS handshake
|
|
25
|
-
*/
|
|
26
|
-
extractSNI(chunk, connInfo, previousDomain) {
|
|
27
|
-
// Use the SniHandler to process the TLS packet
|
|
28
|
-
return SniHandler.processTlsPacket(chunk, connInfo, this.smartProxy.settings.enableTlsDebugLogging || false, previousDomain);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Check for SNI mismatch during renegotiation
|
|
32
|
-
*/
|
|
33
|
-
checkRenegotiationSNI(chunk, connInfo, expectedDomain, connectionId) {
|
|
34
|
-
// Only process if this looks like a TLS ClientHello
|
|
35
|
-
if (!this.isClientHello(chunk)) {
|
|
36
|
-
return { hasMismatch: false };
|
|
37
|
-
}
|
|
38
|
-
try {
|
|
39
|
-
// Extract SNI with renegotiation support
|
|
40
|
-
const newSNI = SniHandler.extractSNIWithResumptionSupport(chunk, connInfo, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
41
|
-
// Skip if no SNI was found
|
|
42
|
-
if (!newSNI)
|
|
43
|
-
return { hasMismatch: false };
|
|
44
|
-
// Check for SNI mismatch
|
|
45
|
-
if (newSNI !== expectedDomain) {
|
|
46
|
-
if (this.smartProxy.settings.enableTlsDebugLogging) {
|
|
47
|
-
console.log(`[${connectionId}] Renegotiation with different SNI: ${expectedDomain} -> ${newSNI}. ` +
|
|
48
|
-
`Terminating connection - SNI domain switching is not allowed.`);
|
|
49
|
-
}
|
|
50
|
-
return { hasMismatch: true, extractedSNI: newSNI };
|
|
51
|
-
}
|
|
52
|
-
else if (this.smartProxy.settings.enableTlsDebugLogging) {
|
|
53
|
-
console.log(`[${connectionId}] Renegotiation detected with same SNI: ${newSNI}. Allowing.`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
console.log(`[${connectionId}] Error processing ClientHello: ${err}. Allowing connection to continue.`);
|
|
58
|
-
}
|
|
59
|
-
return { hasMismatch: false };
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Create a renegotiation handler function for a connection
|
|
63
|
-
*/
|
|
64
|
-
createRenegotiationHandler(connectionId, lockedDomain, connInfo, onMismatch) {
|
|
65
|
-
return (chunk) => {
|
|
66
|
-
const result = this.checkRenegotiationSNI(chunk, connInfo, lockedDomain, connectionId);
|
|
67
|
-
if (result.hasMismatch) {
|
|
68
|
-
onMismatch(connectionId, 'sni_mismatch');
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Analyze TLS connection for browser fingerprinting
|
|
74
|
-
* This helps identify browser vs non-browser connections
|
|
75
|
-
*/
|
|
76
|
-
analyzeClientHello(chunk) {
|
|
77
|
-
// Default result
|
|
78
|
-
const result = {
|
|
79
|
-
isBrowserConnection: false,
|
|
80
|
-
isRenewal: false,
|
|
81
|
-
hasSNI: false
|
|
82
|
-
};
|
|
83
|
-
try {
|
|
84
|
-
// Check if it's a ClientHello
|
|
85
|
-
if (!this.isClientHello(chunk)) {
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
// Check for session resumption
|
|
89
|
-
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
90
|
-
// Extract SNI
|
|
91
|
-
const sni = SniHandler.extractSNI(chunk, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
92
|
-
// Update result
|
|
93
|
-
result.isRenewal = resumptionInfo.isResumption;
|
|
94
|
-
result.hasSNI = !!sni;
|
|
95
|
-
// Browsers typically:
|
|
96
|
-
// 1. Send SNI extension
|
|
97
|
-
// 2. Have a variety of extensions (ALPN, etc.)
|
|
98
|
-
// 3. Use standard cipher suites
|
|
99
|
-
// ...more complex heuristics could be implemented here
|
|
100
|
-
// Simple heuristic: presence of SNI suggests browser
|
|
101
|
-
result.isBrowserConnection = !!sni;
|
|
102
|
-
return result;
|
|
103
|
-
}
|
|
104
|
-
catch (err) {
|
|
105
|
-
console.log(`Error analyzing ClientHello: ${err}`);
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3Rscy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzFELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQWF6RTs7R0FFRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBQ3JCLFlBQW9CLFVBQXNCO1FBQXRCLGVBQVUsR0FBVixVQUFVLENBQVk7SUFBRyxDQUFDO0lBRTlDOztPQUVHO0lBQ0ksY0FBYyxDQUFDLEtBQWE7UUFDakMsT0FBTyxVQUFVLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRDs7T0FFRztJQUNJLGFBQWEsQ0FBQyxLQUFhO1FBQ2hDLE9BQU8sVUFBVSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxVQUFVLENBQ2YsS0FBYSxFQUNiLFFBQXlCLEVBQ3pCLGNBQXVCO1FBRXZCLCtDQUErQztRQUMvQyxPQUFPLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FDaEMsS0FBSyxFQUNMLFFBQVEsRUFDUixJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsSUFBSSxLQUFLLEVBQ3ZELGNBQWMsQ0FDZixDQUFDO0lBQ0osQ0FBQztJQUVIOztTQUVLO0lBQ0kscUJBQXFCLENBQzFCLEtBQWEsRUFDYixRQUF5QixFQUN6QixjQUFzQixFQUN0QixZQUFvQjtRQUVwQixvREFBb0Q7UUFDcEQsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMvQixPQUFPLEVBQUUsV0FBVyxFQUFFLEtB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
|