@browsercore/testing 0.1.2 → 0.2.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 +5 -0
- package/captures/DIVERGENCE_REPORT.md +325 -0
- package/captures/IMPERSIONATION_GAPS_REPORT.md +367 -0
- package/captures/README.md +56 -0
- package/captures/REVIEW_FINDINGS.md +71 -0
- package/captures/_probe/analyze.py +67 -0
- package/captures/_probe/capture_bytes.py +127 -0
- package/captures/_probe/chrome131_determinism.py +32 -0
- package/captures/_probe/diagnose_capture.py +59 -0
- package/captures/_probe/golden_analysis.py +91 -0
- package/captures/_probe/inspect_golden.py +55 -0
- package/captures/_probe/inspect_sv.py +16 -0
- package/captures/_probe/make_golden.py +170 -0
- package/captures/_probe/output/chrome100.json +219 -0
- package/captures/_probe/output/chrome101.json +219 -0
- package/captures/_probe/output/chrome104.json +219 -0
- package/captures/_probe/output/chrome107.json +220 -0
- package/captures/_probe/output/chrome110.json +220 -0
- package/captures/_probe/output/chrome116.json +220 -0
- package/captures/_probe/output/chrome119.json +219 -0
- package/captures/_probe/output/chrome120.json +219 -0
- package/captures/_probe/output/chrome123.json +223 -0
- package/captures/_probe/output/chrome124.json +224 -0
- package/captures/_probe/output/chrome131.json +224 -0
- package/captures/_probe/output/chrome131_fresh.json +224 -0
- package/captures/_probe/output/chrome133a.json +224 -0
- package/captures/_probe/output/chrome136.json +224 -0
- package/captures/_probe/output/chrome99.json +219 -0
- package/captures/_probe/output/edge101.json +219 -0
- package/captures/_probe/output/edge99.json +219 -0
- package/captures/_probe/output/firefox133.json +227 -0
- package/captures/_probe/output/firefox135.json +230 -0
- package/captures/_probe/output/safari155.json +210 -0
- package/captures/_probe/output/safari170.json +214 -0
- package/captures/_probe/output/safari170_fresh.json +214 -0
- package/captures/_probe/output/safari180.json +216 -0
- package/captures/_probe/output/safari180_ios.json +216 -0
- package/captures/_probe/output/safari184.json +215 -0
- package/captures/_probe/output/safari260.json +211 -0
- package/captures/_probe/output/summary.json +2520 -0
- package/captures/_probe/parse_existing_settings.py +15 -0
- package/captures/_probe/peetprint.py +39 -0
- package/captures/_probe/probe.py +137 -0
- package/captures/_probe/raw_bytes/chrome-131_client_hello.bin +0 -0
- package/captures/_probe/raw_bytes/chrome-131_client_hello.hex +32 -0
- package/captures/_probe/raw_bytes/firefox-133_client_hello.bin +0 -0
- package/captures/_probe/raw_bytes/firefox-133_client_hello.hex +32 -0
- package/captures/_probe/raw_bytes/safari-17_client_hello.bin +0 -0
- package/captures/_probe/raw_bytes/safari-17_client_hello.hex +32 -0
- package/captures/_probe/relay_capture.py +137 -0
- package/captures/_probe/socks_capture.py +138 -0
- package/captures/_probe/validate_fresh.py +66 -0
- package/captures/_probe/validate_golden.py +97 -0
- package/captures/_probe/verify_capture.py +68 -0
- package/captures/chrome-131/http2/settings.bin +0 -0
- package/captures/chrome-131/http2/settings.meta.json +9 -0
- package/captures/chrome-131/oracle_capture.reference.json +224 -0
- package/captures/chrome-131/tls/client_hello.bin +0 -0
- package/captures/chrome-131/tls/client_hello.meta.json +20 -0
- package/captures/chrome-140/http2/settings.bin +0 -0
- package/captures/chrome-140/http2/settings.meta.json +9 -0
- package/captures/chrome-140/tls/client_hello.bin +0 -0
- package/captures/chrome-140/tls/client_hello.meta.json +12 -0
- package/captures/firefox-128/tls/client_hello.bin +0 -0
- package/captures/firefox-128/tls/client_hello.meta.json +12 -0
- package/captures/firefox-133/http2/settings.bin +0 -0
- package/captures/firefox-133/http2/settings.meta.json +9 -0
- package/captures/firefox-133/oracle_capture.reference.json +227 -0
- package/captures/firefox-133/tls/client_hello.bin +0 -0
- package/captures/firefox-133/tls/client_hello.meta.json +20 -0
- package/captures/safari-17/http2/settings.bin +0 -0
- package/captures/safari-17/http2/settings.meta.json +9 -0
- package/captures/safari-17/oracle_capture.reference.json +214 -0
- package/captures/safari-17/tls/client_hello.bin +0 -0
- package/captures/safari-17/tls/client_hello.meta.json +20 -0
- package/dist/bench/bench.d.ts +22 -6
- package/dist/bench/bench.d.ts.map +1 -1
- package/dist/bench/bench.js +105 -10
- package/dist/bench/bench.js.map +1 -1
- package/dist/captures/manifest.d.ts.map +1 -1
- package/dist/captures/manifest.js +2 -3
- package/dist/captures/manifest.js.map +1 -1
- package/dist/categories/compression.d.ts +5 -2
- package/dist/categories/compression.d.ts.map +1 -1
- package/dist/categories/compression.js +54 -6
- package/dist/categories/compression.js.map +1 -1
- package/dist/categories/cookies.d.ts +3 -2
- package/dist/categories/cookies.d.ts.map +1 -1
- package/dist/categories/cookies.js +228 -11
- package/dist/categories/cookies.js.map +1 -1
- package/dist/categories/redirects.d.ts +8 -2
- package/dist/categories/redirects.d.ts.map +1 -1
- package/dist/categories/redirects.js +97 -12
- package/dist/categories/redirects.js.map +1 -1
- package/dist/e2e/cert-gen.d.ts +30 -0
- package/dist/e2e/cert-gen.d.ts.map +1 -0
- package/dist/e2e/cert-gen.js +158 -0
- package/dist/e2e/cert-gen.js.map +1 -0
- package/dist/e2e/parse-clienthello.d.ts +177 -0
- package/dist/e2e/parse-clienthello.d.ts.map +1 -0
- package/dist/e2e/parse-clienthello.js +343 -0
- package/dist/e2e/parse-clienthello.js.map +1 -0
- package/dist/e2e/sink-server.d.ts +109 -0
- package/dist/e2e/sink-server.d.ts.map +1 -0
- package/dist/e2e/sink-server.js +292 -0
- package/dist/e2e/sink-server.js.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/fingerprint/index.d.ts +5 -2
- package/dist/fingerprint/index.d.ts.map +1 -1
- package/dist/fingerprint/index.js +3 -2
- package/dist/fingerprint/index.js.map +1 -1
- package/dist/fingerprint/ja3.d.ts.map +1 -1
- package/dist/fingerprint/ja3.js +33 -4
- package/dist/fingerprint/ja3.js.map +1 -1
- package/dist/fingerprint/ja4-errors.d.ts +17 -0
- package/dist/fingerprint/ja4-errors.d.ts.map +1 -0
- package/dist/fingerprint/ja4-errors.js +20 -0
- package/dist/fingerprint/ja4-errors.js.map +1 -0
- package/dist/fingerprint/ja4-reader.d.ts +44 -0
- package/dist/fingerprint/ja4-reader.d.ts.map +1 -0
- package/dist/fingerprint/ja4-reader.js +112 -0
- package/dist/fingerprint/ja4-reader.js.map +1 -0
- package/dist/fingerprint/ja4.d.ts +11 -43
- package/dist/fingerprint/ja4.d.ts.map +1 -1
- package/dist/fingerprint/ja4.js +54 -141
- package/dist/fingerprint/ja4.js.map +1 -1
- package/dist/fingerprint/ja4h.d.ts +46 -0
- package/dist/fingerprint/ja4h.d.ts.map +1 -0
- package/dist/fingerprint/ja4h.js +50 -0
- package/dist/fingerprint/ja4h.js.map +1 -0
- package/dist/golden/golden.d.ts +15 -1
- package/dist/golden/golden.d.ts.map +1 -1
- package/dist/golden/golden.js +35 -22
- package/dist/golden/golden.js.map +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -1
- package/dist/index.js.map +1 -1
- package/dist/reference/browser-provider.d.ts +33 -0
- package/dist/reference/browser-provider.d.ts.map +1 -0
- package/dist/reference/browser-provider.js +60 -0
- package/dist/reference/browser-provider.js.map +1 -0
- package/dist/reference/curl-provider.d.ts +40 -0
- package/dist/reference/curl-provider.d.ts.map +1 -0
- package/dist/reference/curl-provider.js +96 -0
- package/dist/reference/curl-provider.js.map +1 -0
- package/dist/reference/dump.d.ts +42 -0
- package/dist/reference/dump.d.ts.map +1 -0
- package/dist/reference/dump.js +102 -0
- package/dist/reference/dump.js.map +1 -0
- package/dist/reference/node-reference.d.ts.map +1 -1
- package/dist/reference/node-reference.js +2 -5
- package/dist/reference/node-reference.js.map +1 -1
- package/dist/reference/reference-errors.d.ts +36 -0
- package/dist/reference/reference-errors.d.ts.map +1 -0
- package/dist/reference/reference-errors.js +43 -0
- package/dist/reference/reference-errors.js.map +1 -0
- package/dist/reference/reference-types.d.ts +33 -0
- package/dist/reference/reference-types.d.ts.map +1 -0
- package/dist/reference/reference-types.js +9 -0
- package/dist/reference/reference-types.js.map +1 -0
- package/dist/reference/reference.d.ts +14 -77
- package/dist/reference/reference.d.ts.map +1 -1
- package/dist/reference/reference.js +43 -207
- package/dist/reference/reference.js.map +1 -1
- package/dist/rfc/rfcTests.d.ts +46 -8
- package/dist/rfc/rfcTests.d.ts.map +1 -1
- package/dist/rfc/rfcTests.js +203 -16
- package/dist/rfc/rfcTests.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -5
- package/dist/utils.js.map +1 -1
- package/package.json +61 -50
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"golden.d.ts","sourceRoot":"","sources":["../../src/golden/golden.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"golden.d.ts","sourceRoot":"","sources":["../../src/golden/golden.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EACR,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,aAAa,EACb,eAAe,EAClB,MAAM,aAAa,CAAC;AA8BrB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CAgD7E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,eAAe,EAAE,CA+BjG;AAYD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,aAAa,CA2B9D;AAoBD,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,WAAW,CAUjE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,GAAG,gBAAgB,CAa/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC1C,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,SAAS,GACrB,0BAA0B,CAe5B"}
|
package/dist/golden/golden.js
CHANGED
|
@@ -12,16 +12,15 @@
|
|
|
12
12
|
* `captures/<profile>/<protocol>/<record>.{bin,meta.json}` layout.
|
|
13
13
|
*/
|
|
14
14
|
import { readFileSync } from "node:fs";
|
|
15
|
-
import {
|
|
16
|
-
import { dirname, join } from "node:path";
|
|
15
|
+
import { join } from "node:path";
|
|
17
16
|
import { compareBytes, compareBytesWithIgnore } from "../utils.js";
|
|
18
17
|
import { GoldenMismatchError, TestingError } from "../errors.js";
|
|
19
|
-
const here =
|
|
18
|
+
const here = import.meta.dirname;
|
|
20
19
|
// src/golden -> package root -> captures/
|
|
21
20
|
const capturesDir = join(here, "..", "..", "captures");
|
|
22
21
|
/** Parse a CaptureId of the form `${profile}/${protocol}/${record}`. */
|
|
23
22
|
function parseCaptureId(captureId) {
|
|
24
|
-
const EXPECTED_FORMAT =
|
|
23
|
+
const EXPECTED_FORMAT = `\${profile}/\${protocol}/\${record}`;
|
|
25
24
|
const parts = captureId.split("/");
|
|
26
25
|
if (parts.length !== 3) {
|
|
27
26
|
throw new TestingError(`Malformed CaptureId "${captureId}" — expected ${EXPECTED_FORMAT}`);
|
|
@@ -32,39 +31,44 @@ function parseCaptureId(captureId) {
|
|
|
32
31
|
}
|
|
33
32
|
return { profile, protocol, record };
|
|
34
33
|
}
|
|
35
|
-
/**
|
|
36
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Validate unknown JSON data as a {@link CaptureMeta} (no zod dep here).
|
|
36
|
+
*
|
|
37
|
+
* Exported for unit testing the validation branches — the error paths are only
|
|
38
|
+
* reachable with a malformed sidecar, which the on-disk captures are not.
|
|
39
|
+
*/
|
|
40
|
+
export function parseCaptureMeta(raw, captureId) {
|
|
37
41
|
if (typeof raw !== "object" || raw === null) {
|
|
38
42
|
throw new TestingError(`Capture meta for ${captureId} is not an object`);
|
|
39
43
|
}
|
|
40
44
|
const obj = raw;
|
|
41
|
-
const source = obj
|
|
45
|
+
const source = obj["source"];
|
|
42
46
|
if (source !== "curl-impersonate" && source !== "real-browser") {
|
|
43
47
|
throw new TestingError(`Capture meta for ${captureId} has invalid source: ${String(source)}`);
|
|
44
48
|
}
|
|
45
|
-
const protocol = obj
|
|
49
|
+
const protocol = obj["protocol"];
|
|
46
50
|
if (protocol !== "tls" && protocol !== "http2" && protocol !== "http1" && protocol !== "tcp") {
|
|
47
51
|
throw new TestingError(`Capture meta for ${captureId} has invalid protocol: ${String(protocol)}`);
|
|
48
52
|
}
|
|
49
|
-
const record = obj
|
|
53
|
+
const record = obj["record"];
|
|
50
54
|
if (record !== "client_hello" &&
|
|
51
55
|
record !== "settings" &&
|
|
52
56
|
record !== "headers" &&
|
|
53
57
|
record !== "server_hello") {
|
|
54
58
|
throw new TestingError(`Capture meta for ${captureId} has invalid record: ${String(record)}`);
|
|
55
59
|
}
|
|
56
|
-
const description = obj
|
|
60
|
+
const description = obj["description"];
|
|
57
61
|
if (typeof description !== "string") {
|
|
58
62
|
throw new TestingError(`Capture meta for ${captureId} has non-string description`);
|
|
59
63
|
}
|
|
60
|
-
const createdAt = obj
|
|
64
|
+
const createdAt = obj["createdAt"];
|
|
61
65
|
if (typeof createdAt !== "string") {
|
|
62
66
|
throw new TestingError(`Capture meta for ${captureId} has non-string createdAt`);
|
|
63
67
|
}
|
|
64
|
-
const randomizedFields = parseRandomizedFields(obj
|
|
68
|
+
const randomizedFields = parseRandomizedFields(obj["randomizedFields"], captureId);
|
|
65
69
|
return {
|
|
66
70
|
source,
|
|
67
|
-
profile: obj
|
|
71
|
+
profile: obj["profile"],
|
|
68
72
|
protocol,
|
|
69
73
|
record,
|
|
70
74
|
description,
|
|
@@ -72,8 +76,13 @@ function parseCaptureMeta(raw, captureId) {
|
|
|
72
76
|
createdAt,
|
|
73
77
|
};
|
|
74
78
|
}
|
|
75
|
-
/**
|
|
76
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Validate unknown data as a list of {@link RandomizedField}.
|
|
81
|
+
*
|
|
82
|
+
* Exported for unit testing the validation branches — the error paths are only
|
|
83
|
+
* reachable with a malformed sidecar, which the on-disk captures are not.
|
|
84
|
+
*/
|
|
85
|
+
export function parseRandomizedFields(raw, captureId) {
|
|
77
86
|
if (!Array.isArray(raw)) {
|
|
78
87
|
throw new TestingError(`Capture meta for ${captureId} has non-array randomizedFields`);
|
|
79
88
|
}
|
|
@@ -82,15 +91,15 @@ function parseRandomizedFields(raw, captureId) {
|
|
|
82
91
|
throw new TestingError(`Capture meta for ${captureId} randomizedFields[${i}] is not an object`);
|
|
83
92
|
}
|
|
84
93
|
const obj = item;
|
|
85
|
-
const byteOffset = obj
|
|
94
|
+
const byteOffset = obj["byteOffset"];
|
|
86
95
|
if (typeof byteOffset !== "number" || byteOffset < 0) {
|
|
87
96
|
throw new TestingError(`Capture meta for ${captureId} randomizedFields[${i}].byteOffset invalid`);
|
|
88
97
|
}
|
|
89
|
-
const length = obj
|
|
98
|
+
const length = obj["length"];
|
|
90
99
|
if (typeof length !== "number" || length < 0) {
|
|
91
100
|
throw new TestingError(`Capture meta for ${captureId} randomizedFields[${i}].length invalid`);
|
|
92
101
|
}
|
|
93
|
-
const reason = obj
|
|
102
|
+
const reason = obj["reason"];
|
|
94
103
|
if (reason !== "ephemeral_key" && reason !== "nonce" && reason !== "grease" && reason !== "random") {
|
|
95
104
|
throw new TestingError(`Capture meta for ${captureId} randomizedFields[${i}].reason invalid: ${String(reason)}`);
|
|
96
105
|
}
|
|
@@ -141,14 +150,18 @@ export function loadGolden(captureId) {
|
|
|
141
150
|
/** Derive a {@link CaptureSource} from a profile id (best-effort). */
|
|
142
151
|
function parseSource(profile) {
|
|
143
152
|
const p = String(profile);
|
|
144
|
-
if (p.startsWith("chrome"))
|
|
153
|
+
if (p.startsWith("chrome")) {
|
|
145
154
|
return "chrome-140";
|
|
146
|
-
|
|
155
|
+
}
|
|
156
|
+
if (p.startsWith("firefox")) {
|
|
147
157
|
return "firefox-135";
|
|
148
|
-
|
|
158
|
+
}
|
|
159
|
+
if (p.startsWith("safari")) {
|
|
149
160
|
return "safari-18";
|
|
150
|
-
|
|
161
|
+
}
|
|
162
|
+
if (p.startsWith("edge")) {
|
|
151
163
|
return "edge-140";
|
|
164
|
+
}
|
|
152
165
|
return "chrome-140";
|
|
153
166
|
}
|
|
154
167
|
/** Load the {@link CaptureMeta} sidecar for a capture. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"golden.js","sourceRoot":"","sources":["../../src/golden/golden.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"golden.js","sourceRoot":"","sources":["../../src/golden/golden.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Protocol verification: RFC compliance tests, browser golden packet captures,
|
|
5
5
|
* integration tests, and benchmarking.
|
|
6
6
|
*/
|
|
7
|
+
import type { CaptureEntry } from "./captures/manifest.js";
|
|
7
8
|
export { loadGolden, compareAgainstGolden } from "./golden/golden.js";
|
|
8
9
|
export { runTlsCompliance, runHttp2Compliance, runHttp1Compliance } from "./rfc/rfcTests.js";
|
|
9
10
|
export { benchmarkTlsHandshake, benchmarkHttp2Request } from "./bench/bench.js";
|
|
@@ -15,11 +16,26 @@ export type { SpecTestCase, TestCategoryId, TestRun, TestStatus } from "./types.
|
|
|
15
16
|
export * as categories from "./categories/index.js";
|
|
16
17
|
export { compareBytesWithIgnore } from "./utils.js";
|
|
17
18
|
export type { CaptureMeta, ComparisonResultWithIgnore, RandomizedField } from "./types.js";
|
|
18
|
-
export {
|
|
19
|
+
export type { CaptureEntry } from "./captures/manifest.js";
|
|
20
|
+
/**
|
|
21
|
+
* Lazily load the golden-capture manifest.
|
|
22
|
+
*
|
|
23
|
+
* The manifest reads each `.bin` from disk, so it is NOT eagerly evaluated at
|
|
24
|
+
* import time (an eager re-export would force every consumer to pay the read
|
|
25
|
+
* cost — and crash if the tarball lacked `captures/`). Call this only when you
|
|
26
|
+
* actually need the captures.
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadCaptures(): Promise<readonly CaptureEntry[]>;
|
|
19
29
|
export { createReferenceProvider, CurlImpersonateProvider, RealBrowserCaptureProvider, } from "./reference/reference.js";
|
|
20
30
|
export type { CurlImpersonateOptions, Fingerprint, RealBrowserOptions, ReferenceProvider, ReferenceProviderKind, } from "./reference/reference.js";
|
|
21
31
|
export { computeJa3, computeJa4, Ja3ParseError, parseClientHello } from "./fingerprint/index.js";
|
|
22
32
|
export type { Ja3Segments } from "./fingerprint/index.js";
|
|
23
33
|
export { nodeCrypto, nodeDns, nodeZlib, nodeHttp, toError, compareBytesOutcome, } from "./reference/node-reference.js";
|
|
24
34
|
export type { CompareOutcome, HashAlgorithm } from "./reference/node-reference.js";
|
|
35
|
+
export { TlsSinkServer } from "./e2e/sink-server.js";
|
|
36
|
+
export type { ClientHelloCapture, HandshakeResult } from "./e2e/sink-server.js";
|
|
37
|
+
export { generateSelfSignedCert } from "./e2e/cert-gen.js";
|
|
38
|
+
export type { SelfSignedCert } from "./e2e/cert-gen.js";
|
|
39
|
+
export { parseClientHelloWire, peekRecordHeader, findExtension, parseSniHostname, parseAlpnProtocols, parseSupportedVersions, decodeSni, decodeAlpn, decodeSupportedVersions, isGrease, nonGreaseCipherSuites, nonGreaseExtensionTypes, EXT, GREASE_SENTINELS, ClientHelloParseError, } from "./e2e/parse-clienthello.js";
|
|
40
|
+
export type { ParsedClientHello, ParsedExtension, ExtensionTypeValue, } from "./e2e/parse-clienthello.js";
|
|
25
41
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhE,YAAY,EACR,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG7E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC3F,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhE,YAAY,EACR,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG7E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC3F,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D;;;;;;;GAOG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAGrE;AAGD,OAAO,EACH,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,GAC7B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACR,sBAAsB,EACtB,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GACxB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACjG,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1D,OAAO,EACH,UAAU,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,mBAAmB,GACtB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAOnF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAOxD,OAAO,EACH,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,uBAAuB,EACvB,QAAQ,EACR,qBAAqB,EACrB,uBAAuB,EACvB,GAAG,EACH,gBAAgB,EAChB,qBAAqB,GACxB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACR,iBAAiB,EACjB,eAAe,EACf,kBAAkB,GACrB,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,18 @@ export { TestCategory } from "./types.js";
|
|
|
14
14
|
export * as categories from "./categories/index.js";
|
|
15
15
|
// Randomized-field comparison (Cat 14 core) + capture manifest.
|
|
16
16
|
export { compareBytesWithIgnore } from "./utils.js";
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Lazily load the golden-capture manifest.
|
|
19
|
+
*
|
|
20
|
+
* The manifest reads each `.bin` from disk, so it is NOT eagerly evaluated at
|
|
21
|
+
* import time (an eager re-export would force every consumer to pay the read
|
|
22
|
+
* cost — and crash if the tarball lacked `captures/`). Call this only when you
|
|
23
|
+
* actually need the captures.
|
|
24
|
+
*/
|
|
25
|
+
export async function loadCaptures() {
|
|
26
|
+
const manifest = await import("./captures/manifest.js");
|
|
27
|
+
return manifest.captures;
|
|
28
|
+
}
|
|
18
29
|
// Pluggable layered reference provider.
|
|
19
30
|
export { createReferenceProvider, CurlImpersonateProvider, RealBrowserCaptureProvider, } from "./reference/reference.js";
|
|
20
31
|
// Fingerprint computation (JA3 / JA4) for Cat 4.
|
|
@@ -22,4 +33,18 @@ export { computeJa3, computeJa4, Ja3ParseError, parseClientHello } from "./finge
|
|
|
22
33
|
// Node.js reference oracle — deterministic comparison target for the primitive
|
|
23
34
|
// layers (crypto, dns, zlib, wire format). See src/reference/node-reference.ts.
|
|
24
35
|
export { nodeCrypto, nodeDns, nodeZlib, nodeHttp, toError, compareBytesOutcome, } from "./reference/node-reference.js";
|
|
36
|
+
// E2E TLS sink server — live handshake verification oracle (plan
|
|
37
|
+
// docs/E2E_TEST_PLAN.md). The sink performs a real TLS 1.3 handshake and
|
|
38
|
+
// returns the raw ClientHello bytes it saw on the wire, plus parsed handshake
|
|
39
|
+
// inspection (protocol, cipher, ALPN, SNI). Reusable by any package that
|
|
40
|
+
// wants to verify its TLS stack against a real server.
|
|
41
|
+
export { TlsSinkServer } from "./e2e/sink-server.js";
|
|
42
|
+
// Self-signed ECDSA P-256 certificate generator (runtime, no openssl).
|
|
43
|
+
export { generateSelfSignedCert } from "./e2e/cert-gen.js";
|
|
44
|
+
// Minimal ClientHello wire parser — structural assertions for the e2e matrix.
|
|
45
|
+
// (Distinct from the JA3 `parseClientHello` re-exported from fingerprint.)
|
|
46
|
+
// Note: `parseClientHello` is intentionally NOT re-exported here to avoid
|
|
47
|
+
// colliding with the JA3 `parseClientHello` from ./fingerprint/index.js.
|
|
48
|
+
// Consumers of the e2e parser import it directly from ./e2e/parse-clienthello.js.
|
|
49
|
+
export { parseClientHelloWire, peekRecordHeader, findExtension, parseSniHostname, parseAlpnProtocols, parseSupportedVersions, decodeSni, decodeAlpn, decodeSupportedVersions, isGrease, nonGreaseCipherSuites, nonGreaseExtensionTypes, EXT, GREASE_SENTINELS, ClientHelloParseError, } from "./e2e/parse-clienthello.js";
|
|
25
50
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAchE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE7E,sEAAsE;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AAEpD,gEAAgE;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAIpD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;IACxD,OAAO,QAAQ,CAAC,QAAQ,CAAC;AAC7B,CAAC;AAED,wCAAwC;AACxC,OAAO,EACH,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,GAC7B,MAAM,0BAA0B,CAAC;AASlC,iDAAiD;AACjD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAGjG,+EAA+E;AAC/E,gFAAgF;AAChF,OAAO,EACH,UAAU,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,mBAAmB,GACtB,MAAM,+BAA+B,CAAC;AAGvC,iEAAiE;AACjE,yEAAyE;AACzE,8EAA8E;AAC9E,yEAAyE;AACzE,uDAAuD;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,uEAAuE;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,kFAAkF;AAClF,OAAO,EACH,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,uBAAuB,EACvB,QAAQ,EACR,qBAAqB,EACrB,uBAAuB,EACvB,GAAG,EACH,gBAAgB,EAChB,qBAAqB,GACxB,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SECONDARY reference provider — loads pre-recorded captures from `captures/`.
|
|
3
|
+
*
|
|
4
|
+
* `capture()` resolves a stored capture for the profile; `fingerprint()`
|
|
5
|
+
* derives a {@link Fingerprint} from the captured bytes (only TLS ClientHellos
|
|
6
|
+
* are fingerprinted — other protocols throw). Split out of `reference.ts` so
|
|
7
|
+
* the facade stays focused on primary → secondary dispatch.
|
|
8
|
+
*/
|
|
9
|
+
import type { ProfileId } from "@browsercore/profiles";
|
|
10
|
+
import type { GoldenCapture } from "../types.js";
|
|
11
|
+
import type { Fingerprint, ReferenceProvider, ReferenceProviderKind } from "./reference-types.js";
|
|
12
|
+
/** Options for the real-browser (pre-recorded capture) provider. */
|
|
13
|
+
export interface RealBrowserOptions {
|
|
14
|
+
readonly command?: undefined;
|
|
15
|
+
/** Override captures directory. Defaults to the in-repo `captures/` dir. */
|
|
16
|
+
readonly capturesDir?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* SECONDARY provider — loads pre-recorded captures from the `captures/` dir.
|
|
20
|
+
*
|
|
21
|
+
* `capture()` resolves a stored capture for the profile; `fingerprint()`
|
|
22
|
+
* derives a {@link Fingerprint} from the captured bytes (only TLS
|
|
23
|
+
* ClientHellos are fingerprinted — other protocols return a stub).
|
|
24
|
+
*/
|
|
25
|
+
export declare class RealBrowserCaptureProvider implements ReferenceProvider {
|
|
26
|
+
readonly kind: ReferenceProviderKind;
|
|
27
|
+
readonly capturesDir: string;
|
|
28
|
+
constructor(options?: RealBrowserOptions);
|
|
29
|
+
availableProfiles(): ProfileId[];
|
|
30
|
+
capture(profile: ProfileId, _url: string): Promise<GoldenCapture>;
|
|
31
|
+
fingerprint(profile: ProfileId): Promise<Fingerprint>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=browser-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-provider.d.ts","sourceRoot":"","sources":["../../src/reference/browser-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlG,oEAAoE;AACpE,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;GAMG;AACH,qBAAa,0BAA2B,YAAW,iBAAiB;IAChE,SAAgB,IAAI,EAAE,qBAAqB,CAAqC;IAChF,SAAgB,WAAW,EAAE,MAAM,CAAC;IAEpC,YAAY,OAAO,CAAC,EAAE,kBAAkB,EAEvC;IAED,iBAAiB,IAAI,SAAS,EAAE,CAM/B;IAEK,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBtE;IAEK,WAAW,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAQ1D;CACJ"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SECONDARY reference provider — loads pre-recorded captures from `captures/`.
|
|
3
|
+
*
|
|
4
|
+
* `capture()` resolves a stored capture for the profile; `fingerprint()`
|
|
5
|
+
* derives a {@link Fingerprint} from the captured bytes (only TLS ClientHellos
|
|
6
|
+
* are fingerprinted — other protocols throw). Split out of `reference.ts` so
|
|
7
|
+
* the facade stays focused on primary → secondary dispatch.
|
|
8
|
+
*/
|
|
9
|
+
import { ReferenceError } from "./reference-errors.js";
|
|
10
|
+
import { fingerprintFromTlsCapture, profileToSource } from "./dump.js";
|
|
11
|
+
/**
|
|
12
|
+
* SECONDARY provider — loads pre-recorded captures from the `captures/` dir.
|
|
13
|
+
*
|
|
14
|
+
* `capture()` resolves a stored capture for the profile; `fingerprint()`
|
|
15
|
+
* derives a {@link Fingerprint} from the captured bytes (only TLS
|
|
16
|
+
* ClientHellos are fingerprinted — other protocols return a stub).
|
|
17
|
+
*/
|
|
18
|
+
export class RealBrowserCaptureProvider {
|
|
19
|
+
kind = { kind: "real-browser" };
|
|
20
|
+
capturesDir;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.capturesDir = options?.capturesDir ?? defaultCapturesDir;
|
|
23
|
+
}
|
|
24
|
+
availableProfiles() {
|
|
25
|
+
// Discovery is driven by the captures manifest (captures/manifest.ts).
|
|
26
|
+
return [
|
|
27
|
+
"chrome-140",
|
|
28
|
+
"firefox-128",
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
async capture(profile, _url) {
|
|
32
|
+
void _url;
|
|
33
|
+
const manifest = await import("../captures/manifest.js");
|
|
34
|
+
const entry = manifest.captures.find((c) => c.meta.profile === profile);
|
|
35
|
+
if (entry === undefined) {
|
|
36
|
+
throw new ReferenceError(`No pre-recorded capture for profile ${String(profile)}`);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
id: `${profile}/tls/client_hello`,
|
|
40
|
+
source: profileToSource(profile),
|
|
41
|
+
protocol: entry.meta.protocol,
|
|
42
|
+
bytes: entry.bytes,
|
|
43
|
+
description: entry.meta.description,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async fingerprint(profile) {
|
|
47
|
+
const capture = await this.capture(profile, "https://example.com");
|
|
48
|
+
if (capture.protocol !== "tls") {
|
|
49
|
+
throw new ReferenceError(`fingerprint() only supports TLS captures; got ${capture.protocol}`);
|
|
50
|
+
}
|
|
51
|
+
return fingerprintFromTlsCapture(capture);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Default captures dir resolved from this module's location. Computed at module
|
|
55
|
+
// load (not per-instance) since import.meta.dirname is static.
|
|
56
|
+
import { join } from "node:path";
|
|
57
|
+
const here = import.meta.dirname;
|
|
58
|
+
const packageRoot = join(here, "..", "..");
|
|
59
|
+
const defaultCapturesDir = join(packageRoot, "captures");
|
|
60
|
+
//# sourceMappingURL=browser-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-provider.js","sourceRoot":"","sources":["../../src/reference/browser-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AASvE;;;;;;GAMG;AACH,MAAM,OAAO,0BAA0B;IACnB,IAAI,GAA0B,EAAE,IAAI,EAAE,cAAc,EAAW,CAAC;IAChE,WAAW,CAAS;IAEpC,YAAY,OAA4B;QACpC,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,kBAAkB,CAAC;IAClE,CAAC;IAED,iBAAiB;QACb,uEAAuE;QACvE,OAAO;YACH,YAAyB;YACzB,aAA0B;SAC7B,CAAC;IACN,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAkB,EAAE,IAAY;QAC1C,KAAK,IAAI,CAAC;QACV,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,IAAI,cAAc,CACpB,uCAAuC,MAAM,CAAC,OAAO,CAAC,EAAE,CAC3D,CAAC;QACN,CAAC;QACD,OAAO;YACH,EAAE,EAAE,GAAG,OAAO,mBAA0C;YACxD,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC;YAChC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;YAC7B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW;SACtC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAkB;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;QACnE,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC7B,MAAM,IAAI,cAAc,CACpB,iDAAiD,OAAO,CAAC,QAAQ,EAAE,CACtE,CAAC;QACN,CAAC;QACD,OAAO,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;CACJ;AAED,gFAAgF;AAChF,+DAA+D;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,OAAO,CAAC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC3C,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRIMARY reference provider — shells out to curl-impersonate.
|
|
3
|
+
*
|
|
4
|
+
* `capture()` invokes the curl-impersonate binary against `url`, impersonating
|
|
5
|
+
* `profile`, and returns the raw bytes it observed on the wire. The binary
|
|
6
|
+
* must be on PATH (or in `command`); if it is missing, the call throws
|
|
7
|
+
* {@link ReferenceError} so the facade can fall back to the secondary.
|
|
8
|
+
*
|
|
9
|
+
* Split out of `reference.ts` so the facade module stays focused on primary →
|
|
10
|
+
* secondary dispatch while this file owns the curl-impersonate subprocess
|
|
11
|
+
* wiring and dump-format parsing.
|
|
12
|
+
*/
|
|
13
|
+
import type { ProfileId } from "@browsercore/profiles";
|
|
14
|
+
import type { GoldenCapture } from "../types.js";
|
|
15
|
+
import type { Fingerprint, ReferenceProvider, ReferenceProviderKind } from "./reference-types.js";
|
|
16
|
+
/** Options for the curl-impersonate provider. */
|
|
17
|
+
export interface CurlImpersonateOptions {
|
|
18
|
+
/** Path / name of the curl-impersonate binary. Default "curl-impersonate". */
|
|
19
|
+
readonly command: string;
|
|
20
|
+
/** Extra argv passed to the binary. */
|
|
21
|
+
readonly extraArgs?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* PRIMARY provider — shells out to curl-impersonate.
|
|
25
|
+
*
|
|
26
|
+
* `capture()` invokes the curl-impersonate binary against `url`, impersonating
|
|
27
|
+
* `profile`, and returns the raw bytes it observed on the wire. The binary
|
|
28
|
+
* must be on PATH (or in `command`); if it is missing, the call throws
|
|
29
|
+
* {@link ReferenceError} so the facade can fall back to the secondary.
|
|
30
|
+
*/
|
|
31
|
+
export declare class CurlImpersonateProvider implements ReferenceProvider {
|
|
32
|
+
readonly kind: ReferenceProviderKind;
|
|
33
|
+
readonly command: string;
|
|
34
|
+
readonly extraArgs: readonly string[];
|
|
35
|
+
constructor(options?: CurlImpersonateOptions);
|
|
36
|
+
availableProfiles(): ProfileId[];
|
|
37
|
+
capture(profile: ProfileId, url: string): Promise<GoldenCapture>;
|
|
38
|
+
fingerprint(profile: ProfileId): Promise<Fingerprint>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=curl-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curl-provider.d.ts","sourceRoot":"","sources":["../../src/reference/curl-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlG,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAiCD;;;;;;;GAOG;AACH,qBAAa,uBAAwB,YAAW,iBAAiB;IAC7D,SAAgB,IAAI,EAAE,qBAAqB,CAAyC;IACpF,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAE7C,YAAY,OAAO,CAAC,EAAE,sBAAsB,EAG3C;IAED,iBAAiB,IAAI,SAAS,EAAE,CAU/B;IAEK,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA6BrE;IAEK,WAAW,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAG1D;CACJ"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRIMARY reference provider — shells out to curl-impersonate.
|
|
3
|
+
*
|
|
4
|
+
* `capture()` invokes the curl-impersonate binary against `url`, impersonating
|
|
5
|
+
* `profile`, and returns the raw bytes it observed on the wire. The binary
|
|
6
|
+
* must be on PATH (or in `command`); if it is missing, the call throws
|
|
7
|
+
* {@link ReferenceError} so the facade can fall back to the secondary.
|
|
8
|
+
*
|
|
9
|
+
* Split out of `reference.ts` so the facade module stays focused on primary →
|
|
10
|
+
* secondary dispatch while this file owns the curl-impersonate subprocess
|
|
11
|
+
* wiring and dump-format parsing.
|
|
12
|
+
*/
|
|
13
|
+
import { execFile, } from "node:child_process";
|
|
14
|
+
import { ReferenceError } from "./reference-errors.js";
|
|
15
|
+
import { fingerprintFromTlsCapture, parseDumpOutput, profileToSource } from "./dump.js";
|
|
16
|
+
/**
|
|
17
|
+
* Run `command args...` and resolve its captured `{stdout, stderr}`.
|
|
18
|
+
*
|
|
19
|
+
* Wraps node:child_process `execFile` with a `Promise` rather than
|
|
20
|
+
* `util.promisify` so the types resolve without forcing casts — `execFile`'s
|
|
21
|
+
* overloads return `ChildProcess`, which `promisify` cannot infer a useful
|
|
22
|
+
* promise type from. Rejects with an `ExecFileException`-shaped `Error` on
|
|
23
|
+
* non-zero exit, timeout, or spawn failure.
|
|
24
|
+
*/
|
|
25
|
+
function runExecFile(command, args, options) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
execFile(command, args, options, (err, stdout, stderr) => {
|
|
28
|
+
if (err !== null) {
|
|
29
|
+
reject(err);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
resolve({ stdout, stderr });
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* PRIMARY provider — shells out to curl-impersonate.
|
|
38
|
+
*
|
|
39
|
+
* `capture()` invokes the curl-impersonate binary against `url`, impersonating
|
|
40
|
+
* `profile`, and returns the raw bytes it observed on the wire. The binary
|
|
41
|
+
* must be on PATH (or in `command`); if it is missing, the call throws
|
|
42
|
+
* {@link ReferenceError} so the facade can fall back to the secondary.
|
|
43
|
+
*/
|
|
44
|
+
export class CurlImpersonateProvider {
|
|
45
|
+
kind = { kind: "curl-impersonate" };
|
|
46
|
+
command;
|
|
47
|
+
extraArgs;
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.command = options?.command ?? "curl-impersonate";
|
|
50
|
+
this.extraArgs = options?.extraArgs ?? [];
|
|
51
|
+
}
|
|
52
|
+
availableProfiles() {
|
|
53
|
+
// curl-impersonate ships these browser impersonation targets.
|
|
54
|
+
return [
|
|
55
|
+
"chrome-140",
|
|
56
|
+
"chrome-139",
|
|
57
|
+
"firefox-135",
|
|
58
|
+
"firefox-128",
|
|
59
|
+
"safari-18",
|
|
60
|
+
"edge-140",
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
async capture(profile, url) {
|
|
64
|
+
const profileFlag = `--${String(profile)}`;
|
|
65
|
+
const args = [profileFlag, "--dump-traffic", ...this.extraArgs, url];
|
|
66
|
+
let stdout;
|
|
67
|
+
let stderr;
|
|
68
|
+
try {
|
|
69
|
+
const out = await runExecFile(this.command, args, {
|
|
70
|
+
timeout: 30_000,
|
|
71
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
72
|
+
encoding: "utf8",
|
|
73
|
+
});
|
|
74
|
+
stdout = out.stdout;
|
|
75
|
+
stderr = out.stderr;
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
const cause = e instanceof Error ? e : new Error(String(e));
|
|
79
|
+
throw new ReferenceError(`curl-impersonate capture for ${String(profile)} failed: ${cause.message}`, { cause });
|
|
80
|
+
}
|
|
81
|
+
void stderr;
|
|
82
|
+
const bytes = parseDumpOutput(stdout);
|
|
83
|
+
return {
|
|
84
|
+
id: `${profile}/tls/client_hello`,
|
|
85
|
+
source: profileToSource(profile),
|
|
86
|
+
protocol: "tls",
|
|
87
|
+
bytes,
|
|
88
|
+
description: `curl-impersonate capture for ${String(profile)}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async fingerprint(profile) {
|
|
92
|
+
const capture = await this.capture(profile, "https://example.com");
|
|
93
|
+
return fingerprintFromTlsCapture(capture);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=curl-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curl-provider.js","sourceRoot":"","sources":["../../src/reference/curl-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* curl-impersonate dump parsing + TLS fingerprint derivation.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `reference.ts` so the providers and facade stay focused on
|
|
5
|
+
* dispatch while this file owns the curl-impersonate `--dump-traffic` byte
|
|
6
|
+
* format and the JA3/JA4 derivation from a captured ClientHello.
|
|
7
|
+
*/
|
|
8
|
+
import type { ProfileId } from "@browsercore/profiles";
|
|
9
|
+
import type { GoldenCapture } from "../types.js";
|
|
10
|
+
import type { Fingerprint } from "./reference-types.js";
|
|
11
|
+
/** Map a {@link ProfileId} to its {@link CaptureSource} tag. */
|
|
12
|
+
export declare function profileToSource(profile: ProfileId): GoldenCapture["source"];
|
|
13
|
+
/**
|
|
14
|
+
* Parse curl-impersonate `--dump-traffic` output into raw bytes.
|
|
15
|
+
*
|
|
16
|
+
* The dump format is a hex dump with one line per record; we extract the hex
|
|
17
|
+
* payload after the `>>> traffic <<<` marker. Throws {@link DumpParseError}
|
|
18
|
+
* when no hex bytes follow the marker or the hex has odd length.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseDumpOutput(stdout: string): Uint8Array;
|
|
21
|
+
/**
|
|
22
|
+
* Derive a {@link Fingerprint} from a TLS ClientHello capture.
|
|
23
|
+
*
|
|
24
|
+
* Computes JA3 + JA4 from the raw bytes and reads the per-extension metadata
|
|
25
|
+
* (supported groups, signature algorithms, ALPN) from the sidecar
|
|
26
|
+
* `.meta.json` when available.
|
|
27
|
+
*
|
|
28
|
+
* Exported for unit testing the try/catch branches: the happy path reads the
|
|
29
|
+
* sidecar meta, while the fallback path is taken when the sidecar is missing.
|
|
30
|
+
*/
|
|
31
|
+
export declare function fingerprintFromTlsCapture(capture: GoldenCapture): Fingerprint;
|
|
32
|
+
/**
|
|
33
|
+
* Extract a human-readable cipher-suite name from a JA4 tag.
|
|
34
|
+
*
|
|
35
|
+
* JA4 doesn't directly encode the negotiated cipher; this is a placeholder
|
|
36
|
+
* that returns the JA4_a segment for inspection. Real cipher-suite resolution
|
|
37
|
+
* requires parsing the ServerHello, which is out of scope for the capture.
|
|
38
|
+
*
|
|
39
|
+
* Exported for unit testing the empty-tag fallback branch.
|
|
40
|
+
*/
|
|
41
|
+
export declare function cipherSuiteName(ja4Tag: string): string;
|
|
42
|
+
//# sourceMappingURL=dump.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dump.d.ts","sourceRoot":"","sources":["../../src/reference/dump.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGxD,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,CAY3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAiB1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW,CA6B7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtD"}
|