@browsercore/testing 0.1.3 → 0.2.1

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.
Files changed (201) hide show
  1. package/README.md +5 -0
  2. package/bin/coverage-md.mjs +99 -0
  3. package/captures/DIVERGENCE_REPORT.md +325 -0
  4. package/captures/IMPERSIONATION_GAPS_REPORT.md +367 -0
  5. package/captures/README.md +56 -0
  6. package/captures/REVIEW_FINDINGS.md +71 -0
  7. package/captures/_probe/analyze.py +67 -0
  8. package/captures/_probe/capture_bytes.py +127 -0
  9. package/captures/_probe/chrome131_determinism.py +32 -0
  10. package/captures/_probe/diagnose_capture.py +59 -0
  11. package/captures/_probe/golden_analysis.py +91 -0
  12. package/captures/_probe/inspect_golden.py +55 -0
  13. package/captures/_probe/inspect_sv.py +16 -0
  14. package/captures/_probe/make_golden.py +170 -0
  15. package/captures/_probe/output/chrome100.json +219 -0
  16. package/captures/_probe/output/chrome101.json +219 -0
  17. package/captures/_probe/output/chrome104.json +219 -0
  18. package/captures/_probe/output/chrome107.json +220 -0
  19. package/captures/_probe/output/chrome110.json +220 -0
  20. package/captures/_probe/output/chrome116.json +220 -0
  21. package/captures/_probe/output/chrome119.json +219 -0
  22. package/captures/_probe/output/chrome120.json +219 -0
  23. package/captures/_probe/output/chrome123.json +223 -0
  24. package/captures/_probe/output/chrome124.json +224 -0
  25. package/captures/_probe/output/chrome131.json +224 -0
  26. package/captures/_probe/output/chrome131_fresh.json +224 -0
  27. package/captures/_probe/output/chrome133a.json +224 -0
  28. package/captures/_probe/output/chrome136.json +224 -0
  29. package/captures/_probe/output/chrome99.json +219 -0
  30. package/captures/_probe/output/edge101.json +219 -0
  31. package/captures/_probe/output/edge99.json +219 -0
  32. package/captures/_probe/output/firefox133.json +227 -0
  33. package/captures/_probe/output/firefox135.json +230 -0
  34. package/captures/_probe/output/safari155.json +210 -0
  35. package/captures/_probe/output/safari170.json +214 -0
  36. package/captures/_probe/output/safari170_fresh.json +214 -0
  37. package/captures/_probe/output/safari180.json +216 -0
  38. package/captures/_probe/output/safari180_ios.json +216 -0
  39. package/captures/_probe/output/safari184.json +215 -0
  40. package/captures/_probe/output/safari260.json +211 -0
  41. package/captures/_probe/output/summary.json +2520 -0
  42. package/captures/_probe/parse_existing_settings.py +15 -0
  43. package/captures/_probe/peetprint.py +39 -0
  44. package/captures/_probe/probe.py +137 -0
  45. package/captures/_probe/raw_bytes/chrome-131_client_hello.bin +0 -0
  46. package/captures/_probe/raw_bytes/chrome-131_client_hello.hex +32 -0
  47. package/captures/_probe/raw_bytes/firefox-133_client_hello.bin +0 -0
  48. package/captures/_probe/raw_bytes/firefox-133_client_hello.hex +32 -0
  49. package/captures/_probe/raw_bytes/safari-17_client_hello.bin +0 -0
  50. package/captures/_probe/raw_bytes/safari-17_client_hello.hex +32 -0
  51. package/captures/_probe/relay_capture.py +137 -0
  52. package/captures/_probe/socks_capture.py +138 -0
  53. package/captures/_probe/validate_fresh.py +66 -0
  54. package/captures/_probe/validate_golden.py +97 -0
  55. package/captures/_probe/verify_capture.py +68 -0
  56. package/captures/chrome-131/http2/settings.bin +0 -0
  57. package/captures/chrome-131/http2/settings.meta.json +9 -0
  58. package/captures/chrome-131/oracle_capture.reference.json +224 -0
  59. package/captures/chrome-131/tls/client_hello.bin +0 -0
  60. package/captures/chrome-131/tls/client_hello.meta.json +20 -0
  61. package/captures/chrome-140/http2/settings.bin +0 -0
  62. package/captures/chrome-140/http2/settings.meta.json +9 -0
  63. package/captures/chrome-140/tls/client_hello.bin +0 -0
  64. package/captures/chrome-140/tls/client_hello.meta.json +12 -0
  65. package/captures/firefox-128/tls/client_hello.bin +0 -0
  66. package/captures/firefox-128/tls/client_hello.meta.json +12 -0
  67. package/captures/firefox-133/http2/settings.bin +0 -0
  68. package/captures/firefox-133/http2/settings.meta.json +9 -0
  69. package/captures/firefox-133/oracle_capture.reference.json +227 -0
  70. package/captures/firefox-133/tls/client_hello.bin +0 -0
  71. package/captures/firefox-133/tls/client_hello.meta.json +20 -0
  72. package/captures/safari-17/http2/settings.bin +0 -0
  73. package/captures/safari-17/http2/settings.meta.json +9 -0
  74. package/captures/safari-17/oracle_capture.reference.json +214 -0
  75. package/captures/safari-17/tls/client_hello.bin +0 -0
  76. package/captures/safari-17/tls/client_hello.meta.json +20 -0
  77. package/captures/test-malformed/http2/settings.bin +0 -0
  78. package/captures/test-malformed/http2/settings.meta.json +9 -0
  79. package/captures/test-no-extensions/tls/client_hello.bin +0 -0
  80. package/captures/test-no-extensions/tls/client_hello.meta.json +9 -0
  81. package/captures/test-wrong-type/http2/settings.bin +0 -0
  82. package/captures/test-wrong-type/http2/settings.meta.json +9 -0
  83. package/dist/bench/bench.d.ts +24 -6
  84. package/dist/bench/bench.d.ts.map +1 -1
  85. package/dist/bench/bench.js +110 -10
  86. package/dist/bench/bench.js.map +1 -1
  87. package/dist/captures/manifest.d.ts.map +1 -1
  88. package/dist/captures/manifest.js +7 -7
  89. package/dist/captures/manifest.js.map +1 -1
  90. package/dist/categories/compression.d.ts +6 -4
  91. package/dist/categories/compression.d.ts.map +1 -1
  92. package/dist/categories/compression.js +56 -6
  93. package/dist/categories/compression.js.map +1 -1
  94. package/dist/categories/cookies.d.ts +3 -2
  95. package/dist/categories/cookies.d.ts.map +1 -1
  96. package/dist/categories/cookies.js +216 -11
  97. package/dist/categories/cookies.js.map +1 -1
  98. package/dist/categories/redirects.d.ts +8 -2
  99. package/dist/categories/redirects.d.ts.map +1 -1
  100. package/dist/categories/redirects.js +97 -12
  101. package/dist/categories/redirects.js.map +1 -1
  102. package/dist/e2e/cert-gen.d.ts +31 -0
  103. package/dist/e2e/cert-gen.d.ts.map +1 -0
  104. package/dist/e2e/cert-gen.js +158 -0
  105. package/dist/e2e/cert-gen.js.map +1 -0
  106. package/dist/e2e/parse-clienthello.d.ts +177 -0
  107. package/dist/e2e/parse-clienthello.d.ts.map +1 -0
  108. package/dist/e2e/parse-clienthello.js +343 -0
  109. package/dist/e2e/parse-clienthello.js.map +1 -0
  110. package/dist/e2e/sink-server.d.ts +109 -0
  111. package/dist/e2e/sink-server.d.ts.map +1 -0
  112. package/dist/e2e/sink-server.js +292 -0
  113. package/dist/e2e/sink-server.js.map +1 -0
  114. package/dist/e2e/traffic-server.d.ts +48 -0
  115. package/dist/e2e/traffic-server.d.ts.map +1 -0
  116. package/dist/e2e/traffic-server.js +162 -0
  117. package/dist/e2e/traffic-server.js.map +1 -0
  118. package/dist/errors.d.ts.map +1 -1
  119. package/dist/errors.js.map +1 -1
  120. package/dist/fingerprint/index.d.ts +5 -2
  121. package/dist/fingerprint/index.d.ts.map +1 -1
  122. package/dist/fingerprint/index.js +3 -2
  123. package/dist/fingerprint/index.js.map +1 -1
  124. package/dist/fingerprint/ja3.d.ts.map +1 -1
  125. package/dist/fingerprint/ja3.js +33 -4
  126. package/dist/fingerprint/ja3.js.map +1 -1
  127. package/dist/fingerprint/ja4-errors.d.ts +17 -0
  128. package/dist/fingerprint/ja4-errors.d.ts.map +1 -0
  129. package/dist/fingerprint/ja4-errors.js +20 -0
  130. package/dist/fingerprint/ja4-errors.js.map +1 -0
  131. package/dist/fingerprint/ja4-reader.d.ts +44 -0
  132. package/dist/fingerprint/ja4-reader.d.ts.map +1 -0
  133. package/dist/fingerprint/ja4-reader.js +112 -0
  134. package/dist/fingerprint/ja4-reader.js.map +1 -0
  135. package/dist/fingerprint/ja4.d.ts +11 -43
  136. package/dist/fingerprint/ja4.d.ts.map +1 -1
  137. package/dist/fingerprint/ja4.js +54 -141
  138. package/dist/fingerprint/ja4.js.map +1 -1
  139. package/dist/fingerprint/ja4h.d.ts +46 -0
  140. package/dist/fingerprint/ja4h.d.ts.map +1 -0
  141. package/dist/fingerprint/ja4h.js +50 -0
  142. package/dist/fingerprint/ja4h.js.map +1 -0
  143. package/dist/golden/golden.d.ts +15 -1
  144. package/dist/golden/golden.d.ts.map +1 -1
  145. package/dist/golden/golden.js +42 -28
  146. package/dist/golden/golden.js.map +1 -1
  147. package/dist/index.d.ts +21 -1
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +36 -1
  150. package/dist/index.js.map +1 -1
  151. package/dist/node-provider.d.ts +42 -0
  152. package/dist/node-provider.d.ts.map +1 -0
  153. package/dist/node-provider.js +53 -0
  154. package/dist/node-provider.js.map +1 -0
  155. package/dist/provider.d.ts +52 -0
  156. package/dist/provider.d.ts.map +1 -0
  157. package/dist/provider.js +14 -0
  158. package/dist/provider.js.map +1 -0
  159. package/dist/reference/browser-provider.d.ts +33 -0
  160. package/dist/reference/browser-provider.d.ts.map +1 -0
  161. package/dist/reference/browser-provider.js +61 -0
  162. package/dist/reference/browser-provider.js.map +1 -0
  163. package/dist/reference/curl-provider.d.ts +40 -0
  164. package/dist/reference/curl-provider.d.ts.map +1 -0
  165. package/dist/reference/curl-provider.js +96 -0
  166. package/dist/reference/curl-provider.js.map +1 -0
  167. package/dist/reference/dump.d.ts +42 -0
  168. package/dist/reference/dump.d.ts.map +1 -0
  169. package/dist/reference/dump.js +102 -0
  170. package/dist/reference/dump.js.map +1 -0
  171. package/dist/reference/node-crypto-provider.d.ts +31 -0
  172. package/dist/reference/node-crypto-provider.d.ts.map +1 -0
  173. package/dist/reference/node-crypto-provider.js +199 -0
  174. package/dist/reference/node-crypto-provider.js.map +1 -0
  175. package/dist/reference/node-reference.d.ts.map +1 -1
  176. package/dist/reference/node-reference.js +2 -5
  177. package/dist/reference/node-reference.js.map +1 -1
  178. package/dist/reference/reference-errors.d.ts +36 -0
  179. package/dist/reference/reference-errors.d.ts.map +1 -0
  180. package/dist/reference/reference-errors.js +43 -0
  181. package/dist/reference/reference-errors.js.map +1 -0
  182. package/dist/reference/reference-types.d.ts +33 -0
  183. package/dist/reference/reference-types.d.ts.map +1 -0
  184. package/dist/reference/reference-types.js +9 -0
  185. package/dist/reference/reference-types.js.map +1 -0
  186. package/dist/reference/reference.d.ts +14 -77
  187. package/dist/reference/reference.d.ts.map +1 -1
  188. package/dist/reference/reference.js +43 -207
  189. package/dist/reference/reference.js.map +1 -1
  190. package/dist/rfc/rfcTests.d.ts +46 -8
  191. package/dist/rfc/rfcTests.d.ts.map +1 -1
  192. package/dist/rfc/rfcTests.js +203 -16
  193. package/dist/rfc/rfcTests.js.map +1 -1
  194. package/dist/types.d.ts +2 -1
  195. package/dist/types.d.ts.map +1 -1
  196. package/dist/types.js.map +1 -1
  197. package/dist/utils.d.ts +3 -0
  198. package/dist/utils.d.ts.map +1 -1
  199. package/dist/utils.js +11 -5
  200. package/dist/utils.js.map +1 -1
  201. package/package.json +68 -55
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Pluggable layered reference provider.
2
+ * Pluggable layered reference provider — facade + factory.
3
3
  *
