@browsercore/profiles 0.1.3 → 0.1.9

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 (42) hide show
  1. package/README.md +114 -11
  2. package/dist/codes.d.ts +40 -0
  3. package/dist/codes.d.ts.map +1 -0
  4. package/dist/codes.js +111 -0
  5. package/dist/codes.js.map +1 -0
  6. package/dist/diff.d.ts.map +1 -1
  7. package/dist/diff.js +11 -8
  8. package/dist/diff.js.map +1 -1
  9. package/dist/errors.d.ts.map +1 -1
  10. package/dist/errors.js.map +1 -1
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/profiles/chrome.d.ts +17 -4
  16. package/dist/profiles/chrome.d.ts.map +1 -1
  17. package/dist/profiles/chrome.js +68 -83
  18. package/dist/profiles/chrome.js.map +1 -1
  19. package/dist/profiles/edge.d.ts +2 -1
  20. package/dist/profiles/edge.d.ts.map +1 -1
  21. package/dist/profiles/edge.js +39 -41
  22. package/dist/profiles/edge.js.map +1 -1
  23. package/dist/profiles/firefox.d.ts +13 -3
  24. package/dist/profiles/firefox.d.ts.map +1 -1
  25. package/dist/profiles/firefox.js +48 -63
  26. package/dist/profiles/firefox.js.map +1 -1
  27. package/dist/profiles/safari.d.ts +6 -3
  28. package/dist/profiles/safari.d.ts.map +1 -1
  29. package/dist/profiles/safari.js +63 -46
  30. package/dist/profiles/safari.js.map +1 -1
  31. package/dist/registry.d.ts +4 -2
  32. package/dist/registry.d.ts.map +1 -1
  33. package/dist/registry.js +4 -2
  34. package/dist/registry.js.map +1 -1
  35. package/dist/utils.d.ts +2 -1
  36. package/dist/utils.d.ts.map +1 -1
  37. package/dist/utils.js.map +1 -1
  38. package/dist/validate.d.ts +8 -4
  39. package/dist/validate.d.ts.map +1 -1
  40. package/dist/validate.js +8 -62
  41. package/dist/validate.js.map +1 -1
  42. package/package.json +49 -44
package/README.md CHANGED
@@ -1,10 +1,14 @@
1
1
  # @browsercore/profiles
2
2
 
