@browsercore/profiles 0.1.9 → 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.
- package/README.md +1 -1
- package/dist/codes.d.ts +44 -4
- package/dist/codes.d.ts.map +1 -1
- package/dist/codes.js +44 -4
- package/dist/codes.js.map +1 -1
- package/dist/diff.d.ts +25 -1
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +16 -0
- package/dist/diff.js.map +1 -1
- package/dist/errors.d.ts +50 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +50 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles/chrome.d.ts.map +1 -1
- package/dist/profiles/chrome.js +7 -0
- package/dist/profiles/chrome.js.map +1 -1
- package/dist/profiles/edge.d.ts.map +1 -1
- package/dist/profiles/edge.js +7 -0
- package/dist/profiles/edge.js.map +1 -1
- package/dist/profiles/firefox.d.ts.map +1 -1
- package/dist/profiles/firefox.js +20 -0
- package/dist/profiles/firefox.js.map +1 -1
- package/dist/profiles/safari.d.ts.map +1 -1
- package/dist/profiles/safari.js +6 -0
- package/dist/profiles/safari.js.map +1 -1
- package/dist/registry.d.ts +57 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +57 -4
- package/dist/registry.js.map +1 -1
- package/dist/types.d.ts +55 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +36 -4
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +36 -4
- package/dist/utils.js.map +1 -1
- package/dist/validate.d.ts +62 -7
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +67 -6
- package/dist/validate.js.map +1 -1
- package/package.json +3 -3
package/dist/validate.js
CHANGED
|
@@ -19,6 +19,10 @@ import { CIPHER_GREASE_PLACEHOLDER, CIPHER_SUITE_CODES, NAMED_GROUP_CODES, SIGNA
|
|
|
19
19
|
/** Validation / projection failure (unknown profile value, bad capture, etc.). */
|
|
20
20
|
export class ValidationError extends ProfileError {
|
|
21
21
|
kind = "ValidationError";
|
|
22
|
+
/**
|
|
23
|
+
* @param message - Description of what failed to validate or project.
|
|
24
|
+
* @param options - `cause` wraps the underlying error.
|
|
25
|
+
*/
|
|
22
26
|
constructor(message, options) {
|
|
23
27
|
super("ValidationError", message, options);
|
|
24
28
|
this.name = "ValidationError";
|
|
@@ -49,9 +53,26 @@ function mapVersion(name) {
|
|
|
49
53
|
}
|
|
50
54
|
/**
|
|
51
55
|
* Project a profile's TLS fields onto the wire values its ClientHello should
|
|
52
|
-
* carry for a connection to `serverName`.
|
|
53
|
-
*
|
|
54
|
-
*
|
|
56
|
+
* carry for a connection to `serverName`.
|
|
57
|
+
*
|
|
58
|
+
* Extension order is taken verbatim from the profile (already stored as wire
|
|
59
|
+
* codes), since extension order is a fingerprint signal. Cipher suites, named
|
|
60
|
+
* groups, signature schemes, and TLS versions are projected through the IANA
|
|
61
|
+
* code tables in {@link codes.ts}.
|
|
62
|
+
*
|
|
63
|
+
* @param profile - The {@link BrowserProfile} to project.
|
|
64
|
+
* @param serverName - The SNI server name the connection targets.
|
|
65
|
+
* @returns The {@link ClientHelloExpected} wire values.
|
|
66
|
+
* @throws {ValidationError} If the profile references an unknown cipher suite,
|
|
67
|
+
* named group, signature scheme, or TLS version.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const expected = buildExpectedClientHello(chrome140, "example.com");
|
|
72
|
+
* // expected.cipherSuites = [0x1301, 0x1302, ...]
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @since 0.1.0
|
|
55
76
|
*/
|
|
56
77
|
export function buildExpectedClientHello(profile, serverName) {
|
|
57
78
|
return {
|
|
@@ -61,6 +82,14 @@ export function buildExpectedClientHello(profile, serverName) {
|
|
|
61
82
|
keyShareGroups: profile.tls.keyShareGroups.map(mapNamedGroup),
|
|
62
83
|
signatureAlgorithms: profile.tls.signatureAlgorithms.map(mapSignatureScheme),
|
|
63
84
|
grease: profile.tls.grease,
|
|
85
|
+
// Conditionally spread optional fields so absent properties are truly
|
|
86
|
+
// absent (exactOptionalPropertyTypes forbids assigning undefined).
|
|
87
|
+
...(profile.tls.ecPointFormats
|
|
88
|
+
? { ecPointFormats: Array.from(profile.tls.ecPointFormats) }
|
|
89
|
+
: {}),
|
|
90
|
+
...(profile.tls.compressCertificateAlgorithms
|
|
91
|
+
? { compressCertificateAlgorithms: Array.from(profile.tls.compressCertificateAlgorithms) }
|
|
92
|
+
: {}),
|
|
64
93
|
sni: serverName,
|
|
65
94
|
};
|
|
66
95
|
}
|
|
@@ -111,9 +140,31 @@ function diffCipherSuites(profile, expected, capture, out) {
|
|
|
111
140
|
/**
|
|
112
141
|
* Validate a profile against a captured ClientHello.
|
|
113
142
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
143
|
+
* Projects the profile to expected wire values (via {@link buildExpectedClientHello})
|
|
144
|
+
* and compares them field-by-field against the capture. Returns `ok: true` when
|
|
145
|
+
* every field matches (respecting GREASE randomization for cipher suites), and
|
|
146
|
+
* the list of diffs otherwise.
|
|
147
|
+
*
|
|
148
|
+
* SNI is not compared because captures do not record the destination hostname.
|
|
149
|
+
*
|
|
150
|
+
* @param profile - The {@link BrowserProfile} to validate.
|
|
151
|
+
* @param capture - A {@link TlsCapture} parsed from a packet capture.
|
|
152
|
+
* @returns A {@link ValidationResult} indicating match/mismatch.
|
|
153
|
+
* @throws {ValidationError} If the profile references an unknown cipher suite,
|
|
154
|
+
* named group, signature scheme, or TLS version.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* const result = validateProfileAgainstCapture(chrome140, capture);
|
|
159
|
+
* if (!result.ok) {
|
|
160
|
+
* for (const d of result.diffs) {
|
|
161
|
+
* console.log(`${d.path}: expected ${d.a}, got ${d.b}`);
|
|
162
|
+
* }
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* @see buildExpectedClientHello for the projection step.
|
|
167
|
+
* @since 0.1.0
|
|
117
168
|
*/
|
|
118
169
|
export function validateProfileAgainstCapture(profile, capture) {
|
|
119
170
|
const expected = buildExpectedClientHello(profile, "");
|
|
@@ -123,6 +174,16 @@ export function validateProfileAgainstCapture(profile, capture) {
|
|
|
123
174
|
diffNumberArray("tls.supportedVersions", expected.supportedVersions, capture.supportedVersions, diffs);
|
|
124
175
|
diffNumberArray("tls.keyShareGroups", expected.keyShareGroups, capture.keyShareGroups, diffs);
|
|
125
176
|
diffNumberArray("tls.signatureAlgorithms", expected.signatureAlgorithms, capture.signatureAlgorithms, diffs);
|
|
177
|
+
// Optional impersonation fields: only diff when both the profile and the
|
|
178
|
+
// capture record them. Older captures may not include ecPointFormats or
|
|
179
|
+
// compressCertificateAlgorithms, so absence from the capture is not a mismatch.
|
|
180
|
+
if (expected.ecPointFormats !== undefined && capture.ecPointFormats !== undefined) {
|
|
181
|
+
diffNumberArray("tls.ecPointFormats", expected.ecPointFormats, capture.ecPointFormats, diffs);
|
|
182
|
+
}
|
|
183
|
+
if (expected.compressCertificateAlgorithms !== undefined &&
|
|
184
|
+
capture.compressCertificateAlgorithms !== undefined) {
|
|
185
|
+
diffNumberArray("tls.compressCertificateAlgorithms", expected.compressCertificateAlgorithms, capture.compressCertificateAlgorithms, diffs);
|
|
186
|
+
}
|
|
126
187
|
if (expected.grease !== capture.grease) {
|
|
127
188
|
diffs.push({ path: "tls.grease", a: expected.grease, b: capture.grease });
|
|
128
189
|
}
|
package/dist/validate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACH,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GAChB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browsercore/profiles",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Browser fingerprint definitions (TLS / HTTP/2 / HTTP/1.1). Pure data — no protocol implementation.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
|
+
"bin",
|
|
25
26
|
"LICENSE",
|
|
26
27
|
"README.md"
|
|
27
28
|
],
|
|
@@ -31,14 +32,13 @@
|
|
|
31
32
|
},
|
|
32
33
|
"scripts": {
|
|
33
34
|
"clean": "rm -rf dist",
|
|
34
|
-
"build": "tsc -p tsconfig.
|
|
35
|
+
"build": "tsc -p tsconfig.json",
|
|
35
36
|
"prepublishOnly": "npm run clean && npm run build",
|
|
36
37
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
38
|
"test": "vitest run",
|
|
38
39
|
"lint": "oxlint --type-aware src/"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@browsercore/dev": "latest",
|
|
42
42
|
"@types/node": "^26.1.2",
|
|
43
43
|
"@vitest/coverage-v8": "^4.1.10",
|
|
44
44
|
"typescript": "^7.0.0",
|