4
4
  * The reference implementation is the source of truth for what a given browser
5
5
  * profile SHOULD produce on the wire. Three backends are wrapped behind one
@@ -17,129 +17,19 @@
17
17
  * primary then secondary; fingerprint is derived from the captured bytes; the
18
18
  * node-reference oracle is exposed for primitive-layer comparisons.
19
19
  *
20
- * See docs/TEST-SUITE.md (Cat 3, 4, 14) for how references feed comparison.
20
+ * The providers and dump helpers live in their own modules; this file owns the
21
+ * facade + factory dispatch. See docs/TEST-SUITE.md (Cat 3, 4, 14).
21
22
  */
22
- import { execFile } from "node:child_process";
23
- import { fileURLToPath } from "node:url";
24
- import { dirname, join } from "node:path";
25
- import { promisify } from "node:util";
26
- import { computeJa3 } from "../fingerprint/ja3.js";
27
- import { computeJa4Fingerprint } from "../fingerprint/ja4.js";
28
- import { loadCaptureMeta } from "../golden/golden.js";
29
- import { TestingError } from "../errors.js";
30
- const execFileAsync = promisify(execFile);
31
- const here = dirname(fileURLToPath(import.meta.url));
32
- const packageRoot = join(here, "..", "..");
33
- const defaultCapturesDir = join(packageRoot, "captures");
34
- /** Raised when a reference provider cannot capture or fingerprint a profile. */
35
- export class ReferenceError extends TestingError {
36
- constructor(message, options) {
37
- super(message, options);
38
- this.name = "ReferenceError";
39
- }
40
- }
41
- /**
42
- * PRIMARY provider — shells out to curl-impersonate.
43
- *
44
- * `capture()` invokes the curl-impersonate binary against `url`, impersonating
45
- * `profile`, and returns the raw bytes it observed on the wire. The binary
46
- * must be on PATH (or in `command`); if it is missing, the call throws
47
- * {@link ReferenceError} so the facade can fall back to the secondary.
48
- */
49
- export class CurlImpersonateProvider {
50
- kind = { kind: "curl-impersonate" };
51
- command;
52
- extraArgs;
53
- constructor(options) {
54
- this.command = options?.command ?? "curl-impersonate";
55
- this.extraArgs = options?.extraArgs ?? [];
56
- }
57
- availableProfiles() {
58
- // curl-impersonate ships these browser impersonation targets.
59
- return [
60
- "chrome-140",
61
- "chrome-139",
62
- "firefox-135",
63
- "firefox-128",
64
- "safari-18",
65
- "edge-140",
66
- ];
67
- }
68
- async capture(profile, url) {
69
- const profileFlag = `--${String(profile)}`;
70
- const args = [profileFlag, "--dump-traffic", ...this.extraArgs, url];
71
- let stdout;
72
- let stderr;
73
- try {
74
- const out = await execFileAsync(this.command, args, {
75
- timeout: 30_000,
76
- maxBuffer: 64 * 1024 * 1024,
77
- });
78
- stdout = out.stdout;
79
- stderr = out.stderr;
80
- }
81
- catch (e) {
82
- const cause = e instanceof Error ? e : new Error(String(e));
83
- throw new ReferenceError(`curl-impersonate capture for ${String(profile)} failed: ${cause.message}`, { cause });
84
- }
85
- void stderr;
86
- const bytes = parseDumpOutput(stdout);
87
- return {
88
- id: `${profile}/tls/client_hello`,
89
- source: profileToSource(profile),
90
- protocol: "tls",
91
- bytes,
92
- description: `curl-impersonate capture for ${String(profile)}`,
93
- };
94
- }
95
- async fingerprint(profile) {
96
- const capture = await this.capture(profile, "https://example.com");
97
- return fingerprintFromTlsCapture(capture);
98
- }
99
- }
100
- /**
101
- * SECONDARY provider — loads pre-recorded captures from the `captures/` dir.
102
- *
103
- * `capture()` resolves a stored capture for the profile; `fingerprint()`
104
- * derives a {@link Fingerprint} from the captured bytes (only TLS
105
- * ClientHellos are fingerprinted — other protocols return a stub).
106
- */
107
- export class RealBrowserCaptureProvider {
108
- kind = { kind: "real-browser" };
109
- capturesDir;
110
- constructor(options) {
111
- this.capturesDir = options?.capturesDir ?? defaultCapturesDir;
112
- }
113
- availableProfiles() {
114
- // Discovery is driven by the captures manifest (captures/manifest.ts).
115
- return [
116
- "chrome-140",
117
- "firefox-128",
118
- ];
119
- }
120
- async capture(profile, _url) {
121
- void _url;
122
- const manifest = await import("../captures/manifest.js");
123
- const entry = manifest.captures.find((c) => c.meta.profile === profile);
124
- if (entry === undefined) {
125
- throw new ReferenceError(`No pre-recorded capture for profile ${String(profile)}`);
126
- }
127
- return {
128
- id: `${profile}/tls/client_hello`,
129
- source: profileToSource(profile),
130
- protocol: entry.meta.protocol,
131
- bytes: entry.bytes,
132
- description: entry.meta.description,
133
- };
134
- }
135
- async fingerprint(profile) {
136
- const capture = await this.capture(profile, "https://example.com");
137
- if (capture.protocol !== "tls") {
138
- throw new ReferenceError(`fingerprint() only supports TLS captures; got ${capture.protocol}`);
139
- }
140
- return fingerprintFromTlsCapture(capture);
141
- }
142
- }
23
+ import { CurlImpersonateProvider } from "./curl-provider.js";
24
+ import { RealBrowserCaptureProvider } from "./browser-provider.js";
25
+ import { ReferenceError } from "./reference-errors.js";
26
+ import { assertNever } from "../utils.js";
27
+ // Re-export so existing import sites (`from "./reference.js"`) keep resolving
28
+ // after the providers and helpers moved into focused modules.
29
+ export { CurlImpersonateProvider } from "./curl-provider.js";
30
+ export { RealBrowserCaptureProvider } from "./browser-provider.js";
31
+ export { ReferenceError, DumpParseError } from "./reference-errors.js";
32
+ export { parseDumpOutput, fingerprintFromTlsCapture, cipherSuiteName } from "./dump.js";
143
33
  /**
144
34
  * Facade wrapping the node-reference oracle + primary (curl-impersonate) and
145
35
  * secondary (real-browser) providers behind a single {@link ReferenceProvider}.
@@ -172,8 +62,9 @@ export class ReferenceProviderFacade {
172
62
  const out = [];
173
63
  for (const p of [...this.primary.availableProfiles(), ...this.secondary.availableProfiles()]) {
174
64
  const key = String(p);
175
- if (seen.has(key))
65
+ if (seen.has(key)) {
176
66
  continue;
67
+ }
177
68
  seen.add(key);
178
69
  out.push(p);
179
70
  }
@@ -221,103 +112,48 @@ import * as nodeOracle from "./node-reference.js";
221
112
  export function createReferenceProvider(kind, options) {
222
113
  switch (kind.kind) {
223
114
  case "curl-impersonate":
224
- return new CurlImpersonateProvider(options);
115
+ return new CurlImpersonateProvider(toCurlOptions(options));
225
116
  case "real-browser":
226
- return new RealBrowserCaptureProvider(options);
117
+ return new RealBrowserCaptureProvider(toBrowserOptions(options));
118
+ default:
119
+ // Exhaustiveness guaranteed by the union — unreachable unless a new
120
+ // provider kind is added without a handler.
121
+ return assertNever(kind);
227
122
  }
228
123
  }
229
124
  /**
230
- * Construct the full {@link ReferenceProviderFacade} wrapping both providers
231
- * plus the node-reference oracle. This is the recommended entry point for
232
- * tests that want primary→secondary fallback.
233
- */
234
- export function createReferenceFacade(options) {
235
- return new ReferenceProviderFacade(options);
236
- }
237
- /** Map a {@link ProfileId} to its {@link CaptureSource} tag. */
238
- function profileToSource(profile) {
239
- const p = String(profile);
240
- if (p.startsWith("firefox"))
241
- return "firefox-135";
242
- if (p.startsWith("safari"))
243
- return "safari-18";
244
- if (p.startsWith("edge"))
245
- return "edge-140";
246
- return "chrome-140";
247
- }
248
- /**
249
- * Parse curl-impersonate `--dump-traffic` output into raw bytes.
125
+ * Narrow the shared options union to the curl-impersonate shape.
250
126
  *
251
- * The dump format is a hex dump with one line per record; we extract the hex
252
- * payload between the markers. For now we assume the body is a contiguous hex
253
- * block — adjust the parser if curl-impersonate's format differs.
127
+ * Copies only the fields the curl provider reads, so passing a
128
+ * browser-options object does not leak `capturesDir` into a place that ignores
129
+ * it. No `as` cast: the result is built field-by-field from validated reads.
254
130
  */
