nlcurl 0.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/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/cli/args.d.ts +42 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +262 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +114 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +22 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +105 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cookies/jar.d.ts +41 -0
- package/dist/cookies/jar.d.ts.map +1 -0
- package/dist/cookies/jar.js +148 -0
- package/dist/cookies/jar.js.map +1 -0
- package/dist/cookies/parser.d.ts +24 -0
- package/dist/cookies/parser.d.ts.map +1 -0
- package/dist/cookies/parser.js +93 -0
- package/dist/cookies/parser.js.map +1 -0
- package/dist/core/client.d.ts +79 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +106 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/errors.d.ts +36 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +65 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/request.d.ts +96 -0
- package/dist/core/request.d.ts.map +1 -0
- package/dist/core/request.js +5 -0
- package/dist/core/request.js.map +1 -0
- package/dist/core/response.d.ts +48 -0
- package/dist/core/response.d.ts.map +1 -0
- package/dist/core/response.js +65 -0
- package/dist/core/response.js.map +1 -0
- package/dist/core/session.d.ts +60 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +305 -0
- package/dist/core/session.js.map +1 -0
- package/dist/fingerprints/akamai.d.ts +17 -0
- package/dist/fingerprints/akamai.d.ts.map +1 -0
- package/dist/fingerprints/akamai.js +30 -0
- package/dist/fingerprints/akamai.js.map +1 -0
- package/dist/fingerprints/database.d.ts +33 -0
- package/dist/fingerprints/database.d.ts.map +1 -0
- package/dist/fingerprints/database.js +68 -0
- package/dist/fingerprints/database.js.map +1 -0
- package/dist/fingerprints/extensions.d.ts +49 -0
- package/dist/fingerprints/extensions.d.ts.map +1 -0
- package/dist/fingerprints/extensions.js +178 -0
- package/dist/fingerprints/extensions.js.map +1 -0
- package/dist/fingerprints/ja3.d.ts +32 -0
- package/dist/fingerprints/ja3.d.ts.map +1 -0
- package/dist/fingerprints/ja3.js +64 -0
- package/dist/fingerprints/ja3.js.map +1 -0
- package/dist/fingerprints/profiles/chrome.d.ts +30 -0
- package/dist/fingerprints/profiles/chrome.d.ts.map +1 -0
- package/dist/fingerprints/profiles/chrome.js +202 -0
- package/dist/fingerprints/profiles/chrome.js.map +1 -0
- package/dist/fingerprints/profiles/edge.d.ts +16 -0
- package/dist/fingerprints/profiles/edge.d.ts.map +1 -0
- package/dist/fingerprints/profiles/edge.js +61 -0
- package/dist/fingerprints/profiles/edge.js.map +1 -0
- package/dist/fingerprints/profiles/firefox.d.ts +13 -0
- package/dist/fingerprints/profiles/firefox.d.ts.map +1 -0
- package/dist/fingerprints/profiles/firefox.js +160 -0
- package/dist/fingerprints/profiles/firefox.js.map +1 -0
- package/dist/fingerprints/profiles/safari.d.ts +16 -0
- package/dist/fingerprints/profiles/safari.d.ts.map +1 -0
- package/dist/fingerprints/profiles/safari.js +140 -0
- package/dist/fingerprints/profiles/safari.js.map +1 -0
- package/dist/fingerprints/profiles/tor.d.ts +14 -0
- package/dist/fingerprints/profiles/tor.d.ts.map +1 -0
- package/dist/fingerprints/profiles/tor.js +136 -0
- package/dist/fingerprints/profiles/tor.js.map +1 -0
- package/dist/fingerprints/types.d.ts +104 -0
- package/dist/fingerprints/types.d.ts.map +1 -0
- package/dist/fingerprints/types.js +9 -0
- package/dist/fingerprints/types.js.map +1 -0
- package/dist/http/h1/client.d.ts +21 -0
- package/dist/http/h1/client.d.ts.map +1 -0
- package/dist/http/h1/client.js +136 -0
- package/dist/http/h1/client.js.map +1 -0
- package/dist/http/h1/encoder.d.ts +11 -0
- package/dist/http/h1/encoder.d.ts.map +1 -0
- package/dist/http/h1/encoder.js +75 -0
- package/dist/http/h1/encoder.js.map +1 -0
- package/dist/http/h1/parser.d.ts +61 -0
- package/dist/http/h1/parser.d.ts.map +1 -0
- package/dist/http/h1/parser.js +258 -0
- package/dist/http/h1/parser.js.map +1 -0
- package/dist/http/h2/client.d.ts +48 -0
- package/dist/http/h2/client.d.ts.map +1 -0
- package/dist/http/h2/client.js +376 -0
- package/dist/http/h2/client.js.map +1 -0
- package/dist/http/h2/frames.d.ts +65 -0
- package/dist/http/h2/frames.d.ts.map +1 -0
- package/dist/http/h2/frames.js +184 -0
- package/dist/http/h2/frames.js.map +1 -0
- package/dist/http/h2/hpack.d.ts +27 -0
- package/dist/http/h2/hpack.d.ts.map +1 -0
- package/dist/http/h2/hpack.js +423 -0
- package/dist/http/h2/hpack.js.map +1 -0
- package/dist/http/negotiator.d.ts +36 -0
- package/dist/http/negotiator.d.ts.map +1 -0
- package/dist/http/negotiator.js +101 -0
- package/dist/http/negotiator.js.map +1 -0
- package/dist/http/pool.d.ts +63 -0
- package/dist/http/pool.d.ts.map +1 -0
- package/dist/http/pool.js +177 -0
- package/dist/http/pool.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/interceptor.d.ts +27 -0
- package/dist/middleware/interceptor.d.ts.map +1 -0
- package/dist/middleware/interceptor.js +35 -0
- package/dist/middleware/interceptor.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +26 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +59 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/middleware/retry.d.ts +17 -0
- package/dist/middleware/retry.d.ts.map +1 -0
- package/dist/middleware/retry.js +64 -0
- package/dist/middleware/retry.js.map +1 -0
- package/dist/proxy/http-proxy.d.ts +23 -0
- package/dist/proxy/http-proxy.d.ts.map +1 -0
- package/dist/proxy/http-proxy.js +93 -0
- package/dist/proxy/http-proxy.js.map +1 -0
- package/dist/proxy/socks.d.ts +24 -0
- package/dist/proxy/socks.d.ts.map +1 -0
- package/dist/proxy/socks.js +196 -0
- package/dist/proxy/socks.js.map +1 -0
- package/dist/tls/constants.d.ts +142 -0
- package/dist/tls/constants.d.ts.map +1 -0
- package/dist/tls/constants.js +163 -0
- package/dist/tls/constants.js.map +1 -0
- package/dist/tls/node-engine.d.ts +22 -0
- package/dist/tls/node-engine.d.ts.map +1 -0
- package/dist/tls/node-engine.js +190 -0
- package/dist/tls/node-engine.js.map +1 -0
- package/dist/tls/stealth/client-hello.d.ts +38 -0
- package/dist/tls/stealth/client-hello.d.ts.map +1 -0
- package/dist/tls/stealth/client-hello.js +197 -0
- package/dist/tls/stealth/client-hello.js.map +1 -0
- package/dist/tls/stealth/engine.d.ts +16 -0
- package/dist/tls/stealth/engine.d.ts.map +1 -0
- package/dist/tls/stealth/engine.js +196 -0
- package/dist/tls/stealth/engine.js.map +1 -0
- package/dist/tls/stealth/handshake.d.ts +45 -0
- package/dist/tls/stealth/handshake.d.ts.map +1 -0
- package/dist/tls/stealth/handshake.js +403 -0
- package/dist/tls/stealth/handshake.js.map +1 -0
- package/dist/tls/stealth/key-schedule.d.ts +85 -0
- package/dist/tls/stealth/key-schedule.d.ts.map +1 -0
- package/dist/tls/stealth/key-schedule.js +141 -0
- package/dist/tls/stealth/key-schedule.js.map +1 -0
- package/dist/tls/stealth/record-layer.d.ts +74 -0
- package/dist/tls/stealth/record-layer.d.ts.map +1 -0
- package/dist/tls/stealth/record-layer.js +167 -0
- package/dist/tls/stealth/record-layer.js.map +1 -0
- package/dist/tls/types.d.ts +58 -0
- package/dist/tls/types.d.ts.map +1 -0
- package/dist/tls/types.js +6 -0
- package/dist/tls/types.js.map +1 -0
- package/dist/utils/buffer-reader.d.ts +32 -0
- package/dist/utils/buffer-reader.d.ts.map +1 -0
- package/dist/utils/buffer-reader.js +99 -0
- package/dist/utils/buffer-reader.js.map +1 -0
- package/dist/utils/buffer-writer.d.ts +35 -0
- package/dist/utils/buffer-writer.d.ts.map +1 -0
- package/dist/utils/buffer-writer.js +121 -0
- package/dist/utils/buffer-writer.js.map +1 -0
- package/dist/utils/encoding.d.ts +19 -0
- package/dist/utils/encoding.d.ts.map +1 -0
- package/dist/utils/encoding.js +63 -0
- package/dist/utils/encoding.js.map +1 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +56 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/url.d.ts +22 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +56 -0
- package/dist/utils/url.js.map +1 -0
- package/dist/ws/client.d.ts +63 -0
- package/dist/ws/client.d.ts.map +1 -0
- package/dist/ws/client.js +273 -0
- package/dist/ws/client.js.map +1 -0
- package/dist/ws/frame.d.ts +44 -0
- package/dist/ws/frame.d.ts.map +1 -0
- package/dist/ws/frame.js +146 -0
- package/dist/ws/frame.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-engine.d.ts","sourceRoot":"","sources":["../../src/tls/node-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAqB,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AA2F/D,qBAAa,aAAc,YAAW,UAAU;IACxC,OAAO,CACX,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,SAAS,CAAC;CAgGtB"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard TLS engine.
|
|
3
|
+
*
|
|
4
|
+
* Uses Node.js built-in `node:tls` module with maximum configuration
|
|
5
|
+
* from browser profiles. This engine controls:
|
|
6
|
+
* - Cipher suite order (via the `ciphers` option)
|
|
7
|
+
* - Named groups / ECDH curves (via `ecdhCurve`)
|
|
8
|
+
* - Signature algorithms (via `sigalgs`)
|
|
9
|
+
* - ALPN protocols
|
|
10
|
+
* - Min/max protocol version
|
|
11
|
+
* - Session tickets, SNI
|
|
12
|
+
*
|
|
13
|
+
* Limitations: `node:tls` does not expose extension ordering, GREASE
|
|
14
|
+
* injection, or padding extension control. For full JA3 fingerprint
|
|
15
|
+
* matching use the Stealth engine instead.
|
|
16
|
+
*/
|
|
17
|
+
import * as tls from 'node:tls';
|
|
18
|
+
import { CipherSuite, NamedGroup, SignatureScheme } from './constants.js';
|
|
19
|
+
import { TLSError } from '../core/errors.js';
|
|
20
|
+
// ---- Cipher suite name mapping ----
|
|
21
|
+
const CIPHER_NAME = new Map([
|
|
22
|
+
// TLS 1.3 (Node handles these via `ciphersuites` option)
|
|
23
|
+
[CipherSuite.TLS_AES_128_GCM_SHA256, 'TLS_AES_128_GCM_SHA256'],
|
|
24
|
+
[CipherSuite.TLS_AES_256_GCM_SHA384, 'TLS_AES_256_GCM_SHA384'],
|
|
25
|
+
[CipherSuite.TLS_CHACHA20_POLY1305_SHA256, 'TLS_CHACHA20_POLY1305_SHA256'],
|
|
26
|
+
// TLS 1.2
|
|
27
|
+
[CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 'ECDHE-ECDSA-AES128-GCM-SHA256'],
|
|
28
|
+
[CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 'ECDHE-RSA-AES128-GCM-SHA256'],
|
|
29
|
+
[CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 'ECDHE-ECDSA-AES256-GCM-SHA384'],
|
|
30
|
+
[CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 'ECDHE-RSA-AES256-GCM-SHA384'],
|
|
31
|
+
[CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 'ECDHE-ECDSA-CHACHA20-POLY1305'],
|
|
32
|
+
[CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 'ECDHE-RSA-CHACHA20-POLY1305'],
|
|
33
|
+
[CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 'ECDHE-RSA-AES128-SHA'],
|
|
34
|
+
[CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 'ECDHE-RSA-AES256-SHA'],
|
|
35
|
+
[CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, 'AES128-GCM-SHA256'],
|
|
36
|
+
[CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384, 'AES256-GCM-SHA384'],
|
|
37
|
+
[CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, 'AES128-SHA'],
|
|
38
|
+
[CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, 'AES256-SHA'],
|
|
39
|
+
[CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 'ECDHE-ECDSA-AES256-SHA'],
|
|
40
|
+
[CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 'ECDHE-ECDSA-AES128-SHA'],
|
|
41
|
+
[CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, 'AES256-SHA'],
|
|
42
|
+
[CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, 'AES128-SHA'],
|
|
43
|
+
]);
|
|
44
|
+
const GROUP_NAME = new Map([
|
|
45
|
+
[NamedGroup.X25519, 'X25519'],
|
|
46
|
+
[NamedGroup.SECP256R1, 'P-256'],
|
|
47
|
+
[NamedGroup.SECP384R1, 'P-384'],
|
|
48
|
+
[NamedGroup.SECP521R1, 'P-521'],
|
|
49
|
+
[NamedGroup.X448, 'X448'],
|
|
50
|
+
[NamedGroup.FFDHE2048, 'ffdhe2048'],
|
|
51
|
+
[NamedGroup.FFDHE3072, 'ffdhe3072'],
|
|
52
|
+
]);
|
|
53
|
+
const SIGALG_NAME = new Map([
|
|
54
|
+
[SignatureScheme.ECDSA_SECP256R1_SHA256, 'ecdsa_secp256r1_sha256'],
|
|
55
|
+
[SignatureScheme.ECDSA_SECP384R1_SHA384, 'ecdsa_secp384r1_sha384'],
|
|
56
|
+
[SignatureScheme.ECDSA_SECP521R1_SHA512, 'ecdsa_secp521r1_sha512'],
|
|
57
|
+
[SignatureScheme.RSA_PSS_RSAE_SHA256, 'rsa_pss_rsae_sha256'],
|
|
58
|
+
[SignatureScheme.RSA_PSS_RSAE_SHA384, 'rsa_pss_rsae_sha384'],
|
|
59
|
+
[SignatureScheme.RSA_PSS_RSAE_SHA512, 'rsa_pss_rsae_sha512'],
|
|
60
|
+
[SignatureScheme.RSA_PKCS1_SHA256, 'rsa_pkcs1_sha256'],
|
|
61
|
+
[SignatureScheme.RSA_PKCS1_SHA384, 'rsa_pkcs1_sha384'],
|
|
62
|
+
[SignatureScheme.RSA_PKCS1_SHA512, 'rsa_pkcs1_sha512'],
|
|
63
|
+
[SignatureScheme.RSA_PSS_PSS_SHA256, 'rsa_pss_pss_sha256'],
|
|
64
|
+
[SignatureScheme.RSA_PSS_PSS_SHA384, 'rsa_pss_pss_sha384'],
|
|
65
|
+
[SignatureScheme.RSA_PSS_PSS_SHA512, 'rsa_pss_pss_sha512'],
|
|
66
|
+
]);
|
|
67
|
+
// ---- Helpers ----
|
|
68
|
+
function buildCipherString(suites) {
|
|
69
|
+
const tls13 = [];
|
|
70
|
+
const tls12 = [];
|
|
71
|
+
for (const s of suites) {
|
|
72
|
+
const name = CIPHER_NAME.get(s);
|
|
73
|
+
if (!name)
|
|
74
|
+
continue;
|
|
75
|
+
if (name.startsWith('TLS_')) {
|
|
76
|
+
tls13.push(name);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
tls12.push(name);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
ciphers: tls12.join(':'),
|
|
84
|
+
ciphersuites: tls13.join(':'),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function buildEcdhCurve(groups) {
|
|
88
|
+
return groups
|
|
89
|
+
.map((g) => GROUP_NAME.get(g))
|
|
90
|
+
.filter((n) => n !== undefined)
|
|
91
|
+
.join(':');
|
|
92
|
+
}
|
|
93
|
+
function buildSigalgs(algs) {
|
|
94
|
+
return algs
|
|
95
|
+
.map((a) => SIGALG_NAME.get(a))
|
|
96
|
+
.filter((n) => n !== undefined)
|
|
97
|
+
.join(':');
|
|
98
|
+
}
|
|
99
|
+
// ---- Engine implementation ----
|
|
100
|
+
export class NodeTLSEngine {
|
|
101
|
+
async connect(options, profile) {
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
const tlsOpts = {
|
|
104
|
+
host: options.host,
|
|
105
|
+
port: options.port,
|
|
106
|
+
servername: options.servername ?? options.host,
|
|
107
|
+
rejectUnauthorized: !options.insecure,
|
|
108
|
+
ALPNProtocols: options.alpnProtocols,
|
|
109
|
+
minVersion: 'TLSv1.2',
|
|
110
|
+
maxVersion: 'TLSv1.3',
|
|
111
|
+
};
|
|
112
|
+
// Apply profile overrides
|
|
113
|
+
if (profile) {
|
|
114
|
+
const { ciphers, ciphersuites } = buildCipherString(profile.tls.cipherSuites);
|
|
115
|
+
tlsOpts.ciphers = ciphers;
|
|
116
|
+
// ciphersuites is an undocumented but supported option in Node
|
|
117
|
+
tlsOpts['cipherSuites'] = ciphersuites;
|
|
118
|
+
tlsOpts.ecdhCurve = buildEcdhCurve(profile.tls.supportedGroups);
|
|
119
|
+
tlsOpts.sigalgs = buildSigalgs(profile.tls.signatureAlgorithms);
|
|
120
|
+
tlsOpts.ALPNProtocols = profile.tls.alpnProtocols;
|
|
121
|
+
}
|
|
122
|
+
// If a pre-connected socket is provided (e.g. from proxy tunnel),
|
|
123
|
+
// use it as the underlying transport.
|
|
124
|
+
if (options.socket) {
|
|
125
|
+
tlsOpts.socket = options.socket;
|
|
126
|
+
}
|
|
127
|
+
// Timeout
|
|
128
|
+
const timeoutMs = options.timeout ?? 30_000;
|
|
129
|
+
const socket = tls.connect(tlsOpts);
|
|
130
|
+
let settled = false;
|
|
131
|
+
let timer;
|
|
132
|
+
if (timeoutMs > 0) {
|
|
133
|
+
timer = setTimeout(() => {
|
|
134
|
+
if (!settled) {
|
|
135
|
+
settled = true;
|
|
136
|
+
socket.destroy();
|
|
137
|
+
reject(new TLSError('TLS handshake timed out'));
|
|
138
|
+
}
|
|
139
|
+
}, timeoutMs);
|
|
140
|
+
}
|
|
141
|
+
// AbortSignal support
|
|
142
|
+
if (options.signal) {
|
|
143
|
+
const onAbort = () => {
|
|
144
|
+
if (!settled) {
|
|
145
|
+
settled = true;
|
|
146
|
+
if (timer)
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
socket.destroy();
|
|
149
|
+
reject(new TLSError('TLS connection aborted'));
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
if (options.signal.aborted) {
|
|
153
|
+
onAbort();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
options.signal.addEventListener('abort', onAbort, { once: true });
|
|
157
|
+
}
|
|
158
|
+
socket.once('secureConnect', () => {
|
|
159
|
+
if (settled)
|
|
160
|
+
return;
|
|
161
|
+
settled = true;
|
|
162
|
+
if (timer)
|
|
163
|
+
clearTimeout(timer);
|
|
164
|
+
const cipher = socket.getCipher();
|
|
165
|
+
const proto = socket.getProtocol();
|
|
166
|
+
const connectionInfo = {
|
|
167
|
+
version: proto ?? 'unknown',
|
|
168
|
+
alpnProtocol: socket.alpnProtocol || null,
|
|
169
|
+
cipher: cipher?.name ?? 'unknown',
|
|
170
|
+
};
|
|
171
|
+
const tlsSocket = Object.assign(socket, {
|
|
172
|
+
connectionInfo,
|
|
173
|
+
destroyTLS() {
|
|
174
|
+
socket.destroy();
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
resolve(tlsSocket);
|
|
178
|
+
});
|
|
179
|
+
socket.once('error', (err) => {
|
|
180
|
+
if (settled)
|
|
181
|
+
return;
|
|
182
|
+
settled = true;
|
|
183
|
+
if (timer)
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
reject(new TLSError(err.message));
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=node-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-engine.js","sourceRoot":"","sources":["../../src/tls/node-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClientHello builder.
|
|
3
|
+
*
|
|
4
|
+
* Constructs a TLS ClientHello message byte-by-byte, giving full
|
|
5
|
+
* control over extension ordering, GREASE placement, cipher suite
|
|
6
|
+
* order, and every other field that contributes to the JA3 fingerprint.
|
|
7
|
+
*
|
|
8
|
+
* The output is a complete TLS record (record header + handshake
|
|
9
|
+
* header + ClientHello body) ready to send over a TCP socket.
|
|
10
|
+
*/
|
|
11
|
+
import type { BrowserProfile } from '../../fingerprints/types.js';
|
|
12
|
+
export interface KeyShareEntry {
|
|
13
|
+
group: number;
|
|
14
|
+
publicKey: Buffer;
|
|
15
|
+
privateKey: Buffer;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate a key share for the given named group.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateKeyShare(group: number): KeyShareEntry;
|
|
21
|
+
export interface ClientHelloResult {
|
|
22
|
+
/** Complete TLS record bytes to send. */
|
|
23
|
+
record: Buffer;
|
|
24
|
+
/** Generated key shares for use in key exchange. */
|
|
25
|
+
keyShares: KeyShareEntry[];
|
|
26
|
+
/** The client_random value (32 bytes). */
|
|
27
|
+
clientRandom: Buffer;
|
|
28
|
+
/** Session ID (may be empty or 32 bytes). */
|
|
29
|
+
sessionId: Buffer;
|
|
30
|
+
/** The raw ClientHello handshake message (without record header) for
|
|
31
|
+
* transcript hashing. */
|
|
32
|
+
handshakeMessage: Buffer;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a complete ClientHello record from a browser profile.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildClientHello(profile: BrowserProfile, hostname: string): ClientHelloResult;
|
|
38
|
+
//# sourceMappingURL=client-hello.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-hello.d.ts","sourceRoot":"","sources":["../../../src/tls/stealth/client-hello.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,6BAA6B,CAAC;AAWnF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAgC7D;AAsBD,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB;8BAC0B;IAC1B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,GACf,iBAAiB,CA+FnB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClientHello builder.
|
|
3
|
+
*
|
|
4
|
+
* Constructs a TLS ClientHello message byte-by-byte, giving full
|
|
5
|
+
* control over extension ordering, GREASE placement, cipher suite
|
|
6
|
+
* order, and every other field that contributes to the JA3 fingerprint.
|
|
7
|
+
*
|
|
8
|
+
* The output is a complete TLS record (record header + handshake
|
|
9
|
+
* header + ClientHello body) ready to send over a TCP socket.
|
|
10
|
+
*/
|
|
11
|
+
import { randomBytes, createECDH, generateKeyPairSync } from 'node:crypto';
|
|
12
|
+
import { BufferWriter } from '../../utils/buffer-writer.js';
|
|
13
|
+
import { RecordType, HandshakeType, ExtensionType, GREASE_VALUES, NamedGroup, } from '../constants.js';
|
|
14
|
+
// ---- GREASE ----
|
|
15
|
+
/** Pick a random GREASE value. */
|
|
16
|
+
function randomGrease() {
|
|
17
|
+
return GREASE_VALUES[Math.floor(Math.random() * GREASE_VALUES.length)];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a key share for the given named group.
|
|
21
|
+
*/
|
|
22
|
+
export function generateKeyShare(group) {
|
|
23
|
+
switch (group) {
|
|
24
|
+
case NamedGroup.X25519: {
|
|
25
|
+
const kp = generateKeyPairSync('x25519');
|
|
26
|
+
const pub = kp.publicKey.export({ type: 'spki', format: 'der' });
|
|
27
|
+
const priv = kp.privateKey.export({ type: 'pkcs8', format: 'der' });
|
|
28
|
+
// X25519 public key is the last 32 bytes of the SPKI DER
|
|
29
|
+
const publicKey = Buffer.from(pub.subarray(pub.length - 32));
|
|
30
|
+
// X25519 private key is the last 32 bytes of the PKCS8 DER
|
|
31
|
+
const privateKey = Buffer.from(priv.subarray(priv.length - 32));
|
|
32
|
+
return { group, publicKey, privateKey };
|
|
33
|
+
}
|
|
34
|
+
case NamedGroup.SECP256R1:
|
|
35
|
+
case NamedGroup.SECP384R1:
|
|
36
|
+
case NamedGroup.SECP521R1: {
|
|
37
|
+
const curveName = group === NamedGroup.SECP256R1
|
|
38
|
+
? 'prime256v1'
|
|
39
|
+
: group === NamedGroup.SECP384R1
|
|
40
|
+
? 'secp384r1'
|
|
41
|
+
: 'secp521r1';
|
|
42
|
+
const ecdh = createECDH(curveName);
|
|
43
|
+
ecdh.generateKeys();
|
|
44
|
+
return {
|
|
45
|
+
group,
|
|
46
|
+
publicKey: Buffer.from(ecdh.getPublicKey()),
|
|
47
|
+
privateKey: Buffer.from(ecdh.getPrivateKey()),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
throw new Error(`Unsupported key share group: 0x${group.toString(16)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// ---- Key share extension data builder ----
|
|
55
|
+
function buildKeyShareExtensionData(keyShares) {
|
|
56
|
+
const w = new BufferWriter(256);
|
|
57
|
+
// client_shares length placeholder
|
|
58
|
+
const lenReserve = w.reserve(2);
|
|
59
|
+
const startPos = w.position;
|
|
60
|
+
for (const ks of keyShares) {
|
|
61
|
+
w.writeUInt16(ks.group);
|
|
62
|
+
w.writeUInt16(ks.publicKey.length);
|
|
63
|
+
w.writeBytes(ks.publicKey);
|
|
64
|
+
}
|
|
65
|
+
w.patchUInt16(lenReserve, w.position - startPos);
|
|
66
|
+
return w.toBuffer();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build a complete ClientHello record from a browser profile.
|
|
70
|
+
*/
|
|
71
|
+
export function buildClientHello(profile, hostname) {
|
|
72
|
+
const tlsProfile = profile.tls;
|
|
73
|
+
// Generate cryptographic material
|
|
74
|
+
const clientRandom = randomBytes(32);
|
|
75
|
+
const sessionId = tlsProfile.randomSessionId ? randomBytes(32) : Buffer.alloc(0);
|
|
76
|
+
const keyShares = tlsProfile.keyShareGroups.map(generateKeyShare);
|
|
77
|
+
// Pick GREASE values (reuse same value per category for consistency)
|
|
78
|
+
const greaseCipher = tlsProfile.grease ? randomGrease() : 0;
|
|
79
|
+
const greaseExt = tlsProfile.grease ? randomGrease() : 0;
|
|
80
|
+
const greaseGroup = tlsProfile.grease ? randomGrease() : 0;
|
|
81
|
+
const greaseVersion = tlsProfile.grease ? randomGrease() : 0;
|
|
82
|
+
// ---- Build ClientHello body ----
|
|
83
|
+
const body = new BufferWriter(4096);
|
|
84
|
+
// client_version
|
|
85
|
+
body.writeUInt16(tlsProfile.clientVersion);
|
|
86
|
+
// random (32 bytes)
|
|
87
|
+
body.writeBytes(clientRandom);
|
|
88
|
+
// session_id
|
|
89
|
+
body.writeUInt8(sessionId.length);
|
|
90
|
+
if (sessionId.length > 0)
|
|
91
|
+
body.writeBytes(sessionId);
|
|
92
|
+
// cipher_suites
|
|
93
|
+
const ciphers = tlsProfile.grease
|
|
94
|
+
? [greaseCipher, ...tlsProfile.cipherSuites]
|
|
95
|
+
: [...tlsProfile.cipherSuites];
|
|
96
|
+
body.writeUInt16(ciphers.length * 2);
|
|
97
|
+
for (const c of ciphers)
|
|
98
|
+
body.writeUInt16(c);
|
|
99
|
+
// compression_methods
|
|
100
|
+
body.writeUInt8(tlsProfile.compressionMethods.length);
|
|
101
|
+
for (const m of tlsProfile.compressionMethods)
|
|
102
|
+
body.writeUInt8(m);
|
|
103
|
+
// ---- Extensions ----
|
|
104
|
+
const extWriter = new BufferWriter(4096);
|
|
105
|
+
// If GREASE is enabled, prepend a GREASE extension
|
|
106
|
+
if (tlsProfile.grease) {
|
|
107
|
+
extWriter.writeUInt16(greaseExt);
|
|
108
|
+
extWriter.writeUInt16(1);
|
|
109
|
+
extWriter.writeUInt8(0);
|
|
110
|
+
}
|
|
111
|
+
// Write each extension from the profile in exact order
|
|
112
|
+
for (const extDef of tlsProfile.extensions) {
|
|
113
|
+
writeExtension(extWriter, extDef, hostname, keyShares, tlsProfile, {
|
|
114
|
+
greaseGroup,
|
|
115
|
+
greaseVersion,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// If GREASE is enabled, append a GREASE extension at end
|
|
119
|
+
if (tlsProfile.grease) {
|
|
120
|
+
const lastGrease = randomGrease();
|
|
121
|
+
extWriter.writeUInt16(lastGrease);
|
|
122
|
+
extWriter.writeUInt16(1);
|
|
123
|
+
extWriter.writeUInt8(0);
|
|
124
|
+
}
|
|
125
|
+
const extBytes = extWriter.toBuffer();
|
|
126
|
+
body.writeUInt16(extBytes.length);
|
|
127
|
+
body.writeBytes(extBytes);
|
|
128
|
+
const clientHelloBody = body.toBuffer();
|
|
129
|
+
// ---- Wrap in handshake header ----
|
|
130
|
+
const handshake = new BufferWriter(4 + clientHelloBody.length);
|
|
131
|
+
handshake.writeUInt8(HandshakeType.CLIENT_HELLO);
|
|
132
|
+
handshake.writeUInt24(clientHelloBody.length);
|
|
133
|
+
handshake.writeBytes(clientHelloBody);
|
|
134
|
+
const handshakeMessage = handshake.toBuffer();
|
|
135
|
+
// ---- Wrap in record ----
|
|
136
|
+
const record = new BufferWriter(5 + handshakeMessage.length);
|
|
137
|
+
record.writeUInt8(RecordType.HANDSHAKE);
|
|
138
|
+
record.writeUInt16(tlsProfile.recordVersion);
|
|
139
|
+
record.writeUInt16(handshakeMessage.length);
|
|
140
|
+
record.writeBytes(handshakeMessage);
|
|
141
|
+
return {
|
|
142
|
+
record: record.toBuffer(),
|
|
143
|
+
keyShares,
|
|
144
|
+
clientRandom,
|
|
145
|
+
sessionId,
|
|
146
|
+
handshakeMessage,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// ---- Extension writer ----
|
|
150
|
+
function writeExtension(w, extDef, hostname, keyShares, tlsProfile, grease) {
|
|
151
|
+
// Special handling for key_share -- inject actual key material
|
|
152
|
+
if (extDef.type === ExtensionType.KEY_SHARE) {
|
|
153
|
+
const data = buildKeyShareExtensionData(keyShares);
|
|
154
|
+
w.writeUInt16(ExtensionType.KEY_SHARE);
|
|
155
|
+
w.writeUInt16(data.length);
|
|
156
|
+
w.writeBytes(data);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// Special handling for supported_groups with GREASE
|
|
160
|
+
if (extDef.type === ExtensionType.SUPPORTED_GROUPS && tlsProfile.grease) {
|
|
161
|
+
const groups = [grease.greaseGroup, ...tlsProfile.supportedGroups];
|
|
162
|
+
const inner = new BufferWriter(2 + groups.length * 2);
|
|
163
|
+
inner.writeUInt16(groups.length * 2);
|
|
164
|
+
for (const g of groups)
|
|
165
|
+
inner.writeUInt16(g);
|
|
166
|
+
const data = inner.toBuffer();
|
|
167
|
+
w.writeUInt16(ExtensionType.SUPPORTED_GROUPS);
|
|
168
|
+
w.writeUInt16(data.length);
|
|
169
|
+
w.writeBytes(data);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Special handling for supported_versions with GREASE
|
|
173
|
+
if (extDef.type === ExtensionType.SUPPORTED_VERSIONS && tlsProfile.grease) {
|
|
174
|
+
const versions = [grease.greaseVersion, ...tlsProfile.supportedVersions];
|
|
175
|
+
const inner = new BufferWriter(1 + versions.length * 2);
|
|
176
|
+
inner.writeUInt8(versions.length * 2);
|
|
177
|
+
for (const v of versions)
|
|
178
|
+
inner.writeUInt16(v);
|
|
179
|
+
const data = inner.toBuffer();
|
|
180
|
+
w.writeUInt16(ExtensionType.SUPPORTED_VERSIONS);
|
|
181
|
+
w.writeUInt16(data.length);
|
|
182
|
+
w.writeBytes(data);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// General case
|
|
186
|
+
w.writeUInt16(extDef.type);
|
|
187
|
+
if (extDef.data) {
|
|
188
|
+
const data = extDef.data(hostname);
|
|
189
|
+
w.writeUInt16(data.length);
|
|
190
|
+
if (data.length > 0)
|
|
191
|
+
w.writeBytes(data);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
w.writeUInt16(0);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=client-hello.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-hello.js","sourceRoot":"","sources":["../../../src/tls/stealth/client-hello.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stealth TLS engine.
|
|
3
|
+
*
|
|
4
|
+
* Implements ITLSEngine using raw TCP sockets and manual TLS 1.3
|
|
5
|
+
* handshake construction. This gives 100% control over the
|
|
6
|
+
* ClientHello bytes, enabling perfect JA3 fingerprint matching.
|
|
7
|
+
*
|
|
8
|
+
* After the handshake completes, wraps the raw socket in a Duplex
|
|
9
|
+
* stream that transparently encrypts/decrypts application data.
|
|
10
|
+
*/
|
|
11
|
+
import type { ITLSEngine, TLSConnectOptions, TLSSocket } from '../types.js';
|
|
12
|
+
import type { BrowserProfile } from '../../fingerprints/types.js';
|
|
13
|
+
export declare class StealthTLSEngine implements ITLSEngine {
|
|
14
|
+
connect(options: TLSConnectOptions, profile?: BrowserProfile): Promise<TLSSocket>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/tls/stealth/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAqB,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAyJlE,qBAAa,gBAAiB,YAAW,UAAU;IAC3C,OAAO,CACX,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,SAAS,CAAC;CA2BtB"}
|