3
- Browser fingerprint definitions (TLS / HTTP/2 / HTTP/1.1). Pure data — no protocol implementation.
3
+ [![npm version](https://img.shields.io/npm/v/@browsercore/profiles)](https://www.npmjs.com/package/@browsercore/profiles)
4
+ [![coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jverneuer/browsercore-profiles/coverage/coverage/badge.json)](https://github.com/jverneuer/browsercore-profiles/blob/main/COVERAGE.md)
5
+ [![lint](https://img.shields.io/github/actions/workflow/status/jverneuer/browsercore-profiles/ci.yml?label=lint)](https://github.com/jverneuer/browsercore-profiles/actions/workflows/ci.yml)
6
+
7
+ Browser fingerprint definitions (TLS / HTTP/2 / HTTP/1.1). Pure data — no protocol implementation lives here. Higher layers read these definitions and translate them into bytes, header order, and SETTINGS frames.
4
8
 
5
9
  ## Responsibility
6
10
 
7
- Define WHAT a browser fingerprint looks like so that higher layers (tls, http1, http2) can translate it into bytes, header order, and SETTINGS frames. Adding a new Chrome version means adding a new entry here — protocol implementations never change.
11
+ Define WHAT a browser fingerprint looks like: ordered cipher suites, TLS extension order, GREASE behavior, HTTP/2 SETTINGS, and HTTP/1.1 header order. Adding a new Chrome version means adding a new entry here — protocol implementations never change.
8
12
 
9
13
  ## What it does NOT know about
10
14
 
@@ -13,34 +17,64 @@ Define WHAT a browser fingerprint looks like so that higher layers (tls, http1,
13
17
  - Sockets or I/O
14
18
  - Cookies
15
19
 
16
- ## Public API
20
+ ## Install
21
+
22
+ ```bash
23
+ npm install @browsercore/profiles
24
+ ```
25
+
26
+ ## Quick usage
17
27
 
18
28
  ```ts
19
29
  import { getProfile, listProfiles, registerProfile } from "@browsercore/profiles";
30
+ import type { ProfileId } from "@browsercore/profiles";
20
31
 
21
32
  const chrome = getProfile("chrome-140" as ProfileId);
22
33
  console.log(chrome.tls.cipherSuites); // ordered cipher list
23
- console.log(chrome.http2.settings); // HTTP/2 SETTINGS frame values
34
+ console.log(chrome.http2.settings); // HTTP/2 SETTINGS frame values
24
35
 
25
- const all = listProfiles(); // ["chrome-120", "chrome-128", ...]
36
+ const all = listProfiles(); // ["chrome-120", "chrome-128", ...] — insertion order
26
37
 
27
38
  registerProfile(myCustomProfile); // extensibility hook
28
39
  ```
29
40
 
30
- ## Types
41
+ ## Public API
31
42
 
32
43
  | Export | Kind | Purpose |
33
44
  | --- | --- | --- |
45
+ | `getProfile()` | function | Look up a profile by id (throws `UnknownProfileError` if absent) |
46
+ | `listProfiles()` | function | List every registered id, in insertion order |
47
+ | `registerProfile()` | function | Register or overwrite a custom profile at runtime |
48
+ | `diffProfiles()` | function | Field-by-field diff of two profiles, reporting each differing path |
49
+ | `DiffOptions` | interface | Diff tuning (e.g. order-sensitive vs. multiset array comparison) |
50
+ | `ProfileDiff` | interface | A single difference located by its dotted path |
51
+ | `buildExpectedClientHello()` | function | Project a profile's TLS fields onto expected wire codes |
52
+ | `validateProfileAgainstCapture()` | function | Validate a profile against a captured ClientHello |
53
+ | `ValidationResult` | interface | `{ ok, diffs }` outcome of validation |
54
+ | `TlsCapture` | interface | A captured ClientHello parsed out of a packet capture |
55
+ | `ClientHelloExpected` | interface | The wire values a profile's ClientHello should carry |
34
56
  | `BrowserProfile` | interface | Complete fingerprint across TLS + HTTP/2 + HTTP/1.1 |
35
57
  | `TlsProfile` | interface | Cipher order, extensions, GREASE, signature algorithms |
36
58
  | `Http2Profile` | interface | SETTINGS, window sizes, priority |
59
+ | `Http2Settings` | interface | HTTP/2 numeric settings (RFC 9113 §6.5.1) |
60
+ | `Http2Priority` | interface | Stream priority descriptor |
37
61
  | `Http1Profile` | interface | Default headers, header order, accept-encoding |
38
- | `ProfileId` | branded string | Opaque profile identifier |
62
+ | `ProfileId` | branded type | Opaque profile identifier (`"chrome-140"`) |
39
63
  | `ProfileName` | literal union | `"chrome" \| "firefox" \| "safari" \| "edge"` |
40
- | `getProfile()` | function | Look up a profile by id |
41
- | `listProfiles()` | function | List all registered ids |
42
- | `registerProfile()` | function | Add a custom profile at runtime |
64
+ | `ChromeProfiles` / `FirefoxProfiles` / `SafariProfiles` / `EdgeProfiles` | const maps | Per-browser profile definitions |
65
+ | `assertNever()` | function | Exhaustiveness check for switches over unions |
66
+ | `ProfileError` | class | Base typed error (matched on `kind`) |
43
67
  | `UnknownProfileError` | class | Thrown when a profile id is not found |
68
+ | `ValidationError` | class | Thrown on an unknown profile value or bad capture |
69
+
70
+ ## Shipped profiles
71
+
72
+ | Browser | Profiles |
73
+ | --- | --- |
74
+ | Chrome | `chrome-120`, `chrome-128`, `chrome-140` |
75
+ | Firefox | `firefox-120`, `firefox-128`, `firefox-135` |
76
+ | Safari | `safari-17`, `safari-18` |
77
+ | Edge | `edge-120`, `edge-128` |
44
78
 
45
79
  ## Dependency graph
46
80
 
@@ -48,4 +82,73 @@ registerProfile(myCustomProfile); // extensibility hook
48
82
  @browsercore/profiles
49
83
  ```
50
84
 
51
- No other `@browsercore/*` packages and no Node built-ins are imported. This is a pure data package.
85
+ No other `@browsercore/*` runtime packages and no Node built-ins are imported. This is a pure data package. `@browsercore/dev` is a dev-only dependency that supplies shared build / lint / test configuration (see [Shared config](#shared-config)).
86
+
87
+ ## Source layout
88
+
89
+ ```
90
+ src/
91
+ ├─ index.ts Public API surface — re-exports from the rest of the package
92
+ ├─ index.internal.ts Barrel re-exporting the per-browser profile maps
93
+ ├─ registry.ts getProfile / listProfiles / registerProfile (Map-backed)
94
+ ├─ diff.ts diffProfiles — field-by-field diff of two profiles
95
+ ├─ validate.ts buildExpectedClientHello / validateProfileAgainstCapture
96
+ ├─ codes.ts IANA TLS registry codes (cipher suites, groups, versions, sig schemes)
97
+ ├─ errors.ts ProfileError / UnknownProfileError / ValidationError
98
+ ├─ types.ts BrowserProfile + per-layer profile interfaces
99
+ ├─ utils.ts assertNever / createId
100
+ └─ profiles/ Per-browser profile definitions
101
+ ├─ chrome.ts chrome-120, chrome-128, chrome-140
102
+ ├─ firefox.ts firefox-120, firefox-128, firefox-135
103
+ ├─ safari.ts safari-17, safari-18
104
+ └─ edge.ts edge-120, edge-128
105
+ ```
106
+
107
+ ## Development
108
+
109
+ Requires **Node >= 26**. ESM only (`"type": "module"`).
110
+
111
+ ```sh
112
+ npm install # installs @browsercore/dev (file:../dev) + siblings
113
+ npm run build # tsc -p tsconfig.build.json (emit to dist/)
114
+ npm run typecheck
115
+ npm run lint # oxlint --type-aware src/
116
+ npm test # vitest run
117
+ ```
118
+
119
+ Run a single test file:
120
+
121
+ ```sh
122
+ npx vitest run tests/profiles.test.ts
123
+ ```
124
+
125
+ Run tests by name pattern:
126
+
127
+ ```sh
128
+ npx vitest run -t "returns a known Chrome profile by id"
129
+ ```
130
+
131
+ Generate a coverage report:
132
+
133
+ ```sh
134
+ npm test -- --coverage
135
+ node ../dev/bin/coverage-md.mjs # writes COVERAGE.md + coverage/badge.json
136
+ ```
137
+
138
+ ### Shared config
139
+
140
+ This package adopts `@browsercore/dev`, the shared config package for the
141
+ `@browsercore/*` family. Configuration is centralized — this repo only wires it in:
142
+
143
+ | Concern | Mechanism |
144
+ | --- | --- |
145
+ | TypeScript strict flags | `tsconfig.json` extends `@browsercore/dev/tsconfig.base.json` |
146
+ | Vitest config | `vitest.config.ts` calls `definePackageConfig({ name: "profiles" })` |
147
+ | Oxlint config | `oxlint.config.ts` extends `@browsercore/dev/oxlint` |
148
+ | Coverage report | `coverage-md` bin from `@browsercore/dev` |
149
+
150
+ `@browsercore/dev` is declared as a devDependency via `"@browsercore/dev": "file:../dev"`.
151
+
152
+ ## License
153
+
154
+ MIT
@@ -0,0 +1,40 @@
1
+ /**
2
+ * IANA TLS registry codes used to project profile names onto wire values.
3
+ *
4
+ * These are the canonical 2-byte codes from the IANA TLS parameter registries.
5
+ * Only the codes referenced by the shipped profiles are mapped here — an
6
+ * unknown name is a bug in a profile definition and surfaces as a
7
+ * {@link ValidationError} at projection time, so the tables double as an
8
+ * allow-list that keeps profile data honest.
9
+ *
10
+ * Registries:
11
+ * - Cipher suites: tls-parameters.xhtml#tls-parameters-4
12
+ * - Named groups: tls-parameters.xhtml#tls-parameters-8
13
+ * - Signature schemes: tls-parameters.xhtml#tls-parameters-16
14
+ */
15
+ /**
16
+ * The name Chrome/Edge use in their cipher list to mark a GREASE slot (RFC 8701).
17
+ * The real value is randomized per-connection (0x0a0a..0xfafa); validation accepts
18
+ * any GREASE-pattern byte pair at a slot marked with this placeholder.
19
+ */
20
+ export declare const CIPHER_GREASE_PLACEHOLDER = "TLS_GREASE_RESERVED_0";
21
+ /** Selected IANA TLS Cipher Suite codes, keyed by the canonical suite name used in profiles. */
22
+ export declare const CIPHER_SUITE_CODES: Readonly<Record<string, number>>;
23
+ /** Selected IANA TLS Supported Groups (named groups) codes. */
24
+ export declare const NAMED_GROUP_CODES: Readonly<Record<string, number>>;
25
+ /** Selected IANA TLS SignatureScheme codes. */
26
+ export declare const SIGNATURE_SCHEME_CODES: Readonly<Record<string, number>>;
27
+ /** IANA TLS ProtocolVersion codes for the supported_versions extension. */
28
+ export declare const VERSION_CODES: Readonly<Record<string, number>>;
29
+ /**
30
+ * Map a cipher-suite name to its 2-byte IANA wire code.
31
+ *
32
+ * This is the single projection seam from a profile's cipher name to the bytes
33
+ * a ClientHello carries. It throws on an unknown name rather than returning a
34
+ * sentinel: 0x0000 would be ambiguous (it collides with
35
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV), and a silent default would hide a bug in
36
+ * a profile definition. An unknown name is therefore always an error here,
37
+ * never a 0x0000 fallback.
38
+ */
39
+ export declare function cipherSuiteToWire(name: string): number;
40
+ //# sourceMappingURL=codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE,gGAAgG;AAChG,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkC/D,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAY9D,CAAC;AAEF,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAanE,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK1D,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtD"}
package/dist/codes.js ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * IANA TLS registry codes used to project profile names onto wire values.
3
+ *
4
+ * These are the canonical 2-byte codes from the IANA TLS parameter registries.
5
+ * Only the codes referenced by the shipped profiles are mapped here — an
6
+ * unknown name is a bug in a profile definition and surfaces as a
7
+ * {@link ValidationError} at projection time, so the tables double as an
8
+ * allow-list that keeps profile data honest.
9
+ *
10
+ * Registries:
11
+ * - Cipher suites: tls-parameters.xhtml#tls-parameters-4
12
+ * - Named groups: tls-parameters.xhtml#tls-parameters-8
13
+ * - Signature schemes: tls-parameters.xhtml#tls-parameters-16
14
+ */
15
+ import { ProfileError } from "./errors.js";
16
+ /**
17
+ * The name Chrome/Edge use in their cipher list to mark a GREASE slot (RFC 8701).
18
+ * The real value is randomized per-connection (0x0a0a..0xfafa); validation accepts
19
+ * any GREASE-pattern byte pair at a slot marked with this placeholder.
20
+ */
21
+ export const CIPHER_GREASE_PLACEHOLDER = "TLS_GREASE_RESERVED_0";
22
+ /** Selected IANA TLS Cipher Suite codes, keyed by the canonical suite name used in profiles. */
23
+ export const CIPHER_SUITE_CODES = {
24
+ // GREASE: real value is randomized per-connection (0x0a0a..0xfafa). We use the
25
+ // first canonical GREASE code for the expected representation; validation
26
+ // accepts any GREASE-pattern value at a GREASE slot.
27
+ [CIPHER_GREASE_PLACEHOLDER]: 0x0a0a,
28
+ TLS_AES_128_GCM_SHA256: 0x1301,
29
+ TLS_AES_256_GCM_SHA384: 0x1302,
30
+ TLS_CHACHA20_POLY1305_SHA256: 0x1303,
31
+ TLS_AES_128_CCM_SHA256: 0x1304,
32
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: 0xc02b,
33
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: 0xc02f,
34
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: 0xc02c,
35
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: 0xc030,
36
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: 0xcca9,
37
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: 0xcca8,
38
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: 0xc013,
39
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: 0xc014,
40
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: 0xc009,
41
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: 0xc00a,
42
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: 0xc023,
43
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: 0xc024,
44
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: 0xc027,
45
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: 0xc028,
46
+ TLS_RSA_WITH_AES_128_GCM_SHA256: 0x009c,
47
+ TLS_RSA_WITH_AES_256_GCM_SHA384: 0x009d,
48
+ TLS_RSA_WITH_AES_128_CBC_SHA: 0x002f,
49
+ TLS_RSA_WITH_AES_256_CBC_SHA: 0x0035,
50
+ TLS_RSA_WITH_AES_128_CBC_SHA256: 0x003c,
51
+ TLS_RSA_WITH_AES_256_CBC_SHA256: 0x003d,
52
+ // Safari legacy tail: 3DES ciphers (RFC 3268). BoringSSL dropped these, but
53
+ // curl-impersonate restores them so Safari's ClientHello matches byte-for-byte.
54
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: 0xc008,
55
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: 0xc012,
56
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA: 0x000a,
57
+ };
58
+ /** Selected IANA TLS Supported Groups (named groups) codes. */
59
+ export const NAMED_GROUP_CODES = {
60
+ x25519: 0x001d,
61
+ secp256r1: 0x0017,
62
+ secp384r1: 0x0018,
63
+ secp521r1: 0x0019,
64
+ ffdhe2048: 0x0100,
65
+ ffdhe3072: 0x0101,
66
+ // Chrome 124+ adds the hybrid post-quantum group. The draft Kyber768 code
67
+ // (0x6399) shipped in Chrome 124–130; the final MLKEM768 code (0x11ec) has
68
+ // been used since Chrome 131. Both appear at the front of the group list.
69
+ X25519Kyber768: 0x6399,
70
+ X25519MLKEM768: 0x11ec,
71
+ };
72
+ /** Selected IANA TLS SignatureScheme codes. */
73
+ export const SIGNATURE_SCHEME_CODES = {
74
+ ecdsa_secp256r1_sha256: 0x0403,
75
+ ecdsa_secp384r1_sha384: 0x0503,
76
+ ecdsa_secp521r1_sha512: 0x0603,
77
+ ecdsa_sha1: 0x0203,
78
+ rsa_pss_rsae_sha256: 0x0804,
79
+ rsa_pss_rsae_sha384: 0x0805,
80
+ rsa_pss_rsae_sha512: 0x0806,
81
+ rsa_pkcs1_sha256: 0x0401,
82
+ rsa_pkcs1_sha384: 0x0501,
83
+ rsa_pkcs1_sha512: 0x0601,
84
+ rsa_pkcs1_sha1: 0x0201,
85
+ ed25519: 0x0807,
86
+ };
87
+ /** IANA TLS ProtocolVersion codes for the supported_versions extension. */
88
+ export const VERSION_CODES = {
89
+ "TLS 1.3": 0x0304,
90
+ "TLS 1.2": 0x0303,
91
+ "TLS 1.1": 0x0302,
92
+ "TLS 1.0": 0x0301,
93
+ };
94
+ /**
95
+ * Map a cipher-suite name to its 2-byte IANA wire code.
96
+ *
97
+ * This is the single projection seam from a profile's cipher name to the bytes
98
+ * a ClientHello carries. It throws on an unknown name rather than returning a
99
+ * sentinel: 0x0000 would be ambiguous (it collides with
100
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV), and a silent default would hide a bug in
101
+ * a profile definition. An unknown name is therefore always an error here,
102
+ * never a 0x0000 fallback.
103
+ */
104
+ export function cipherSuiteToWire(name) {
105
+ const code = CIPHER_SUITE_CODES[name];
106
+ if (code === undefined) {
107
+ throw new ProfileError("UnknownCipherSuite", `Unknown cipher suite: ${name}`);
108
+ }
109
+ return code;
110
+ }
111
+ //# sourceMappingURL=codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.js","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,uBAAuB,CAAC;AAEjE,gGAAgG;AAChG,MAAM,CAAC,MAAM,kBAAkB,GAAqC;IAChE,+EAA+E;IAC/E,0EAA0E;IAC1E,qDAAqD;IACrD,CAAC,yBAAyB,CAAC,EAAE,MAAM;IACnC,sBAAsB,EAAE,MAAM;IAC9B,sBAAsB,EAAE,MAAM;IAC9B,4BAA4B,EAAE,MAAM;IACpC,sBAAsB,EAAE,MAAM;IAC9B,uCAAuC,EAAE,MAAM;IAC/C,qCAAqC,EAAE,MAAM;IAC7C,uCAAuC,EAAE,MAAM;IAC/C,qCAAqC,EAAE,MAAM;IAC7C,6CAA6C,EAAE,MAAM;IACrD,2CAA2C,EAAE,MAAM;IACnD,kCAAkC,EAAE,MAAM;IAC1C,kCAAkC,EAAE,MAAM;IAC1C,oCAAoC,EAAE,MAAM;IAC5C,oCAAoC,EAAE,MAAM;IAC5C,uCAAuC,EAAE,MAAM;IAC/C,uCAAuC,EAAE,MAAM;IAC/C,qCAAqC,EAAE,MAAM;IAC7C,qCAAqC,EAAE,MAAM;IAC7C,+BAA+B,EAAE,MAAM;IACvC,+BAA+B,EAAE,MAAM;IACvC,4BAA4B,EAAE,MAAM;IACpC,4BAA4B,EAAE,MAAM;IACpC,+BAA+B,EAAE,MAAM;IACvC,+BAA+B,EAAE,MAAM;IACvC,4EAA4E;IAC5E,gFAAgF;IAChF,qCAAqC,EAAE,MAAM;IAC7C,mCAAmC,EAAE,MAAM;IAC3C,6BAA6B,EAAE,MAAM;CACxC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,iBAAiB,GAAqC;IAC/D,MAAM,EAAE,MAAM;IACd,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,0EAA0E;IAC1E,2EAA2E;IAC3E,0EAA0E;IAC1E,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,MAAM;CACzB,CAAC;AAEF,+CAA+C;AAC/C,MAAM,CAAC,MAAM,sBAAsB,GAAqC;IACpE,sBAAsB,EAAE,MAAM;IAC9B,sBAAsB,EAAE,MAAM;IAC9B,sBAAsB,EAAE,MAAM;IAC9B,UAAU,EAAE,MAAM;IAClB,mBAAmB,EAAE,MAAM;IAC3B,mBAAmB,EAAE,MAAM;IAC3B,mBAAmB,EAAE,MAAM;IAC3B,gBAAgB,EAAE,MAAM;IACxB,gBAAgB,EAAE,MAAM;IACxB,gBAAgB,EAAE,MAAM;IACxB,cAAc,EAAE,MAAM;IACtB,OAAO,EAAE,MAAM;CAClB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAqC;IAC3D,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;CACpB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC1C,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACrB,MAAM,IAAI,YAAY,CAAC,oBAAoB,EAAE,yBAAyB,IAAI,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qDAAqD;AACrD,MAAM,WAAW,WAAW;IACxB;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACvB;AAyJD;;;;;;GAMG;AACH,wBAAgB,YAAY,CACxB,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,OAAO,GAAE,WAAgB,GAC1B,WAAW,EAAE,CAIf"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qDAAqD;AACrD,MAAM,WAAW,WAAW;IACxB;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACvB;AA+JD;;;;;;GAMG;AACH,wBAAgB,YAAY,CACxB,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,OAAO,GAAE,WAAgB,GAC1B,WAAW,EAAE,CAIf"}
package/dist/diff.js CHANGED
@@ -23,10 +23,12 @@ function emit(out, path, a, b) {
23
23
  /** Sorted union of own-property keys from both objects, for deterministic output. */
24
24
  function unionKeys(a, b) {
25
25
  const keys = new Set();
26
- for (const k of Object.keys(a))
26
+ for (const k of Object.keys(a)) {
27
27
  keys.add(k);
28
- for (const k of Object.keys(b))
28
+ }
29
+ for (const k of Object.keys(b)) {
29
30
  keys.add(k);
31
+ }
30
32
  return Array.from(keys).sort();
31
33
  }
32
34
  /**
@@ -34,8 +36,9 @@ function unionKeys(a, b) {
34
36
  * Reference equality (`===`) short-circuits identical subtrees.
35
37
  */
36
38
  function walk(path, a, b, options, out) {
37
- if (a === b)
39
+ if (a === b) {
38
40
  return;
41
+ }
39
42
  const aArr = isArray(a);
40
43
  const bArr = isArray(b);
41
44
  if (aArr && bArr) {
@@ -56,7 +59,7 @@ function walk(path, a, b, options, out) {
56
59
  walk(childPath, a[key], b[key], options, out);
57
60
  }
58
61
  else if (aHas) {
59
- emit(out, childPath, a[key], undefined);
62
+ emit(out, childPath, a[key]);
60
63
  }
61
64
  else {
62
65
  emit(out, childPath, undefined, b[key]);
@@ -82,7 +85,7 @@ function walkArray(path, a, b, options, out) {
82
85
  walk(childPath, a[i], b[i], options, out);
83
86
  }
84
87
  else if (aHas) {
85
- emit(out, childPath, a[i], undefined);
88
+ emit(out, childPath, a[i]);
86
89
  }
87
90
  else {
88
91
  emit(out, childPath, undefined, b[i]);
@@ -93,8 +96,8 @@ function walkArray(path, a, b, options, out) {
93
96
  // Unordered: compare as multisets of serialized keys. A single whole-array
94
97
  // diff is reported when membership differs.
95
98
  const sortKey = (v) => isObject(v) || isArray(v) ? stableStringify(v) : String(v);
96
- const sortedA = a.map(sortKey).sort();
97
- const sortedB = b.map(sortKey).sort();
99
+ const sortedA = a.map((v) => sortKey(v)).sort();
100
+ const sortedB = b.map((v) => sortKey(v)).sort();
98
101
  let equal = sortedA.length === sortedB.length;
99
102
  if (equal) {
100
103
  for (let i = 0; i < sortedA.length; i++) {
@@ -114,7 +117,7 @@ function stableStringify(value) {
114
117
  }
115
118
  function sortValue(value) {
116
119
  if (isArray(value)) {
117
- return value.map(sortValue);
120
+ return value.map((v) => sortValue(v));
118
121
  }
119
122
  if (isObject(value)) {
120
123
  const sorted = {};
package/dist/diff.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iEAAiE;AACjE,qBAAa,YAAa,SAAQ,KAAK;IACnC,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAyB,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;gBAG9C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE;CAOlC;AAED,6DAA6D;AAC7D,qBAAa,mBAAoB,SAAQ,YAAY;IACjD,SAAyB,IAAI,EAAG,qBAAqB,CAAU;IAC/D,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAEtB,SAAS,EAAE,MAAM;CAKhC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iEAAiE;AACjE,qBAAa,YAAa,SAAQ,KAAK;IACnC,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAyB,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAElD,YACI,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,EAM9B;CACJ;AAED,6DAA6D;AAC7D,qBAAa,mBAAoB,SAAQ,YAAY;IACjD,SAAyB,IAAI,EAAG,qBAAqB,CAAU;IAC/D,SAAgB,SAAS,EAAE,MAAM,CAAC;IAElC,YAAY,SAAS,EAAE,MAAM,EAI5B;CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iEAAiE;AACjE,MAAM,OAAO,YAAa,SAAQ,KAAK;IACnB,IAAI,CAAS;IACJ,KAAK,CAAoB;IAElD,YACI,IAAY,EACZ,OAAe,EACf,OAA2B;QAE3B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC;IAChC,CAAC;CACJ;AAED,6DAA6D;AAC7D,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACxB,IAAI,GAAG,qBAA8B,CAAC;IAC/C,SAAS,CAAS;IAElC,YAAY,SAAiB;QACzB,KAAK,CAAC,qBAAqB,EAAE,4BAA4B,SAAS,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;CACJ"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iEAAiE;AACjE,MAAM,OAAO,YAAa,SAAQ,KAAK;IACnB,IAAI,CAAS;IACJ,KAAK,CAAoB;IAElD,YACI,IAAY,EACZ,OAAe,EACf,OAA2B;QAE3B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC;IAChC,CAAC;CACJ;AAED,6DAA6D;AAC7D,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACxB,IAAI,GAAG,qBAA8B,CAAC;IAC/C,SAAS,CAAS;IAElC,YAAY,SAAiB;QACzB,KAAK,CAAC,qBAAqB,EAAE,4BAA4B,SAAS,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;CACJ"}
package/dist/index.d.ts CHANGED
@@ -9,7 +9,8 @@ export { getProfile, listProfiles, registerProfile, } from "./registry.js";
9
9
  export { diffProfiles, } from "./diff.js";
10
10
  export type { DiffOptions, ProfileDiff, } from "./diff.js";
11
11
  export { buildExpectedClientHello, validateProfileAgainstCapture, ValidationError, } from "./validate.js";
12
- export type { TlsCapture, ClientHelloExpected, } from "./validate.js";
12
+ export type { TlsCapture, ClientHelloExpected, ValidationResult, } from "./validate.js";
13
+ export { cipherSuiteToWire, CIPHER_GREASE_PLACEHOLDER, CIPHER_SUITE_CODES, NAMED_GROUP_CODES, SIGNATURE_SCHEME_CODES, VERSION_CODES, } from "./codes.js";
13
14
  export { ChromeProfiles, FirefoxProfiles, SafariProfiles, EdgeProfiles, } from "./index.internal.js";
14
15
  export { ProfileError, UnknownProfileError, } from "./errors.js";
15
16
  export type { BrowserProfile, Http1Profile, Http2Profile, Http2Settings, Http2Priority, ProfileId, ProfileName, TlsProfile, } from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,YAAY,GACf,MAAM,WAAW,CAAC;AAEnB,YAAY,EACR,WAAW,EACX,WAAW,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EACH,wBAAwB,EACxB,6BAA6B,EAC7B,eAAe,GAClB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACR,UAAU,EACV,mBAAmB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,YAAY,EACZ,mBAAmB,GACtB,MAAM,aAAa,CAAC;AAErB,YAAY,EACR,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,EACb,SAAS,EACT,WAAW,EACX,UAAU,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,YAAY,GACf,MAAM,WAAW,CAAC;AAEnB,YAAY,EACR,WAAW,EACX,WAAW,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EACH,wBAAwB,EACxB,6BAA6B,EAC7B,eAAe,GAClB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACR,UAAU,EACV,mBAAmB,EACnB,gBAAgB,GACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,YAAY,EACZ,mBAAmB,GACtB,MAAM,aAAa,CAAC;AAErB,YAAY,EACR,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,EACb,SAAS,EACT,WAAW,EACX,UAAU,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@
8
8
  export { getProfile, listProfiles, registerProfile, } from "./registry.js";
9
9
  export { diffProfiles, } from "./diff.js";
10
10
  export { buildExpectedClientHello, validateProfileAgainstCapture, ValidationError, } from "./validate.js";
11
+ export { cipherSuiteToWire, CIPHER_GREASE_PLACEHOLDER, CIPHER_SUITE_CODES, NAMED_GROUP_CODES, SIGNATURE_SCHEME_CODES, VERSION_CODES, } from "./codes.js";
11
12
  export { ChromeProfiles, FirefoxProfiles, SafariProfiles, EdgeProfiles, } from "./index.internal.js";
12
13
  export { ProfileError, UnknownProfileError, } from "./errors.js";
13
14
  export { assertNever } from "./utils.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,YAAY,GACf,MAAM,WAAW,CAAC;AAOnB,OAAO,EACH,wBAAwB,EACxB,6BAA6B,EAC7B,eAAe,GAClB,MAAM,eAAe,CAAC;AAOvB,OAAO,EACH,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,YAAY,EACZ,mBAAmB,GACtB,MAAM,aAAa,CAAC;AAarB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,YAAY,GACf,MAAM,WAAW,CAAC;AAOnB,OAAO,EACH,wBAAwB,EACxB,6BAA6B,EAC7B,eAAe,GAClB,MAAM,eAAe,CAAC;AAQvB,OAAO,EACH,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,YAAY,EACZ,mBAAmB,GACtB,MAAM,aAAa,CAAC;AAarB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -1,10 +1,23 @@
1
1
  /**
2
2
  * Chrome fingerprint definitions.
3
3
  *
4
- * TLS values mirror real Chrome ClientHello captures (JA3 / JA4 style). Chrome
5
- * enables GREASE (RFC 8701), advertises TLS 1.3, and sends a stable cipher order
6
- * per release. HTTP/2 settings track Chrome's real SETTINGS frame. Values are
7
- * accurate for the listed versions unless noted otherwise.
4
+ * TLS values are byte-accurate against real curl-impersonate ClientHello
5
+ * captures. The authoritative ground truth is the lwthiker/curl-impersonate
6
+ * wire captures (testing-worktree/captures/_probe/output/chrome*.json) together
7
+ * with their reported ja3 / ja4 / peetprint fingerprints. Every value here is
8
+ * verified against those captures:
9
+ *
10
+ * - chrome-120: ja3 698f6d684588ddc1217dfb4454916129, peetprint
11
+ * 8ad9325e12f531d2983b78860de7b0ec (no post-quantum group).
12
+ * - chrome-124..130: X25519Kyber768 (0x6399) added to supported_groups.
13
+ * - chrome-131+: X25519MLKEM768 (0x11ec) replaces Kyber768; the
14
+ * application_settings extension moves from 17513 to 17613.
15
+ *
16
+ * Chrome permutes its extension order at runtime (tls_permute_extensions), so
17
+ * `extensionOrder` stores the canonical pre-permutation seed that
18
+ * curl-impersonate configures — matching the peetprint's normalized order.
19
+ * GREASE slots are tracked separately via the `grease` flag; the runtime
20
+ * randomizes the actual 0x?a?a values per RFC 8701.
8
21
  */
9
22
  import type { BrowserProfile } from "../types.js";
10
23
  export declare const chrome120: BrowserProfile;
@@ -1 +1 @@
1
- {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/profiles/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,aAAa,CAAC;AAkD7D,eAAO,MAAM,SAAS,EAAE,cAoDvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,cAoDvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,cAoDvB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;CAIjB,CAAC"}
1
+ {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/profiles/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,aAAa,CAAC;AAwF7D,eAAO,MAAM,SAAS,EAAE,cA+BvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,cA+BvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,cA+BvB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;CAIjB,CAAC"}