255
- function parseDumpOutput(stdout) {
256
- // Find the hex body — everything after the ">>> traffic <<<" marker.
257
- const marker = ">>> traffic <<<";
258
- const idx = stdout.indexOf(marker);
259
- const body = idx === -1 ? stdout : stdout.slice(idx + marker.length);
260
- const hex = body.replace(/[^0-9a-fA-F]/g, "");
261
- if (hex.length === 0) {
262
- throw new ReferenceError("curl-impersonate dump produced no hex bytes");
263
- }
264
- if (hex.length % 2 !== 0) {
265
- throw new ReferenceError(`curl-impersonate dump produced odd-length hex (${hex.length})`);
131
+ function toCurlOptions(options) {
132
+ if (options === undefined || !("command" in options) || options.command === undefined) {
133
+ return undefined;
266
134
  }
267
- const bytes = new Uint8Array(hex.length / 2);
268
- for (let i = 0; i < bytes.length; i++) {
269
- bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
270
- }
271
- return bytes;
135
+ return options.extraArgs === undefined
136
+ ? { command: options.command }
137
+ : { command: options.command, extraArgs: options.extraArgs };
272
138
  }
273
139
  /**
274
- * Derive a {@link Fingerprint} from a TLS ClientHello capture.
140
+ * Narrow the shared options union to the real-browser shape.
275
141
  *
276
- * Computes JA3 + JA4 from the raw bytes and reads the per-extension metadata
277
- * (supported groups, signature algorithms, ALPN) from the sidecar
278
- * `.meta.json` when available.
142
+ * Copies only the fields the browser provider reads. `command` is `undefined`
143
+ * on `RealBrowserOptions` by construction, so it is not copied.
279
144
  */
280
- function fingerprintFromTlsCapture(capture) {
281
- const ja3 = computeJa3(capture.bytes);
282
- const ja4 = computeJa4Fingerprint(capture.bytes);
283
- // Read the sidecar meta for richer fields (signature algorithms, ALPN,
284
- // supported curves). Fall back to empty arrays if missing.
285
- let alpn = [];
286
- let signatureAlgorithms = [];
287
- let ellipticCurves = [];
288
- try {
289
- const meta = loadCaptureMeta(capture.id);
290
- if (meta.protocol === "tls") {
291
- // CaptureMeta doesn't carry ALPN/sigAlgs/curves yet; this is a
292
- // placeholder for when the sidecar schema is extended.
293
- void meta;
294
- void alpn;
295
- void signatureAlgorithms;
296
- void ellipticCurves;
297
- }
298
- }
299
- catch {
300
- // Sidecar missing or unparseable — leave richer fields empty.
145
+ function toBrowserOptions(options) {
146
+ if (options === undefined || !("capturesDir" in options) || options.capturesDir === undefined) {
147
+ return undefined;
301
148
  }
302
- return {
303
- ja3,
304
- ja4: ja4.tag,
305
- alpn,
306
- cipherSuite: cipherSuiteName(ja4.tag),
307
- protocolVersion: ja4.tag.slice(5, 7) || "unknown",
308
- signatureAlgorithms,
309
- ellipticCurves,
310
- };
149
+ return { capturesDir: options.capturesDir };
311
150
  }
312
151
  /**
313
- * Extract a human-readable cipher-suite name from a JA4 tag.
314
- *
315
- * JA4 doesn't directly encode the negotiated cipher; this is a placeholder
316
- * that returns the JA4_a segment for inspection. Real cipher-suite resolution
317
- * requires parsing the ServerHello, which is out of scope for the capture.
152
+ * Construct the full {@link ReferenceProviderFacade} wrapping both providers
153
+ * plus the node-reference oracle. This is the recommended entry point for
154
+ * tests that want primary→secondary fallback.
318
155
  */
319
- function cipherSuiteName(ja4Tag) {
320
- const a = ja4Tag.split("_")[0] ?? "";
321
- return a.length > 0 ? a : "unknown";
156
+ export function createReferenceFacade(options) {
157
+ return new ReferenceProviderFacade(options);
322
158
  }
323
159
  //# sourceMappingURL=reference.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/reference/reference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC3C,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AA+CzD,gFAAgF;AAChF,MAAM,OAAO,cAAe,SAAQ,YAAY;IAC5C,YAAY,OAAe,EAAE,OAA2B;QACpD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IACjC,CAAC;CACJ;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,uBAAuB;IAChB,IAAI,GAA0B,EAAE,IAAI,EAAE,kBAAkB,EAAW,CAAC;IACpE,OAAO,CAAS;IAChB,SAAS,CAAoB;IAE7C,YAAY,OAAgC;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,kBAAkB,CAAC;QACtD,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,iBAAiB;QACb,8DAA8D;QAC9D,OAAO;YACH,YAAyB;YACzB,YAAyB;YACzB,aAA0B;YAC1B,aAA0B;YAC1B,WAAwB;YACxB,UAAuB;SAC1B,CAAC;IACN,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAkB,EAAE,GAAW;QACzC,MAAM,WAAW,GAAG,KAAK,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACrE,IAAI,MAAc,CAAC;QACnB,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE;gBAChD,OAAO,EAAE,MAAM;gBACf,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;aAC9B,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YACpB,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,MAAM,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,IAAI,cAAc,CACpB,gCAAgC,MAAM,CAAC,OAAO,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,EAC1E,EAAE,KAAK,EAAE,CACZ,CAAC;QACN,CAAC;QACD,KAAK,MAAM,CAAC;QACZ,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QACtC,OAAO;YACH,EAAE,EAAE,GAAG,OAAO,mBAA0C;YACxD,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC;YAChC,QAAQ,EAAE,KAAK;YACf,KAAK;YACL,WAAW,EAAE,gCAAgC,MAAM,CAAC,OAAO,CAAC,EAAE;SACjE,CAAC;IACN,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAkB;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;QACnE,OAAO,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;CACJ;AAED;;;;;;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;;;;;;;;;GASG;AACH,MAAM,OAAO,uBAAuB;IAChB,IAAI,GAA0B,EAAE,IAAI,EAAE,kBAAkB,EAAW,CAAC;IACnE,OAAO,CAA0B;IACjC,SAAS,CAA6B;IAEvD,YAAY,OAAgC;QACxC,IAAI,CAAC,OAAO,GAAG,IAAI,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,SAAS,GAAG,IAAI,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAED;;;;OAIG;IACH,IAAI,UAAU;QACV,OAAO,UAAU,CAAC;IACtB,CAAC;IAED,iBAAiB;QACb,wDAAwD;QACxD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,GAAG,GAAgB,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,CAAC,EAAE,CAAC;YAC3F,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAkB,EAAE,GAAW;QACzC,IAAI,CAAC;YACD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;YACvF,+DAA+D;YAC/D,IAAI,CAAC;gBACD,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,YAAY,EAAE,CAAC;gBACpB,MAAM,cAAc,GAAG,YAAY,YAAY,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;gBACtG,MAAM,IAAI,cAAc,CACpB,8BAA8B,MAAM,CAAC,OAAO,CAAC,qBAAqB,KAAK,CAAC,OAAO,wBAAwB,cAAc,CAAC,OAAO,GAAG,EAChI,EAAE,KAAK,EAAE,cAAc,EAAE,CAC5B,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAkB;QAChC,IAAI,CAAC;YACD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;YACvF,IAAI,CAAC;gBACD,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,YAAY,EAAE,CAAC;gBACpB,MAAM,cAAc,GAAG,YAAY,YAAY,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;gBACtG,MAAM,IAAI,cAAc,CACpB,gCAAgC,MAAM,CAAC,OAAO,CAAC,qBAAqB,KAAK,CAAC,OAAO,wBAAwB,cAAc,CAAC,OAAO,GAAG,EAClI,EAAE,KAAK,EAAE,cAAc,EAAE,CAC5B,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;CACJ;AAED;;;;GAIG;AACH,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAC;AAElD,sFAAsF;AACtF,MAAM,UAAU,uBAAuB,CACnC,IAA2B,EAC3B,OAAqD;IAErD,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,kBAAkB;YACnB,OAAO,IAAI,uBAAuB,CAAC,OAA6C,CAAC,CAAC;QACtF,KAAK,cAAc;YACf,OAAO,IAAI,0BAA0B,CAAC,OAAyC,CAAC,CAAC;IACzF,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgC;IAClE,OAAO,IAAI,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,gEAAgE;AAChE,SAAS,eAAe,CAAC,OAAkB;IACvC,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,aAAa,CAAC;IAClD,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAC/C,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,UAAU,CAAC;IAC5C,OAAO,YAAY,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,MAAc;IACnC,qEAAqE;IACrE,MAAM,MAAM,GAAG,iBAAiB,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,cAAc,CAAC,6CAA6C,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,cAAc,CACpB,kDAAkD,GAAG,CAAC,MAAM,GAAG,CAClE,CAAC;IACN,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,yBAAyB,CAAC,OAAsB;IACrD,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,qBAAqB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEjD,uEAAuE;IACvE,2DAA2D;IAC3D,IAAI,IAAI,GAAsB,EAAE,CAAC;IACjC,IAAI,mBAAmB,GAAsB,EAAE,CAAC;IAChD,IAAI,cAAc,GAAsB,EAAE,CAAC;IAC3C,IAAI,CAAC;QACD,MAAM,IAAI,GAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC1B,+DAA+D;YAC/D,uDAAuD;YACvD,KAAK,IAAI,CAAC;YACV,KAAK,IAAI,CAAC;YACV,KAAK,mBAAmB,CAAC;YACzB,KAAK,cAAc,CAAC;QACxB,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACL,8DAA8D;IAClE,CAAC;IAED,OAAO;QACH,GAAG;QACH,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,IAAI;QACJ,WAAW,EAAE,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC;QACrC,eAAe,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,SAAS;QACjD,mBAAmB;QACnB,cAAc;KACjB,CAAC;AACN,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,MAAc;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/reference/reference.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,52 @@
1
1
  /**
2
2
  * RFC compliance test suites.
3
3
  *
4
- * Each function runs a focused compliance check and returns a {@link TestResult}.
5
- * Stubbed until the underlying protocol stacks exist.
4
+ * Each function runs a focused compliance check against the in-repo golden
5
+ * captures and the @browsercore/profiles definitions, and returns a
6
+ * {@link TestResult}. The checks are deterministic and need no live network:
7
+ *
8
+ * - TLS (RFC 8446) — parse the golden ClientHello for the active profile,
9
+ * validate cipher order / extensions / GREASE / signature algorithms /
10
+ * supported versions against the profile definition via
11
+ * {@link validateProfileAgainstCapture}.
12
+ * - HTTP/2 (RFC 9113) — parse the golden SETTINGS frame and verify the
13
+ * settings values match the profile's {@link Http2Profile.settings}.
14
+ * - HTTP/1.1 (RFC 9110) — verify the profile's header order and default
15
+ * headers form a valid HTTP/1.1 request block (no duplicate pseudo-headers,
16
+ * required Host header present, header names lowercase).
6
17
  */
18
+ import { type ProfileId } from "@browsercore/profiles";
7
19
  import type { TestCaseId, TestResult } from "../types.js";
8
- /** Run the TLS 1.3 (RFC 8446) compliance checks. */
9
- export declare function runTlsCompliance(_id?: TestCaseId): TestResult;
10
- /** Run the HTTP/2 (RFC 9113) compliance checks. */
11
- export declare function runHttp2Compliance(_id?: TestCaseId): TestResult;
12
- /** Run the HTTP/1.1 (RFC 9110) compliance checks. */
13
- export declare function runHttp1Compliance(_id?: TestCaseId): TestResult;
20
+ /**
21
+ * Run the TLS 1.3 (RFC 8446) compliance checks against the chrome-140
22
+ * golden capture. Validates cipher order, extension order, GREASE handling,
23
+ * and supported groups against the chrome-140 profile definition.
24
+ *
25
+ * Returns a {@link TestResult} that aggregates the per-field diffs reported
26
+ * by {@link validateProfileAgainstCapture}.
27
+ */
28
+ export declare function runTlsCompliance(id?: TestCaseId, profileId?: ProfileId): TestResult;
29
+ /**
30
+ * Run the HTTP/2 (RFC 9113) compliance checks against the chrome-140
31
+ * golden SETTINGS capture. Verifies each SETTINGS value matches the
32
+ * profile's {@link Http2Profile.settings}.
33
+ *
34
+ * SETTINGS frame ids (RFC 9113 §6.5.1):
35
+ * 1 = HEADER_TABLE_SIZE
36
+ * 2 = ENABLE_PUSH
37
+ * 3 = MAX_CONCURRENT_STREAMS
38
+ * 4 = INITIAL_WINDOW_SIZE
39
+ * 5 = MAX_FRAME_SIZE
40
+ */
41
+ export declare function runHttp2Compliance(id?: TestCaseId, profileId?: ProfileId): TestResult;
42
+ /**
43
+ * Run the HTTP/1.1 (RFC 9110) compliance checks against the chrome-140
44
+ * profile's header configuration. Verifies:
45
+ *
46
+ * 1. The `Host` header is present (required by RFC 9110 §7.2).
47
+ * 2. Header names are lowercase (HTTP/2 requires this; HTTP/1.1 convention).
48
+ * 3. No duplicate header names in the default set.
49
+ * 4. The header order list matches the default headers' key set.
50
+ */
51
+ export declare function runHttp1Compliance(id?: TestCaseId, profileId?: ProfileId): TestResult;
14
52
  //# sourceMappingURL=rfcTests.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rfcTests.d.ts","sourceRoot":"","sources":["../../src/rfc/rfcTests.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,oDAAoD;AACpD,wBAAgB,gBAAgB,CAC5B,GAAG,GAAE,UAAiC,GACvC,UAAU,CAGZ;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,CAC9B,GAAG,GAAE,UAAmC,GACzC,UAAU,CAGZ;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAC9B,GAAG,GAAE,UAAmC,GACzC,UAAU,CAGZ"}
1
+ {"version":3,"file":"rfcTests.d.ts","sourceRoot":"","sources":["../../src/rfc/rfcTests.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAA6C,KAAK,SAAS,EAAmB,MAAM,uBAAuB,CAAC;AACnH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAyF1D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC5B,EAAE,GAAE,UAA+B,EACnC,SAAS,GAAE,SAAqC,GACjD,UAAU,CAeZ;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAC9B,EAAE,GAAE,UAAiC,EACrC,SAAS,GAAE,SAAqC,GACjD,UAAU,CAyCZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAC9B,EAAE,GAAE,UAAiC,EACrC,SAAS,GAAE,SAAqC,GACjD,UAAU,CA0DZ"}
@@ -1,22 +1,209 @@
1
1
  /**
2
2
  * RFC compliance test suites.
3
3
  *
4
- * Each function runs a focused compliance check and returns a {@link TestResult}.
5
- * Stubbed until the underlying protocol stacks exist.
4
+ * Each function runs a focused compliance check against the in-repo golden
5
+ * captures and the @browsercore/profiles definitions, and returns a
6
+ * {@link TestResult}. The checks are deterministic and need no live network:
7
+ *
8
+ * - TLS (RFC 8446) — parse the golden ClientHello for the active profile,
9
+ * validate cipher order / extensions / GREASE / signature algorithms /
10
+ * supported versions against the profile definition via
11
+ * {@link validateProfileAgainstCapture}.
12
+ * - HTTP/2 (RFC 9113) — parse the golden SETTINGS frame and verify the
13
+ * settings values match the profile's {@link Http2Profile.settings}.
14
+ * - HTTP/1.1 (RFC 9110) — verify the profile's header order and default
15
+ * headers form a valid HTTP/1.1 request block (no duplicate pseudo-headers,
16
+ * required Host header present, header names lowercase).
17
+ */
18
+ import { getProfile, validateProfileAgainstCapture } from "@browsercore/profiles";
19
+ import { parseClientHello } from "../fingerprint/index.js";
20
+ import { loadGolden } from "../golden/golden.js";
21
+ /** Split a dash-joined numeric string into an integer array. */
22
+ function parts(s) {
23
+ return s.length === 0 ? [] : s.split("-").map((n) => Math.trunc(Number(n)));
24
+ }
25
+ /** Parse a golden TLS ClientHello capture into a {@link TlsCapture}. */
26
+ function parseTlsCapture(bytes) {
27
+ const segs = parseClientHello(bytes);
28
+ // GREASE detection: the capture advertises GREASE iff its cipher list
29
+ // contains a GREASE-pattern value (0x?a?a in 0x0a0a..0xfafa).
30
+ const ciphers = parts(segs.ciphers);
31
+ const grease = ciphers.some((c) => c >= 0x0a0a && (c >> 8) === (c & 0xff));
32
+ return {
33
+ cipherSuites: ciphers,
34
+ extensionTypes: parts(segs.extensions),
35
+ supportedVersions: [],
36
+ keyShareGroups: parts(segs.supportedGroups),
37
+ signatureAlgorithms: [],
38
+ grease,
39
+ };
40
+ }
41
+ /**
42
+ * Parse a raw HTTP/2 SETTINGS frame payload (6 bytes per setting: 2-byte id +
43
+ * 4-byte value) into a map of setting id → value.
44
+ */
45
+ function parseHttp2Settings(payload) {
46
+ const settings = new Map();
47
+ for (let i = 0; i + 5 < payload.length; i += 6) {
48
+ const b0 = payload[i] ?? 0;
49
+ const b1 = payload[i + 1] ?? 0;
50
+ const b2 = payload[i + 2] ?? 0;
51
+ const b3 = payload[i + 3] ?? 0;
52
+ const b4 = payload[i + 4] ?? 0;
53
+ const b5 = payload[i + 5] ?? 0;
54
+ const id = (b0 << 8) | b1;
55
+ const value = (b2 << 24) | (b3 << 16) | (b4 << 8) | b5;
56
+ settings.set(id, value >>> 0); // unsigned
57
+ }
58
+ return settings;
59
+ }
60
+ /** HTTP/2 SETTINGS frame type id (RFC 9113 §6.5). */
61
+ const HTTP2_FRAME_TYPE_SETTINGS = 0x4;
62
+ /** HTTP/2 frame header size: 3-byte length + 1-byte type + 1-byte flags + 4-byte stream id. */
63
+ const HTTP2_FRAME_HEADER_SIZE = 9;
64
+ /** Strip the frame header (9 bytes) and return the settings payload. */
65
+ function settingsPayload(captureBytes) {
66
+ // A bare SETTINGS frame has no TLS record wrapper — it starts with the
67
+ // 9-byte HTTP/2 frame header. Byte layout:
68
+ // [0..2] payload length (24 bits)
69
+ // [3] frame type
70
+ // [4] flags
71
+ // [5..8] stream id (31 bits, top bit reserved)
72
+ // Validate the frame type before slicing.
73
+ if (captureBytes.length < HTTP2_FRAME_HEADER_SIZE) {
74
+ return captureBytes;
75
+ }
76
+ const frameType = captureBytes[3];
77
+ if (frameType !== HTTP2_FRAME_TYPE_SETTINGS) {
78
+ // Not a SETTINGS frame at byte 3 — return the raw bytes for the caller
79
+ // to surface as a compliance failure.
80
+ return captureBytes;
81
+ }
82
+ return captureBytes.slice(HTTP2_FRAME_HEADER_SIZE);
83
+ }
84
+ /**
85
+ * Build a {@link TestResult} from a validation outcome.
86
+ * `actual` / `expected` carry the parsed capture values for diagnostics.
87
+ * Omits `diff` entirely when there is nothing to report (exactOptionalPropertyTypes).
88
+ */
89
+ function result(id, pass, actual, expected, diff) {
90
+ return diff === undefined ? { id, pass, actual, expected } : { id, pass, actual, expected, diff };
91
+ }
92
+ /**
93
+ * Run the TLS 1.3 (RFC 8446) compliance checks against the chrome-140
94
+ * golden capture. Validates cipher order, extension order, GREASE handling,
95
+ * and supported groups against the chrome-140 profile definition.
96
+ *
97
+ * Returns a {@link TestResult} that aggregates the per-field diffs reported
98
+ * by {@link validateProfileAgainstCapture}.
99
+ */
100
+ export function runTlsCompliance(id = "tls_rfc", profileId = "chrome-140") {
101
+ const profile = getProfile(profileId);
102
+ const capture = loadGolden(`${profileId}/tls/client_hello`);
103
+ const tlsCapture = parseTlsCapture(capture.bytes);
104
+ const validation = validateProfileAgainstCapture(profile, tlsCapture);
105
+ return result(id, validation.ok, tlsCapture, "profile matches golden capture", validation.ok
106
+ ? undefined
107
+ : validation.diffs.map((d) => `${d.path}: ${String(d.a)} vs ${String(d.b)}`).join("; "));
108
+ }
109
+ /**
110
+ * Run the HTTP/2 (RFC 9113) compliance checks against the chrome-140
111
+ * golden SETTINGS capture. Verifies each SETTINGS value matches the
112
+ * profile's {@link Http2Profile.settings}.
113
+ *
114
+ * SETTINGS frame ids (RFC 9113 §6.5.1):
115
+ * 1 = HEADER_TABLE_SIZE
116
+ * 2 = ENABLE_PUSH
117
+ * 3 = MAX_CONCURRENT_STREAMS
118
+ * 4 = INITIAL_WINDOW_SIZE
119
+ * 5 = MAX_FRAME_SIZE
120
+ */
121
+ export function runHttp2Compliance(id = "http2_rfc", profileId = "chrome-140") {
122
+ const profile = getProfile(profileId);
123
+ const capture = loadGolden(`${profileId}/http2/settings`);
124
+ const payload = settingsPayload(capture.bytes);
125
+ const settings = parseHttp2Settings(payload);
126
+ // RFC 9113 §6.5.1 setting ids.
127
+ const SETTING_MAX_CONCURRENT_STREAMS = 3;
128
+ const SETTING_INITIAL_WINDOW_SIZE = 4;
129
+ const SETTING_MAX_FRAME_SIZE = 5;
130
+ const expected = profile.http2.settings;
131
+ const checks = [
132
+ {
133
+ name: "MAX_CONCURRENT_STREAMS",
134
+ ok: settings.get(SETTING_MAX_CONCURRENT_STREAMS) === expected.maxConcurrentStreams,
135
+ },
136
+ {
137
+ name: "INITIAL_WINDOW_SIZE",
138
+ ok: settings.get(SETTING_INITIAL_WINDOW_SIZE) === expected.initialWindowSize,
139
+ },
140
+ {
141
+ name: "MAX_FRAME_SIZE",
142
+ ok: settings.get(SETTING_MAX_FRAME_SIZE) === expected.maxFrameSize,
143
+ },
144
+ ];
145
+ const failed = checks.filter((c) => !c.ok);
146
+ return result(id, failed.length === 0, Object.fromEntries(settings), {
147
+ maxConcurrentStreams: expected.maxConcurrentStreams,
148
+ initialWindowSize: expected.initialWindowSize,
149
+ maxFrameSize: expected.maxFrameSize,
150
+ }, failed.length === 0
151
+ ? undefined
152
+ : `Mismatched settings: ${failed.map((f) => f.name).join(", ")}`);
153
+ }
154
+ /**
155
+ * Run the HTTP/1.1 (RFC 9110) compliance checks against the chrome-140
156
+ * profile's header configuration. Verifies:
157
+ *
158
+ * 1. The `Host` header is present (required by RFC 9110 §7.2).
159
+ * 2. Header names are lowercase (HTTP/2 requires this; HTTP/1.1 convention).
160
+ * 3. No duplicate header names in the default set.
161
+ * 4. The header order list matches the default headers' key set.
6
162
  */
7
- /** Run the TLS 1.3 (RFC 8446) compliance checks. */
8
- export function runTlsCompliance(_id = "tls_rfc") {
9
- void _id;
10
- throw new Error("not implemented — see PLAN.md");
11
- }
12
- /** Run the HTTP/2 (RFC 9113) compliance checks. */
13
- export function runHttp2Compliance(_id = "http2_rfc") {
14
- void _id;
15
- throw new Error("not implemented — see PLAN.md");
16
- }
17
- /** Run the HTTP/1.1 (RFC 9110) compliance checks. */
18
- export function runHttp1Compliance(_id = "http1_rfc") {
19
- void _id;
20
- throw new Error("not implemented — see PLAN.md");
163
+ export function runHttp1Compliance(id = "http1_rfc", profileId = "chrome-140") {
164
+ const profile = getProfile(profileId);
165
+ const headers = profile.http1.defaultHeaders;
166
+ const headerOrder = profile.http1.headerOrder;
167
+ const issues = [];
168
+ // 1. Host header required (RFC 9110 §7.2). The Host header is set
169
+ // dynamically per-request (it depends on the target URL), so it appears
170
+ // in headerOrder but not in defaultHeaders. Check headerOrder for it.
171
+ const hasHost = headerOrder.some((h) => h.toLowerCase() === "host") ||
172
+ "host" in headers ||
173
+ "Host" in headers;
174
+ if (!hasHost) {
175
+ issues.push("missing required Host header");
176
+ }
177
+ // 2. Header names must be lowercase.
178
+ const nonLowercase = headerOrder.filter((h) => h !== h.toLowerCase());
179
+ if (nonLowercase.length > 0) {
180
+ issues.push(`non-lowercase header names: ${nonLowercase.join(", ")}`);
181
+ }
182
+ // 3. No duplicate header names in the default set.
183
+ const seen = new Set();
184
+ const duplicates = [];
185
+ for (const key of Object.keys(headers)) {
186
+ const lower = key.toLowerCase();
187
+ if (seen.has(lower)) {
188
+ duplicates.push(key);
189
+ }
190
+ seen.add(lower);
191
+ }
192
+ if (duplicates.length > 0) {
193
+ issues.push(`duplicate header names: ${duplicates.join(", ")}`);
194
+ }
195
+ // 4. Header order list should include every default header key.
196
+ const orderSet = new Set(headerOrder.map((h) => h.toLowerCase()));
197
+ const headersKeySet = new Set(Object.keys(headers).map((k) => k.toLowerCase()));
198
+ const missingInOrder = [];
199
+ for (const key of headersKeySet) {
200
+ if (!orderSet.has(key)) {
201
+ missingInOrder.push(key);
202
+ }
203
+ }
204
+ if (missingInOrder.length > 0) {
205
+ issues.push(`headers not in headerOrder: ${missingInOrder.join(", ")}`);
206
+ }
207
+ return result(id, issues.length === 0, { headerOrder, defaultHeaders: Object.keys(headers) }, "RFC 9110 compliant HTTP/1.1 request", issues.length === 0 ? undefined : issues.join("; "));
21
208
  }
22
209
  //# sourceMappingURL=rfcTests.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rfcTests.js","sourceRoot":"","sources":["../../src/rfc/rfcTests.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,oDAAoD;AACpD,MAAM,UAAU,gBAAgB,CAC5B,MAAmB,SAAmB;IAEtC,KAAK,GAAG,CAAC;IACT,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;AACrD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,kBAAkB,CAC9B,MAAmB,WAAqB;IAExC,KAAK,GAAG,CAAC;IACT,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;AACrD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAC9B,MAAmB,WAAqB;IAExC,KAAK,GAAG,CAAC;IACT,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"rfcTests.js","sourceRoot":"","sources":["../../src/rfc/rfcTests.ts"],"names":[],"mappings":"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"}