tunnelfetch 1.2.0 → 1.4.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/README.md +93 -28
- package/README.zh-CN.md +54 -11
- package/package.json +5 -1
- package/src/client/header-order.js +159 -0
- package/src/client.js +79 -18
- package/src/http2/connection.js +36 -4
- package/src/index.js +1 -0
- package/src/profile/chrome.js +45 -0
- package/src/profile/vendor/chacha20poly1305.js +65 -0
- package/src/profile/vendor/mlkem768.js +67 -0
- package/src/profiles.js +184 -0
- package/src/tls/aead.js +51 -16
- package/src/tls/connect.js +49 -8
- package/src/tls/constants.js +60 -6
- package/src/tls/extensions.js +10 -0
- package/src/tls/grease.js +109 -0
- package/src/tls/handshake-messages.js +78 -9
- package/src/tls/handshake.js +2 -1
- package/src/tls/hybrid.js +166 -0
- package/src/tls/record.js +24 -3
- package/src/warmup-fixture.js +46 -45
- package/types/client/header-order.d.ts +56 -0
- package/types/client.d.ts +68 -0
- package/types/http2/connection.d.ts +16 -1
- package/types/http2/hpack.d.ts +1 -1
- package/types/index.d.ts +1 -0
- package/types/profile/chrome.d.ts +16 -0
- package/types/profile/vendor/chacha20poly1305.d.ts +7 -0
- package/types/profile/vendor/mlkem768.d.ts +23 -0
- package/types/profiles.d.ts +100 -0
- package/types/tls/aead.d.ts +17 -1
- package/types/tls/connect.d.ts +45 -6
- package/types/tls/constants.d.ts +31 -3
- package/types/tls/extensions.d.ts +7 -0
- package/types/tls/grease.d.ts +46 -0
- package/types/tls/handshake-messages.d.ts +12 -5
- package/types/tls/hybrid.d.ts +63 -0
- package/types/tls/record.d.ts +23 -0
package/src/http2/connection.js
CHANGED
|
@@ -117,6 +117,13 @@ export class Http2Retryable extends Http2Error {}
|
|
|
117
117
|
* @property {number} [maxConcurrentStreams] our advertised SETTINGS_MAX_CONCURRENT_STREAMS.
|
|
118
118
|
* @property {number} [maxHeaderTableSize] our advertised SETTINGS_HEADER_TABLE_SIZE.
|
|
119
119
|
* @property {number} [maxHeaderListSize] self-protection cap on a decoded response header list.
|
|
120
|
+
* @property {string[]} [pseudoHeaderOrder] request pseudo-headers in the order to emit them.
|
|
121
|
+
* Defaults to curl's `[':method', ':scheme', ':authority', ':path']`. Any of the four left out is
|
|
122
|
+
* appended rather than dropped — RFC 9113 s8.3.1 makes all four mandatory and a request missing
|
|
123
|
+
* one is malformed, which is not a fingerprint choice anyone should be able to make by accident.
|
|
124
|
+
* @property {Record<string, 'incremental'|'without'|'never'>} [hpackIndexing] per-field HPACK
|
|
125
|
+
* indexing. Which fields enter the dynamic table is part of the fingerprint. Defaults to curl's:
|
|
126
|
+
* everything incremental except `:path`, which is sent without indexing.
|
|
120
127
|
* @property {Array<[number, number]>} [settings] the SETTINGS flight sent in the connection
|
|
121
128
|
* preface, as [id, value] pairs. Order is significant — an Akamai-style HTTP/2 fingerprint reads
|
|
122
129
|
* the ids in the order they are sent — so this replaces the flight entirely rather than merging.
|
|
@@ -202,6 +209,10 @@ export class Http2Connection {
|
|
|
202
209
|
this._maxHeaderBlockBytes = opts.maxHeaderBlockBytes ?? 262144;
|
|
203
210
|
/** @type {Array<[number, number]> | null} the SETTINGS flight, ids and order included */
|
|
204
211
|
this._settingsFlight = opts.settings ?? null;
|
|
212
|
+
// The rest of what an Akamai-style h2 fingerprint reads: the pseudo-header order and which
|
|
213
|
+
// fields go into the HPACK dynamic table. Both default to curl's, both captured off the wire.
|
|
214
|
+
this._pseudoHeaderOrder = opts.pseudoHeaderOrder ?? null;
|
|
215
|
+
this._hpackIndexing = opts.hpackIndexing ?? null;
|
|
205
216
|
this._expectFirstSettings = true;
|
|
206
217
|
|
|
207
218
|
this._fatal = null; // set once; rejects every stream and every future request
|
|
@@ -321,7 +332,10 @@ export class Http2Connection {
|
|
|
321
332
|
}
|
|
322
333
|
const hasBody = body != null && body.byteLength > 0;
|
|
323
334
|
|
|
324
|
-
const fields = buildRequestFields(
|
|
335
|
+
const fields = buildRequestFields(
|
|
336
|
+
{ method, scheme, authority, path, headers },
|
|
337
|
+
{ pseudoHeaderOrder: this._pseudoHeaderOrder, hpackIndexing: this._hpackIndexing },
|
|
338
|
+
);
|
|
325
339
|
const block = encodeHeaderBlock(fields);
|
|
326
340
|
this._sendHeaderBlock(id, block, !hasBody);
|
|
327
341
|
stream.localEnded = !hasBody;
|
|
@@ -1206,14 +1220,32 @@ export class Http2Connection {
|
|
|
1206
1220
|
* headers: Array<[string, string]> }} req
|
|
1207
1221
|
* @returns {import('./hpack.js').HpackField[]}
|
|
1208
1222
|
*/
|
|
1209
|
-
export function buildRequestFields({ method, scheme, authority, path, headers }) {
|
|
1223
|
+
export function buildRequestFields({ method, scheme, authority, path, headers }, opts = {}) {
|
|
1210
1224
|
const pseudo = { ':method': method, ':scheme': scheme, ':authority': authority, ':path': path };
|
|
1225
|
+
const order = opts.pseudoHeaderOrder ?? PSEUDO_HEADER_ORDER;
|
|
1226
|
+
// Which fields go into the dynamic table is itself part of the fingerprint: an Akamai-style h2
|
|
1227
|
+
// hash reads the HPACK representation, and curl indexes everything except :path. A caller
|
|
1228
|
+
// matching another client needs both this and the order, so both are configurable — with the
|
|
1229
|
+
// caller's map consulted first and curl's rule as the default.
|
|
1230
|
+
const indexingFor = (name) =>
|
|
1231
|
+
opts.hpackIndexing?.[name] ?? (name === ':path' ? 'without' : 'incremental');
|
|
1232
|
+
|
|
1211
1233
|
const fields = [];
|
|
1234
|
+
const seen = new Set();
|
|
1235
|
+
for (const name of order) {
|
|
1236
|
+
if (!(name in pseudo) || seen.has(name)) continue;
|
|
1237
|
+
seen.add(name);
|
|
1238
|
+
fields.push({ name, value: pseudo[name], indexing: indexingFor(name) });
|
|
1239
|
+
}
|
|
1240
|
+
// A caller-supplied order that omits a pseudo-header would produce a malformed request
|
|
1241
|
+
// (RFC 9113 s8.3.1 makes all four mandatory for a request), so the missing ones are appended in
|
|
1242
|
+
// curl's order rather than silently dropped.
|
|
1212
1243
|
for (const name of PSEUDO_HEADER_ORDER) {
|
|
1213
|
-
|
|
1244
|
+
if (seen.has(name)) continue;
|
|
1245
|
+
fields.push({ name, value: pseudo[name], indexing: indexingFor(name) });
|
|
1214
1246
|
}
|
|
1215
1247
|
for (const [name, value] of headers) {
|
|
1216
|
-
fields.push({ name, value, indexing:
|
|
1248
|
+
fields.push({ name, value, indexing: indexingFor(name) });
|
|
1217
1249
|
}
|
|
1218
1250
|
return fields;
|
|
1219
1251
|
}
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// The Chrome identity, ready to use. Importing this module IS the opt-in.
|
|
2
|
+
//
|
|
3
|
+
// `profiles.chrome` in the main entry is a declaration: it names what the identity needs and
|
|
4
|
+
// REFUSES to be presented without it, so nobody accidentally ships a Chromium ClientHello over a
|
|
5
|
+
// curl handshake. That refusal is correct but it leaves the caller to find and wire two WASM
|
|
6
|
+
// primitives, which is friction for the common case of "I want Chrome".
|
|
7
|
+
//
|
|
8
|
+
// This module closes that gap without moving the cost onto anyone else. The main entry stays free
|
|
9
|
+
// of both blobs — a bundler only pulls them in for code that imports THIS path, so a caller using
|
|
10
|
+
// the curl default pays nothing. That is the whole reason it is a separate entry point rather than
|
|
11
|
+
// a flag.
|
|
12
|
+
//
|
|
13
|
+
// import { Client } from 'tunnelfetch';
|
|
14
|
+
// import { chrome } from 'tunnelfetch/profile/chrome';
|
|
15
|
+
// new Client({ profile: chrome, connect, proxy });
|
|
16
|
+
//
|
|
17
|
+
// Still not supplied here: `br` and `zstd` decoders. Those are not cryptography and there is no
|
|
18
|
+
// single right implementation — bring your own through `decoders` (see the README). The profile
|
|
19
|
+
// will keep refusing until you do, which is the point.
|
|
20
|
+
|
|
21
|
+
import { chrome as declaration } from '../profiles.js';
|
|
22
|
+
import { chacha20poly1305 } from './vendor/chacha20poly1305.js';
|
|
23
|
+
import { mlkem768 } from './vendor/mlkem768.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* `profiles.chrome` with the two capabilities this package cannot perform natively already wired
|
|
27
|
+
* in. Everything else about it — the cipher list, the groups, the shuffled extension order, GREASE,
|
|
28
|
+
* the HTTP/2 SETTINGS and pseudo-header order, the request header order — comes from the
|
|
29
|
+
* declaration unchanged, and all of it was captured off the wire from Chrome 150.
|
|
30
|
+
*
|
|
31
|
+
* @type {import('../profiles.js').FingerprintProfile & {
|
|
32
|
+
* ciphers: Record<string, unknown>, groups: Record<string, unknown> }}
|
|
33
|
+
*/
|
|
34
|
+
export const chrome = Object.freeze({
|
|
35
|
+
...declaration,
|
|
36
|
+
name: `${declaration.name} (with bundled ML-KEM and ChaCha20)`,
|
|
37
|
+
// These satisfy two of the four entries in `requires`. `decoder:br` and `decoder:zstd` remain the
|
|
38
|
+
// caller's, so constructing a Client with this profile still fails until they are supplied —
|
|
39
|
+
// deliberately, because a Chrome that advertises `br` and cannot read it is worse than one that
|
|
40
|
+
// says so up front.
|
|
41
|
+
ciphers: Object.freeze({ chacha20: chacha20poly1305 }),
|
|
42
|
+
groups: Object.freeze({ x25519mlkem768: mlkem768 }),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export { chacha20poly1305, mlkem768 };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// ChaCha20-Poly1305 (RFC 8439 IETF AEAD) — libsodium reference C (DJB chacha-merged +
|
|
2
|
+
// poly1305-donna32 + the _ietf_encrypt/decrypt_detached construction) compiled to
|
|
3
|
+
// freestanding wasm32 with wasi-sdk 25 / LLVM 19. Zero wasm imports, no WASI, no
|
|
4
|
+
// allocator. Sources and build: wasmcrypto/c/chacha20poly1305.c, wasmcrypto/build.sh.
|
|
5
|
+
// AUTO-GENERATED by wasmcrypto/gen-js.mjs — edit that, not this.
|
|
6
|
+
// wasm sha256[0..12): ec15f83a678a raw 8839 bytes
|
|
7
|
+
|
|
8
|
+
const B64 = "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OgC+ASACQQA6AL8BIABBvxBqLQAAIQUgAEG+EGotAAAhAyAAQb0Qai0AACEGIABBvBBqLQAAIQcgAEG7EGotAAAhCCAAQboQai0AACEJIABBuRBqLQAAIQogAEG4EGotAAAhCyAAQbcQai0AACEMIABBthBqLQAAIQ0gAEG1EGotAAAhDiAAQbQQai0AACEPIABBsxBqLQAAIRAgAEGyEGotAAAhESAAQbEQai0AACAAQbAQai0AACEAIAItAA8hEyACLQAOIRQgAi0ADSEVIAItAAwhFiACLQALIRcgAi0ACiEYIAItAAkhGSACLQAIIRogAi0AByEbIAItAAYhHCACLQAFIR0gAi0ABCEeIAItAAMhHyACLQACISAgAi0AASACLQAAISIgAkEAOgAAIAJBADoAASACQQA6AAIgAkEAOgADIAJBADoABCACQQA6AAUgAkEAOgAGIAJBADoAByACQQA6AAggAkEAOgAJIAJBADoACiACQQA6AAsgAkEAOgAMIAJBADoADSACQQA6AA4gAkEAOgAPQX8hBHMgACAic3IgESAgc3IgECAfc3IgDyAec3IgDiAdc3IgDSAcc3IgDCAbc3IgCyAac3IgCiAZc3IgCSAYc3IgCCAXc3IgByAWc3IgBiAVc3IgAyAUc3IgBSATc3JBAWtBgAJxRQRAQcAQIAEQAAwBC0HAEEHAECAjQQEQCiABIQQLIAJBwAFqJAAgBAvOCQE3fyMAQUBqIQkgA0IAUgRAIAAoAjwhHSAAKAI4IR4gACgCNCESIAAoAjAhEyAAKAIsIR8gACgCKCEgIAAoAiQhISAAKAIgISIgACgCHCEjIAAoAhghJCAAKAIUISUgACgCECEmIAAoAgwhJyAAKAIIISggACgCBCEpIAAoAgAhKiAJQThqISwgCUEwaiEtIAlBKGohLiAJQSBqIS8gCUEYaiEwIAlBEGohMQNAAkAgA0I/VgRAIAIhBQwBCyAsQgA3AwAgLUIANwMAIC5CADcDACAvQgA3AwAgMEIANwMAIDFCADcDACAJQgA3AwggCUIANwMAQQAhBANAIAQgCWogASAEai0AADoAACADIARBAWoiBK1WDQALIAkiBSEBIAIhKwtBbCEWICohCCApIQogKCEOICchFCAmIQQgJSECICQhBiAjIQcgIiELICEhDyAgIQwgHSEQIB4h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";
|
|
9
|
+
|
|
10
|
+
function fromBase64(s) {
|
|
11
|
+
const bin = atob(s);
|
|
12
|
+
const u = new Uint8Array(bin.length);
|
|
13
|
+
for (let i = 0; i < u.length; i++) u[i] = bin.charCodeAt(i);
|
|
14
|
+
return u;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Module scope: on workerd this runs at isolate startup, which is not billed as request CPU.
|
|
18
|
+
// SYNCHRONOUS compile+instantiate, deliberately: the async forms (WebAssembly.compile /
|
|
19
|
+
// .instantiate) return promises that do not settle during workerd's startup evaluation, and
|
|
20
|
+
// the deploy is rejected with error 10021 "Top-level await in module is unsettled" — measured,
|
|
21
|
+
// not assumed. The module has zero imports; it cannot touch anything outside its own memory.
|
|
22
|
+
const _instance = new WebAssembly.Instance(new WebAssembly.Module(fromBase64(B64)), {});
|
|
23
|
+
const x = _instance.exports;
|
|
24
|
+
|
|
25
|
+
export const buildId = "ec15f83a678a";
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const MSG = x.cc_msg(), AAD = x.cc_aad(), KEY = x.cc_key(), NONCE = x.cc_nonce();
|
|
29
|
+
const MSG_CAP = x.cc_msg_cap(), AAD_CAP = x.cc_aad_cap();
|
|
30
|
+
let mem = new Uint8Array(x.memory.buffer);
|
|
31
|
+
const view = () => (mem.buffer === x.memory.buffer ? mem : (mem = new Uint8Array(x.memory.buffer)));
|
|
32
|
+
const EMPTY = new Uint8Array(0);
|
|
33
|
+
|
|
34
|
+
function load(key, nonce, data, aad) {
|
|
35
|
+
if (key.length !== 32) throw new RangeError('key must be 32 bytes');
|
|
36
|
+
if (nonce.length !== 12) throw new RangeError('nonce must be 12 bytes');
|
|
37
|
+
if (aad.length > AAD_CAP) throw new RangeError('aad too long');
|
|
38
|
+
const m = view();
|
|
39
|
+
m.set(key, KEY);
|
|
40
|
+
m.set(nonce, NONCE);
|
|
41
|
+
m.set(aad, AAD);
|
|
42
|
+
m.set(data, MSG);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const chacha20poly1305 = {
|
|
46
|
+
/** seal(key32, nonce12, plaintext, aad?) -> ciphertext||tag (RFC 8439 AEAD) */
|
|
47
|
+
seal(key, nonce, plaintext, aad = EMPTY) {
|
|
48
|
+
if (plaintext.length > MSG_CAP) throw new RangeError('plaintext too long');
|
|
49
|
+
load(key, nonce, plaintext, aad);
|
|
50
|
+
const n = x.cc_seal(plaintext.length, aad.length);
|
|
51
|
+
if (n < 0) throw new RangeError('seal rejected input');
|
|
52
|
+
return view().slice(MSG, MSG + n);
|
|
53
|
+
},
|
|
54
|
+
/** open(key32, nonce12, ciphertextAndTag, aad?) -> plaintext; throws on auth failure */
|
|
55
|
+
open(key, nonce, ciphertext, aad = EMPTY) {
|
|
56
|
+
if (ciphertext.length < 16 || ciphertext.length > MSG_CAP + 16) {
|
|
57
|
+
throw new Error('chacha20poly1305: invalid ciphertext');
|
|
58
|
+
}
|
|
59
|
+
load(key, nonce, ciphertext, aad);
|
|
60
|
+
const n = x.cc_open(ciphertext.length, aad.length);
|
|
61
|
+
if (n < 0) throw new Error('chacha20poly1305: authentication failed');
|
|
62
|
+
return view().slice(MSG, MSG + n);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// ML-KEM-768 (FIPS 203, final — NOT round-3 Kyber) — mlkem-native v1.2.0 single-compilation-
|
|
2
|
+
// unit build, compiled UNMODIFIED to freestanding wasm32 with wasi-sdk 25 / LLVM 19.
|
|
3
|
+
// Zero wasm imports; randomness is injected by the caller (or fetched from WebCrypto here).
|
|
4
|
+
// Sources and build: wasmcrypto/c/mlkem768_shim.c, wasmcrypto/build.sh.
|
|
5
|
+
// AUTO-GENERATED by wasmcrypto/gen-js.mjs — edit that, not this.
|
|
6
|
+
// wasm sha256[0..12): e17c38843d1e raw 31353 bytes
|
|
7
|
+
|
|
8
|
+
const B64 = "AGFzbQEAAAABPwlgAAF/YAJ/fwBgAX8AYAR/f39/AGADf39/AX9gAn9/AX9gBX9/f39/AGAGf39/f39/AGAJf39/f39/f39/AAMcGwQFAAAAAAAAAAAAAAAABgEHAggCAQMCAwECAQUDAQADBggBfwFBgLEICweMAQ0GbWVtb3J5AgAIbWtfY29pbnMAAgZta19tc2cAAwVta19wawAEBW1rX3NrAAUFbWtfY3QABgVta19zcwAHC21rX3BrX2J5dGVzAAgLbWtfc2tfYnl0ZXMACQtta19jdF9ieXRlcwAKCW1rX2tleWdlbgALCW1rX2VuY2FwcwAMCW1rX2RlY2FwcwANCtntARvGAQEDfwJAIAJFDQACQCACQQdxIgVFBEAgACEDIAIhBAwBCyACQXhxIQQgACEDA0AgAyABLQAAOgAAIANBAWohAyABQQFqIQEgBUEBayIFDQALCyACQQhJDQADQCADIAEtAAA6AAAgAyABLQABOgABIAMgAS0AAjoAAiADIAEtAAM6AAMgAyABLQAEOgAEIAMgAS0ABToABSADIAEtAAY6AAYgAyABLQAHOgAHIANBCGohAyABQQhqIQEgBEEIayIEDQALCyAAC5MBAQN/AkAgAUUNACAAIQIgASEDIAFBB3EiBARAIAFBeHEhAwNAIAJBADoAACACQQFqIQIgBEEBayIEDQALCyABQQhJDQADQCACQQA6AAcgAkEAOgAGIAJBADoABSACQQA6AAQgAkEAOgADIAJBADoAAiACQQA6AAEgAkEAOgAAIAJBCGohAiADQQhrIgMNAAsLIAALBQBBwAsLBQBBgAwLBQBBoAwLBQBBwBULBQBBoCgLBQBB4DALBQBBoAkLBQBB4BILBQBBwAgL3R4CDn8DfiMAQdABayIGJAAjACIAIABBgM8Aa0FgcSIAJAAgAEEDOgCgTiAAQcALKQAANwOATiAAQcgLKQAANwOITiAAQdALKQAANwOQTiAAQdgLKQAANwOYTiAAQZAqakG4ARABIQIgACAALQCATjoAgCogACAAKACBTjYAgSogACAAKQCFTjcAhSogACAAKQCNTjcAjSogACAAKACVTjYAlSogACAALQCZKiAALQCZTnM6AJkqIAAgAC0AmiogAC0Amk5zOgCaKiAAIAAtAJsqIAAtAJtOczoAmyogACAALQCcKiAA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AHM6AAAgAUGLAWoiASABLQAAIAJBmwNqLQAAczoAACAAQQRqIgANAAsgAxARQfh+IQADQCAAIANqIgFBiAFqIgIgAi0AACAAQaAMaiICQaAEai0AAHM6AAAgAUGJAWoiBCAELQAAIAJBoQRqLQAAczoAACABQYoBaiIEIAQtAAAgAkGiBGotAABzOgAAIAFBiwFqIgEgAS0AACACQaMEai0AAHM6AAAgAEEEaiIADQALIAMQEUH4fiEAA0AgACADaiIBQYgBaiICIAItAAAgAEGgDGoiAkGoBWotAABzOgAAIAFBiQFqIgQgBC0AACACQakFai0AAHM6AAAgAUGKAWoiBCAELQAAIAJBqgVqLQAAczoAACABQYsBaiIBIAEtAAAgAkGrBWotAABzOgAAIABBBGoiAA0ACyADEBFB+H4hAANAIAAgA2oiAUGIAWoiAiACLQAAIABBoAxqIgJBsAZqLQAAczoAACABQYkBaiIEIAQtAAAgAkGxBmotAABzOgAAIAFBigFqIgQgBC0AACACQbIGai0AAHM6AAAgAUGLAWoiASABLQAAIAJBswZqLQAAczoAACAAQQRqIgANAAsgAxARQfh+IQADQCAAIANqIgFBiAFqIgIgAi0AACAAQaAMaiICQbgHai0AAHM6AAAgAUGJAWoiBCAELQAAIAJBuQdqLQAAczoAACABQYoBaiIEIAQtAAAgAkG6B2otAABzOgAAIAFBiwFqIgEgAS0AACACQbsHai0AAHM6AAAgAEEEaiIADQALIAMQEUH4fiEAA0AgACADaiIBQYgBaiICIAItAAAgAEGgDGoiAkHACGotAABzOgAAIAFBiQFqIgQgBC0AACACQcEIai0AAHM6AAAgAUGKAWoiBCAELQAAIAJBwghqLQAAczoAACABQYsBaiIBIAEtAAAgAkHDCGotAABzOgAAIABBBGoiAA0ACyADEBFBoH8hAANAIAAgA2oiAUHgAGoiAiACLQAAIABBoAxqIgJBoAlqLQAAczoAACABQeEAaiIEIAQtAAAgAkGhCWotAABzOgAAIAFB4gBqIgQgBC0AACACQaIJai0AAHM6AAAgAUHjAGoiASABLQAAIAJBowlqLQAAczoAACAAQQRqIgANAAsgAyADLQBgQQZzOgBgIAMgAy0AhwFBgAFzOgCHASADEBFB+CcgA0EYaikD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IQMDQCACQZABaiIBIANqIgVB4ABqIgQgBC0AACADQaAMaiIEQaAJai0AAHM6AAAgBUHhAGoiBiAGLQAAIARBoQlqLQAAczoAACAFQeIAaiIGIAYtAAAgBEGiCWotAABzOgAAIAVB4wBqIgUgBS0AACAEQaMJai0AAHM6AAAgA0EEaiIDDQALIAIgAi0A8AFBBnM6APABIAIgAi0AlwJBgAFzOgCXAiABEBEgAEEYaiACQagBaikDADcDACAAQRBqIAJBoAFqKQMANwMAIABBCGogAikDmAE3AwAgACACKQOQATcDACABQcgBEAEaIAFByAEQARpBQCEDA0AgAkGQAWoiBSADaiIAQUBrIgEgAS0AACACQUBrIgQgA2oiAUFAay0AAHM6AAAgAEHBAGoiBiAGLQAAIAFBwQBqLQAAczoAACAAQcIAaiIGIAYtAAAgAUHCAGotAABzOgAAIABBwwBqIgAgAC0AACABQcMAai0AAHM6AAAgA0EEaiIDDQALIAIgAi0A0AFBBnM6ANABIAIgAi0A1wFBgAFzOgDXASAFEBEgAkE4aiACQcgBaikDADcDACACQTBqIAJBwAFqKQMANwMAIAJBKGogAkG4AWopAwA3AwAgAkEgaiIDIAJBsAFqKQMANwMAIAIgAkGoAWopAwA3AxggAiACQaABaikDADcDECACIAIpA5gBNwMIIAIgAikDkAE3AwAgBUHIARABGkGgKCAEQaAMIAMQF0H4MCACKQMYNwAAQfAwIAIpAxA3AABB6DAgAikDCDcAAEHgMCACKQMANwAAQQAhAwsgAkE4akIANwMAIAJBMGpCADcDACACQShqQgA3AwAgAkEgakIANwMAIAJCADcDGCACQgA3AxAgAkIANwMIIAJCADcDACACQfgAakIANwMAIAJB8ABqQgA3AwAgAkHoAGpCADcDACACQeAAakIANwMAIAJCADcDWCACQgA3A1AgAkIANwNIIAJCADcDQCQAIAML8y8BJn8jACIAIABBwAtrQWBxIgkkAEF/IQUjACIAIABBgAJrQWBxIgAkACAAQTBqQcgBEAEaQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBiApqLQAAczoAACADQYkBaiIEIAQtAAAgAkGJCmotAABzOgAAIANBigFqIgQgBC0AACACQYoKai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBiwpqLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBkAtqLQAAczoAACADQYkBaiIEIAQtAAAgAkGRC2otAABzOgAAIANBigFqIgQgBC0AACACQZILai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBkwtqLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBmAxqLQAAczoAACADQYkBaiIEIAQtAAAgAkGZDGotAABzOgAAIANBigFqIgQgBC0AACACQZoMai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBmwxqLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBoA1qLQAAczoAACADQYkBaiIEIAQtAAAgAkGhDWotAABzOgAAIANBigFqIgQgBC0AACACQaINai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBow1qLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBqA5qLQAAczoAACADQYkBaiIEIAQtAAAgAkGpDmotAABzOgAAIANBigFqIgQgBC0AACACQaoOai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBqw5qLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBsA9qLQAAczoAACADQYkBaiIEIAQtAAAgAkGxD2otAABzOgAAIANBigFqIgQgBC0AACACQbIPai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBsw9qLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBuBBqLQAAczoAACADQYkBaiIEIAQtAAAgAkG5EGotAABzOgAAIANBigFqIgQgBC0AACACQboQai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBuxBqLQAAczoAACABQQRqIgENAAsgBhARQfh+IQEDQCAAQTBqIgYgAWoiA0GIAWoiAiACLQAAIAFBwBVqIgJBwBFqLQAAczoAACADQYkBaiIEIAQtAAAgAkHBEWotAABzOgAAIANBigFqIgQgBC0AACACQcIRai0AAHM6AAAgA0GLAWoiAyADLQAAIAJBwxFqLQAAczoAACABQQRqIgENAAsgBhARQaB/IQEDQCAAQTBqIgYgAWoiA0HgAGoiAiACLQAAIAFBwBVqIgJBoBJqLQAAczoAACADQeEAaiIEIAQtAAAgAkGhEmotAABzOgAAIANB4gBqIgQgBC0AACACQaISai0AAHM6AAAgA0HjAGoiAyADLQAAIAJBoxJqLQAAczoAACABQQRqIgENAAsgACAALQCQAUEGczoAkAEgACAALQC3AUGAAXM6ALcBIAYQESAAIABByABqKQMANwMYIAAgAEFAaykDADcDECAAIAApAzg3AwggACAAKQMwNwMAIAZByAEQARpBACAALQAfQf8nLQAAcyIBIAAtAB5B/ictAABzIgMgAC0AHUH9Jy0AAHMiAiAALQAcQfwnLQAAcyIGIAAtABtB+yctAABzIgQgAC0AGkH6Jy0AAHMiCCAALQAZQfknLQAAcyILIAAtABhB+CctAABzIgogAC0AF0H3Jy0AAHMiDSAALQAWQfYnLQAAcyIOIAAtABVB9SctAABzIg8gAC0AFEH0Jy0AAHMiECAALQATQfMnLQAAcyIRIAAtABJB8ictAABzIhIgAC0AEUHxJy0AAHMiEyAALQAQQfAnLQAAcyIUIAAtAA9B7yctAABzIhUgAC0ADkHuJy0AAHMiFiAALQANQe0nLQAAcyIXIAAtAAxB7CctAABzIhggAC0AC0HrJy0AAHMiGSAALQAKQeonLQAAcyIaIAAtAAlB6SctAABzIhsgAC0ACEHoJy0AAHMiHCAALQAHQecnLQAAcyIdIAAtAAZB5ictAABzIh4gAC0ABUHlJy0AAHMiHyAALQAEQeQnLQAAcyIgIAAtAANB4yctAABzIiEgAC0AAkHiJy0AAHMiIiAALQABQeEnLQAAcyIjIAAtAABB4CctAABzIiRycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJyayElIABCADcDACAAQgA3AwggAEIANwMQIABCADcDGCQAIAEgAyACIAYgBCAIIAsgCiANIA4gDyAQIBEgEiATIBQgFSAWIBcgGCAZIBogGyAcIB0gHiAfICAgISAiICMgJHNzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3MiACAlQRB2c0H/AXEgAEH/AXFGBEAgCUGgCWohA0EAIQBBACEGIwAiASABQYAma0FgcSIFJAAgBUGAGmoiByEBA0AgAEGgKGoiAi0AACEKIAJBAWotAAAhBCACQQJqLQAAIQggAUEGaiACQQRqLQAAQQJ0IAJBA2otAAAiAkEGdnJBgRpsQYAEakEKdjsBACABQQRqIAJBBHRB8AdxIAhBBHZyQYEabEGABGpBCnY7AQAgAUECaiAIQQZ0QcAHcSAEQQJ2ckGBGmxBgARqQQp2OwEAIAEgCiAEQQh0QYAGcXJBgRpsQYAEakEKdjsBACABQQhqIQEgAEEFaiIAQcACRw0ACyAHQYYEaiEBQQAhAANAIABBoChqIgJBwAJqLQAAIQogAkHBAmotAAAhBCACQcICai0AACEIIAEgAkHEAmotAABBAnQgAkHDAmotAAAiAkEGdnJBgRpsQYAEakEKdjsBACABQQJrIAJBBHRB8AdxIAhBBHZyQYEabEGABGpBCnY7AQAgAUEEayAIQQZ0QcAHcSAEQQJ2ckGBGmxBgARqQQp2OwEAIAFBBmsgCiAEQQh0QYAGcXJBgRpsQYAEakEKdjsBACABQQhqIQEgAEEFaiIAQcACRw0ACyAHQYYIaiEBQQAhAANAIABBoChqIgJBgAVqLQAAIQggAkGBBWotAAAhByACQYIFai0AACEEIAEgAkGEBWotAABBAnQgAkGDBWotAAAiAkEGdnJBgRpsQYAEakEKdjsBACABQQJrIAJBBHRB8AdxIARBBHZyQYEabEGABGpBCnY7AQAgAUEEayAEQQZ0QcAHcSAHQQJ2ckGBGmxBgARqQQp2OwEAIAFBBmsgCCAHQQh0QYAGcXJBgRpsQYAEakEKdjsBACABQQhqIQEgAEEFaiIAQcACRw0AC0HgLyEAA0AgBUGACmogBmoiAUECaiAALQAAIgJBBHZBgRpsQQhqQQR2OwEAIAEgAkEPcUGBGmxBCGpBBHY7AQAgAEEBaiEAIAZBBGoiBkGABEcNAAsgBUGADmoiAUHAFRAYIAVBgBpqIgAQEyAFQYAeahATIAVBgCJqEBMgBSAAEBQgBUGABmoiAiABIAAgBRAVIAIQGUGAfCEAA0AgBUGACmogAGoiAUGABGoiAiACLwEAIAVBgAZqIABqIgJBgARqLwEAazsBACABQYIEaiIGIAYvAQAgAkGCBGovAQBrOwEAIAFBhARqIgYgBi8BACACQYQEai8BAGs7AQAgAUGGBGoiASABLwEAIAJBhgRqLwEAazsBACAAQQhqIgANAAtBACEAA0BBACAFQYAKaiICIABqIgYuAQAiAUG/nQFsQYCAgBBqQRp1Qf9lbCABaiIBwUEQdmshByAGIAFBgRpqIAFzIAdBEHZxIAFzOwEAIABBAmoiAEGABEcNAAtBACEBA0AgA0EAOgAAIAMgASACaiIALgEAQbjfzgBsQYCAgIAEakEfdiIGOgAAIAMgAEECai4BAEG4384AbEGAgICABGpBHnZBAnEgBnIiBjoAACADIAYgAEEEai4BAEG4384AbEGAgICABGpBHXZBBHFyIgY6AAAgAyAGIABBBmouAQBBuN/OAGxBgICAgARqQRx2QQhxciIGOgAAIAMgBiAAQQhqLgEAQbjfzgBsQYCAgIAEakEbdkEQcXIiBjoAACADIAYgAEEKai4BAEG4384AbEGAgICABGpBGnZBIHFyIgY6AAAgAyAGIABBDGouAQBBuN/OAGxBgICAgARqQRl2QcAAcXIiBjoAACADIAYgAEEOai4BAEG4384AbEGAgICABGpBGHZBgAFxcjoAACADQQFqIQMgAUEQaiIBQYAERw0ACyAFQYAGEAEiAEGABmpBgAQQARogAEGACmpBgAQQARogAEGADmpBgAwQARogAEGAGmpBgAwQARokACAJQdgJakH4JykAADcDACAJQdAJakHwJykAADcDACAJQcgJakHoJykAADcDACAJQeAnKQAANwPACSAJQcgBEAEhAEFAIQEDQCAAIAFqIgVBQGsiAyADLQAAIABBoAlqIAFqIgNBQGstAABzOgAAIAVBwQBqIgIgAi0AACADQcEAai0AAHM6AAAgBUHCAGoiAiACLQAAIANBwgBqLQAAczoAACAFQcMAaiIFIAUtAAAgA0HDAGotAABzOgAAIAFBBGoiAQ0ACyAAIAAtAEBBBnM6AEAgACAALQBHQYABczoARyAAEBEgAEGYCWogAEE4aikDADcDACAAQZAJaiAAQTBqKQMANwMAIABBiAlqIABB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";
|
|
9
|
+
|
|
10
|
+
function fromBase64(s) {
|
|
11
|
+
const bin = atob(s);
|
|
12
|
+
const u = new Uint8Array(bin.length);
|
|
13
|
+
for (let i = 0; i < u.length; i++) u[i] = bin.charCodeAt(i);
|
|
14
|
+
return u;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Module scope: on workerd this runs at isolate startup, which is not billed as request CPU.
|
|
18
|
+
// SYNCHRONOUS compile+instantiate, deliberately: the async forms (WebAssembly.compile /
|
|
19
|
+
// .instantiate) return promises that do not settle during workerd's startup evaluation, and
|
|
20
|
+
// the deploy is rejected with error 10021 "Top-level await in module is unsettled" — measured,
|
|
21
|
+
// not assumed. The module has zero imports; it cannot touch anything outside its own memory.
|
|
22
|
+
const _instance = new WebAssembly.Instance(new WebAssembly.Module(fromBase64(B64)), {});
|
|
23
|
+
const x = _instance.exports;
|
|
24
|
+
|
|
25
|
+
export const buildId = "e17c38843d1e";
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const COINS = x.mk_coins(), MSGBUF = x.mk_msg();
|
|
29
|
+
const PK = x.mk_pk(), SK = x.mk_sk(), CT = x.mk_ct(), SS = x.mk_ss();
|
|
30
|
+
const PK_B = x.mk_pk_bytes(), SK_B = x.mk_sk_bytes(), CT_B = x.mk_ct_bytes();
|
|
31
|
+
let mem = new Uint8Array(x.memory.buffer);
|
|
32
|
+
const view = () => (mem.buffer === x.memory.buffer ? mem : (mem = new Uint8Array(x.memory.buffer)));
|
|
33
|
+
|
|
34
|
+
export const mlkem768 = {
|
|
35
|
+
publicKeyBytes: PK_B, secretKeyBytes: SK_B, cipherTextBytes: CT_B, sharedSecretBytes: 32,
|
|
36
|
+
/** keygen(seed?) — seed is d||z (64 bytes) for ML-KEM.KeyGen_internal; omitted = fresh CSPRNG */
|
|
37
|
+
keygen(seed) {
|
|
38
|
+
if (seed === undefined) crypto.getRandomValues((seed = new Uint8Array(64)));
|
|
39
|
+
if (seed.length !== 64) throw new RangeError('seed must be 64 bytes (d||z)');
|
|
40
|
+
const m = view();
|
|
41
|
+
m.set(seed, COINS);
|
|
42
|
+
if (x.mk_keygen() !== 0) throw new Error('mlkem768: keygen failed');
|
|
43
|
+
return { publicKey: m.slice(PK, PK + PK_B), secretKey: m.slice(SK, SK + SK_B) };
|
|
44
|
+
},
|
|
45
|
+
/** encapsulate(publicKey, msg?) — msg is m (32 bytes) for ML-KEM.Encaps_internal */
|
|
46
|
+
encapsulate(publicKey, msg) {
|
|
47
|
+
if (publicKey.length !== PK_B) throw new RangeError('bad public key length');
|
|
48
|
+
if (msg === undefined) crypto.getRandomValues((msg = new Uint8Array(32)));
|
|
49
|
+
if (msg.length !== 32) throw new RangeError('msg must be 32 bytes');
|
|
50
|
+
const m = view();
|
|
51
|
+
m.set(publicKey, PK);
|
|
52
|
+
m.set(msg, MSGBUF);
|
|
53
|
+
if (x.mk_encaps() !== 0) throw new Error('mlkem768: invalid public key (FIPS 203 7.2 modulus check)');
|
|
54
|
+
return { cipherText: m.slice(CT, CT + CT_B), sharedSecret: m.slice(SS, SS + 32) };
|
|
55
|
+
},
|
|
56
|
+
/** decapsulate(cipherText, secretKey) -> sharedSecret (implicit rejection per FIPS 203) */
|
|
57
|
+
decapsulate(cipherText, secretKey) {
|
|
58
|
+
if (cipherText.length !== CT_B) throw new RangeError('bad ciphertext length');
|
|
59
|
+
if (secretKey.length !== SK_B) throw new RangeError('bad secret key length');
|
|
60
|
+
const m = view();
|
|
61
|
+
m.set(cipherText, CT);
|
|
62
|
+
m.set(secretKey, SK);
|
|
63
|
+
if (x.mk_decaps() !== 0) throw new Error('mlkem768: invalid secret key (FIPS 203 7.3 hash check)');
|
|
64
|
+
return m.slice(SS, SS + 32);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
package/src/profiles.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Fingerprint profiles: one coherent network identity, instead of a dozen knobs that can disagree.
|
|
2
|
+
//
|
|
3
|
+
// Every field a fingerprinter reads is individually configurable — cipher list, groups, signature
|
|
4
|
+
// algorithms, ALPN, TLS versions, ClientHello extension order, GREASE, request header order,
|
|
5
|
+
// HTTP/2 SETTINGS, pseudo-header order, HPACK indexing, Accept-Encoding. That is necessary and it
|
|
6
|
+
// is also a trap: nothing stopped a caller assembling a Chrome User-Agent on top of curl's TLS and
|
|
7
|
+
// curl's HTTP/2, which is a combination no real client produces and a detector reads instantly.
|
|
8
|
+
//
|
|
9
|
+
// A profile is the whole identity or none of it. It supplies defaults for every layer at once, and
|
|
10
|
+
// it declares what it REQUIRES — because a profile that quietly drops the half of itself this
|
|
11
|
+
// runtime cannot perform would recreate exactly the incoherence it exists to prevent.
|
|
12
|
+
//
|
|
13
|
+
// The values are captured, not recalled. curl 8.21.0 / OpenSSL 3.6.3 and Chromium, both read off
|
|
14
|
+
// the wire on 2026-08-01. See test/tls/fingerprint.test.js and test/tls/grease.test.js.
|
|
15
|
+
|
|
16
|
+
import { ConfigError, codes } from './errors.js';
|
|
17
|
+
import { CURL_EXTENSION_ORDER, SHUFFLE_EXTENSIONS } from './tls/handshake-messages.js';
|
|
18
|
+
import { CURL_HEADER_ORDER } from './client/header-order.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} FingerprintProfile
|
|
22
|
+
* @property {string} name
|
|
23
|
+
* @property {object} [tls] merged into `tls`
|
|
24
|
+
* @property {readonly string[]} [headerOrder]
|
|
25
|
+
* @property {Array<[number, number]>} [http2Settings]
|
|
26
|
+
* @property {string[]} [http2PseudoHeaderOrder]
|
|
27
|
+
* @property {Record<string, string>} [http2HpackIndexing]
|
|
28
|
+
* @property {Array<[string, string]>} [headers] default request headers, in order
|
|
29
|
+
* @property {string[]} [requires] capabilities the caller must inject for this identity to be
|
|
30
|
+
* honest: `'cipher:chacha20'`, `'group:x25519mlkem768'`, `'decoder:br'`, `'decoder:zstd'`
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* curl 8.21.0 / OpenSSL 3.6.3. Complete: every layer was captured, and everything it offers is
|
|
35
|
+
* something this package can actually perform. This is the default identity.
|
|
36
|
+
*/
|
|
37
|
+
export const curl = Object.freeze({
|
|
38
|
+
name: 'curl/8.21.0',
|
|
39
|
+
tls: Object.freeze({
|
|
40
|
+
alpn: ['h2', 'http/1.1'],
|
|
41
|
+
extensionOrder: CURL_EXTENSION_ORDER,
|
|
42
|
+
grease: false, // curl does not GREASE
|
|
43
|
+
}),
|
|
44
|
+
headerOrder: CURL_HEADER_ORDER,
|
|
45
|
+
headers: Object.freeze([['User-Agent', 'curl/8.21.0']]),
|
|
46
|
+
// Captured: MAX_CONCURRENT_STREAMS, INITIAL_WINDOW_SIZE, ENABLE_PUSH, in that order.
|
|
47
|
+
http2Settings: Object.freeze([[3, 100], [4, 10485760], [2, 0]]),
|
|
48
|
+
http2PseudoHeaderOrder: Object.freeze([':method', ':scheme', ':authority', ':path']),
|
|
49
|
+
http2HpackIndexing: Object.freeze({ ':path': 'without' }),
|
|
50
|
+
requires: Object.freeze([]),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Chromium, TLS layer captured off the wire.
|
|
55
|
+
*
|
|
56
|
+
* INCOMPLETE ON PURPOSE, and it refuses to be used as though it were not. Two things are missing
|
|
57
|
+
* and neither can be papered over:
|
|
58
|
+
*
|
|
59
|
+
* * Chromium offers TLS_CHACHA20_POLY1305_SHA256 and the X25519MLKEM768 group, and this package
|
|
60
|
+
* implements neither. A ClientHello is an OFFER: a server may take either, and a client that
|
|
61
|
+
* then cannot complete the handshake has traded a fingerprint mismatch for a dead connection.
|
|
62
|
+
* Both are reachable by injection, which is why they are listed in `requires` rather than
|
|
63
|
+
* silently dropped.
|
|
64
|
+
* * Chromium's HTTP/2 preface was not captured — capturing it needs a TLS server the browser
|
|
65
|
+
* will trust, which is a different exercise. So this profile carries no h2 layer, and using it
|
|
66
|
+
* with HTTP/2 enabled would produce a Chromium ClientHello above a curl h2 preface: precisely
|
|
67
|
+
* the split identity a profile exists to prevent.
|
|
68
|
+
*
|
|
69
|
+
* `applyProfile` refuses both cases with a message naming what is missing.
|
|
70
|
+
*/
|
|
71
|
+
export const chrome = Object.freeze({
|
|
72
|
+
name: 'chrome/150',
|
|
73
|
+
tls: Object.freeze({
|
|
74
|
+
// Chromium's list, in Chromium's order, RESTRICTED to what this package can perform. It offers
|
|
75
|
+
// sixteen; the eight left out are TLS 1.2 CBC, RSA key exchange and the 1.2 ChaCha20 suites,
|
|
76
|
+
// none of which this package implements. Listing them would have been the exact dishonesty the
|
|
77
|
+
// requires-check exists to prevent: in a 1.3 handshake they are ignored, but a 1.2 server can
|
|
78
|
+
// select one and get a dead connection. 0x1303 is present because ChaCha20 is injectable and
|
|
79
|
+
// this profile requires it.
|
|
80
|
+
ciphers: Object.freeze([0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030]),
|
|
81
|
+
groups: Object.freeze([0x11ec, 0x001d, 0x0017, 0x0018]),
|
|
82
|
+
// Chrome sends real key_shares for X25519MLKEM768 and X25519 (a GREASE entry leads, added by
|
|
83
|
+
// the grease option). Both must be generated, so both are named here; the hybrid entry is
|
|
84
|
+
// stripped, and this whole profile refused, unless an ML-KEM implementation was injected.
|
|
85
|
+
offerGroups: Object.freeze([0x11ec, 0x001d]),
|
|
86
|
+
sigSchemes: Object.freeze([0x0403, 0x0804, 0x0401, 0x0503, 0x0805, 0x0501, 0x0806, 0x0601]),
|
|
87
|
+
alpn: ['h2', 'http/1.1'],
|
|
88
|
+
// Measured: two hellos, identical extension set, entirely different orders. Chromium shuffles.
|
|
89
|
+
extensionOrder: SHUFFLE_EXTENSIONS,
|
|
90
|
+
grease: true,
|
|
91
|
+
}),
|
|
92
|
+
// Captured off the wire the same way as the TLS layer: Chrome 150 driven at this package's own
|
|
93
|
+
// TLS test server with --ignore-certificate-errors, so no root CA was installed anywhere. The
|
|
94
|
+
// ClientHello precedes certificate validation and ALPN is negotiated inside the handshake, so
|
|
95
|
+
// both fingerprints are exactly what the browser normally sends.
|
|
96
|
+
http2Settings: Object.freeze([[1, 65536], [2, 0], [4, 6291456], [6, 262144]]),
|
|
97
|
+
http2ConnectionWindow: 15663105 + 65535,
|
|
98
|
+
// m,a,s,p — NOT curl's m,s,a,p. Measured, and a difference that would have been easy to miss.
|
|
99
|
+
http2PseudoHeaderOrder: Object.freeze([':method', ':authority', ':scheme', ':path']),
|
|
100
|
+
headerOrder: Object.freeze([
|
|
101
|
+
'host',
|
|
102
|
+
'sec-ch-ua', 'sec-ch-ua-mobile', 'sec-ch-ua-platform',
|
|
103
|
+
'upgrade-insecure-requests', 'user-agent', 'accept',
|
|
104
|
+
'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-user', 'sec-fetch-dest',
|
|
105
|
+
'accept-encoding', 'accept-language', 'priority',
|
|
106
|
+
'*',
|
|
107
|
+
'content-length', 'content-type',
|
|
108
|
+
]),
|
|
109
|
+
headers: Object.freeze([['Accept-Encoding', 'gzip, deflate, br, zstd']]),
|
|
110
|
+
// http2:captured is gone — it is captured now. What remains is what this package cannot yet
|
|
111
|
+
// PERFORM, which is a different kind of gap and the only kind that can make an offer dishonest.
|
|
112
|
+
requires: Object.freeze([
|
|
113
|
+
'cipher:chacha20',
|
|
114
|
+
'group:x25519mlkem768',
|
|
115
|
+
'decoder:br',
|
|
116
|
+
'decoder:zstd',
|
|
117
|
+
]),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
/** @type {Record<string, FingerprintProfile>} */
|
|
121
|
+
export const profiles = Object.freeze({ curl, chrome });
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Fold a profile into a Client's options, and refuse an identity that cannot be honoured.
|
|
125
|
+
*
|
|
126
|
+
* Explicit options WIN over the profile: a caller who names a field meant to name it, and silently
|
|
127
|
+
* overriding them would make the profile impossible to adjust. The profile fills what was not said.
|
|
128
|
+
*
|
|
129
|
+
* @param {object} options as given to the Client
|
|
130
|
+
* @returns {object} options with the profile folded in
|
|
131
|
+
*/
|
|
132
|
+
export function applyProfile(options) {
|
|
133
|
+
const p = options.profile;
|
|
134
|
+
if (!p) return options;
|
|
135
|
+
if (typeof p !== 'object' || !p.name) {
|
|
136
|
+
throw new ConfigError(
|
|
137
|
+
codes.CONFIG_INVALID,
|
|
138
|
+
'profile must be a fingerprint profile object; see `profiles` for the built-in ones',
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// A profile may carry its own implementations — `tunnelfetch/profile/chrome` bundles the two
|
|
143
|
+
// WASM primitives, and importing it is the opt-in. So a requirement is satisfied by either the
|
|
144
|
+
// caller's options OR the profile itself; checking only the options made a self-sufficient
|
|
145
|
+
// profile refuse itself.
|
|
146
|
+
const supplied = (kind, what) =>
|
|
147
|
+
Boolean(options[kind]?.[what] ?? p[kind]?.[what]);
|
|
148
|
+
const missing = [];
|
|
149
|
+
for (const need of p.requires ?? []) {
|
|
150
|
+
const [kind, what] = need.split(':');
|
|
151
|
+
if (kind === 'decoder' && !supplied('decoders', what)) missing.push(need);
|
|
152
|
+
if (kind === 'cipher' && !supplied('ciphers', what)) missing.push(need);
|
|
153
|
+
if (kind === 'group' && !supplied('groups', what)) missing.push(need);
|
|
154
|
+
// A profile with no captured h2 layer must not be run over HTTP/2, or it presents this
|
|
155
|
+
// identity's ClientHello above a different client's preface.
|
|
156
|
+
if (kind === 'http2' && options.http2 !== false) missing.push(need);
|
|
157
|
+
}
|
|
158
|
+
if (missing.length) {
|
|
159
|
+
throw new ConfigError(
|
|
160
|
+
codes.CONFIG_INVALID,
|
|
161
|
+
`the "${p.name}" profile cannot be presented honestly: ${missing.join(', ')} ` +
|
|
162
|
+
`${missing.length === 1 ? 'is' : 'are'} missing. A fingerprint field this package cannot ` +
|
|
163
|
+
'perform is an offer a server may take and then find unhonoured, which fails the ' +
|
|
164
|
+
'connection rather than merely looking wrong. For the Chrome identity with its two WASM ' +
|
|
165
|
+
"primitives already wired in, import { chrome } from 'tunnelfetch/profile/chrome'; " +
|
|
166
|
+
'otherwise supply the missing pieces yourself through `decoders`, `ciphers` and `groups`.',
|
|
167
|
+
{ profile: p.name, missing },
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const out = { ...options };
|
|
172
|
+
if (p.tls) out.tls = { ...p.tls, ...(options.tls ?? {}) };
|
|
173
|
+
// Implementations the profile brings, with the caller's taking precedence.
|
|
174
|
+
for (const kind of ['ciphers', 'groups', 'decoders']) {
|
|
175
|
+
if (p[kind]) out[kind] = { ...p[kind], ...(options[kind] ?? {}) };
|
|
176
|
+
}
|
|
177
|
+
for (const key of ['headerOrder', 'http2Settings', 'http2PseudoHeaderOrder', 'http2HpackIndexing']) {
|
|
178
|
+
if (options[key] === undefined && p[key] != null) out[key] = p[key];
|
|
179
|
+
}
|
|
180
|
+
// Profile headers are DEFAULTS: a request that sets its own User-Agent keeps it. They are folded
|
|
181
|
+
// in per request rather than here, so this only records them.
|
|
182
|
+
if (p.headers) out.profileHeaders = p.headers;
|
|
183
|
+
return out;
|
|
184
|
+
}
|