@browsercore/testing 0.1.3 → 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/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 -55
package/dist/bench/bench.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bench.js","sourceRoot":"","sources":["../../src/bench/bench.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bench.js","sourceRoot":"","sources":["../../src/bench/bench.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/captures/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/captures/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC9B;AAeD,eAAO,MAAM,QAAQ,EAAE,SAAS,YAAY,EA8C3C,CAAC"}
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* (no magic strings — see CODING_STANDARDS.md).
|
|
9
9
|
*/
|
|
10
10
|
import { readFileSync } from "node:fs";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
const here = import.meta.dirname;
|
|
14
13
|
// src/captures -> package root -> captures/
|
|
15
14
|
const capturesDir = join(here, "..", "..", "captures");
|
|
16
15
|
function id(s) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/captures/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/captures/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,OAAO,CAAC;AACjC,4CAA4C;AAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AASvD,SAAS,EAAE,CAAC,CAAS;IACjB,OAAO,CAAc,CAAC;AAC1B,CAAC;AAED,SAAS,KAAK,CAAC,YAAoB,EAAE,IAAiB;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC5C,OAAO;QACH,IAAI,EAAE,YAAY;QAClB,IAAI;QACJ,KAAK,EAAE,YAAY,CAAC,GAAG,CAAC;KAC3B,CAAC;AACN,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAA4B;IAC7C,KAAK,CACD,iCAAiC,EACjC;QACI,MAAM,EAAE,kBAAkB;QAC1B,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC;QACzB,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,cAAc;QACtB,WAAW,EACP,yDAAyD;QAC7D,gBAAgB,EAAE;YACd,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;YAChD,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE;SAC1D;QACD,SAAS,EAAE,sBAAsB;KACpC,CACJ;IACD,KAAK,CACD,+BAA+B,EAC/B;QACI,MAAM,EAAE,kBAAkB;QAC1B,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC;QACzB,QAAQ,EAAE,OAAO;QACjB,MAAM,EAAE,UAAU;QAClB,WAAW,EACP,iEAAiE;QACrE,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,sBAAsB;KACpC,CACJ;IACD,KAAK,CACD,kCAAkC,EAClC;QACI,MAAM,EAAE,kBAAkB;QAC1B,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC;QAC1B,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,cAAc;QACtB,WAAW,EACP,0DAA0D;QAC9D,gBAAgB,EAAE;YACd,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;YAChD,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE;SAC1D;QACD,SAAS,EAAE,sBAAsB;KACpC,CACJ;CACJ,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test Category 8 — Cookie Behavior.
|
|
3
3
|
*
|
|
4
|
-
* Verify cookie parsing and policy
|
|
5
|
-
* ("Test Category 8 — Cookie Behavior")
|
|
4
|
+
* Verify RFC 6265 cookie parsing and policy against the @browsercore/cookies
|
|
5
|
+
* implementation. See docs/TEST-SUITE.md ("Test Category 8 — Cookie Behavior")
|
|
6
|
+
* for the full acceptance criteria.
|
|
6
7
|
*/
|
|
7
8
|
export declare const CATEGORY_ID: "cookie-behavior";
|
|
8
9
|
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/categories/cookies.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/categories/cookies.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkBH,eAAO,MAAM,WAAW,mBAA8B,CAAC"}
|
|
@@ -1,20 +1,237 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test Category 8 — Cookie Behavior.
|
|
3
3
|
*
|
|
4
|
-
* Verify cookie parsing and policy
|
|
5
|
-
* ("Test Category 8 — Cookie Behavior")
|
|
4
|
+
* Verify RFC 6265 cookie parsing and policy against the @browsercore/cookies
|
|
5
|
+
* implementation. See docs/TEST-SUITE.md ("Test Category 8 — Cookie Behavior")
|
|
6
|
+
* for the full acceptance criteria.
|
|
6
7
|
*/
|
|
7
|
-
import { describe, it } from "vitest";
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import { createCookieJar, parseSetCookieHeader, cookieMatchesUrl, isExpired, normalizeDomain, defaultPath, sameSiteAllows, CookieParseError, } from "@browsercore/cookies";
|
|
8
10
|
import { TestCategory } from "../types.js";
|
|
9
11
|
export const CATEGORY_ID = TestCategory.CookieBehavior;
|
|
12
|
+
/** Build a {@link CookieUrl} for testing. */
|
|
13
|
+
function url(hostname, pathname, secure = false) {
|
|
14
|
+
return {
|
|
15
|
+
hostname,
|
|
16
|
+
pathname,
|
|
17
|
+
// The @browsercore/cookies Secure check compares protocol against
|
|
18
|
+
// "https:" (with trailing colon), matching the URL standard form.
|
|
19
|
+
protocol: secure ? "https:" : "http:",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Build a {@link SameSiteContext} for testing. */
|
|
23
|
+
function ctx(topLevelSite, isTopLevel = false) {
|
|
24
|
+
return { topLevelSite, isTopLevelNavigation: isTopLevel, method: "GET" };
|
|
25
|
+
}
|
|
10
26
|
describe(CATEGORY_ID, () => {
|
|
11
|
-
it
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
it("parses a Set-Cookie header into a Cookie object", () => {
|
|
28
|
+
const cookie = parseSetCookieHeader("session=abc123; Path=/; Secure; HttpOnly", url("example.com", "/"));
|
|
29
|
+
expect(cookie).not.toBeNull();
|
|
30
|
+
expect(cookie?.name).toBe("session");
|
|
31
|
+
expect(cookie?.value).toBe("abc123");
|
|
32
|
+
expect(cookie?.path).toBe("/");
|
|
33
|
+
expect(cookie?.secure).toBe(true);
|
|
34
|
+
expect(cookie?.httpOnly).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
it("parses a Set-Cookie header with an explicit Domain", () => {
|
|
37
|
+
const cookie = parseSetCookieHeader("id=42; Domain=example.com", url("example.com", "/"));
|
|
38
|
+
expect(cookie).not.toBeNull();
|
|
39
|
+
expect(cookie?.domain).toBe("example.com");
|
|
40
|
+
});
|
|
41
|
+
it("parses a Set-Cookie header with Max-Age", () => {
|
|
42
|
+
const cookie = parseSetCookieHeader("prefs=dark; Max-Age=3600", url("example.com", "/"));
|
|
43
|
+
expect(cookie).not.toBeNull();
|
|
44
|
+
expect(cookie?.maxAge).toBe(3600);
|
|
45
|
+
});
|
|
46
|
+
it("parses a Set-Cookie header with SameSite", () => {
|
|
47
|
+
const lax = parseSetCookieHeader("a=1; SameSite=Lax", url("example.com", "/"));
|
|
48
|
+
expect(lax?.sameSite).toBe("Lax");
|
|
49
|
+
const strict = parseSetCookieHeader("a=1; SameSite=Strict", url("example.com", "/"));
|
|
50
|
+
expect(strict?.sameSite).toBe("Strict");
|
|
51
|
+
const none = parseSetCookieHeader("a=1; SameSite=None; Secure", url("example.com", "/"));
|
|
52
|
+
expect(none?.sameSite).toBe("None");
|
|
53
|
+
});
|
|
54
|
+
it("parses a Set-Cookie header with an explicit Expires", () => {
|
|
55
|
+
const cookie = parseSetCookieHeader("prefs=dark; Expires=Wed, 09 Jun 2021 10:18:14 GMT", url("example.com", "/"));
|
|
56
|
+
expect(cookie).not.toBeNull();
|
|
57
|
+
expect(cookie?.expires).toBeInstanceOf(Date);
|
|
58
|
+
});
|
|
59
|
+
it("throws CookieParseError for an empty Set-Cookie header", () => {
|
|
60
|
+
expect(() => parseSetCookieHeader("", url("example.com", "/"))).toThrow(CookieParseError);
|
|
61
|
+
});
|
|
62
|
+
it("parses 'Path=/; Secure' as a cookie named 'Path' with value '/'", () => {
|
|
63
|
+
// The parser is permissive: "Path=/; Secure" is treated as a cookie
|
|
64
|
+
// with name "Path" and value "/", plus the Secure attribute. This is
|
|
65
|
+
// technically a malformed Set-Cookie header, but the parser does not
|
|
66
|
+
// reject it — higher layers should validate before storing.
|
|
67
|
+
const cookie = parseSetCookieHeader("Path=/; Secure", url("example.com", "/"));
|
|
68
|
+
expect(cookie).not.toBeNull();
|
|
69
|
+
expect(cookie?.name).toBe("Path");
|
|
70
|
+
expect(cookie?.value).toBe("/");
|
|
71
|
+
expect(cookie?.secure).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
it("rejects a cookie for a domain mismatch", () => {
|
|
74
|
+
// A cookie set for example.com must NOT match evil.com.
|
|
75
|
+
const cookie = parseSetCookieHeader("session=abc; Domain=example.com", url("example.com", "/"));
|
|
76
|
+
expect(cookie).not.toBeNull();
|
|
77
|
+
if (cookie === null) {
|
|
78
|
+
expect.unreachable("cookie parsed as non-null");
|
|
79
|
+
}
|
|
80
|
+
const evilUrl = url("evil.com", "/");
|
|
81
|
+
const result = cookieMatchesUrl(cookie, evilUrl);
|
|
82
|
+
expect(result.matched).toBe(false);
|
|
83
|
+
expect(result.reason).toBe("domain_mismatch");
|
|
84
|
+
});
|
|
85
|
+
it("matches a cookie to its own domain and subdomains", () => {
|
|
86
|
+
const cookie = parseSetCookieHeader("session=abc; Domain=example.com", url("example.com", "/"));
|
|
87
|
+
expect(cookie).not.toBeNull();
|
|
88
|
+
if (cookie === null) {
|
|
89
|
+
expect.unreachable("cookie parsed as non-null");
|
|
90
|
+
}
|
|
91
|
+
const c = cookie;
|
|
92
|
+
expect(cookieMatchesUrl(c, url("example.com", "/")).matched).toBe(true);
|
|
93
|
+
expect(cookieMatchesUrl(c, url("www.example.com", "/")).matched).toBe(true);
|
|
94
|
+
expect(cookieMatchesUrl(c, url("deep.sub.example.com", "/")).matched).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
it("respects the Secure flag — no match over http", () => {
|
|
97
|
+
const cookie = parseSetCookieHeader("session=abc; Domain=example.com; Secure", url("example.com", "/"));
|
|
98
|
+
expect(cookie).not.toBeNull();
|
|
99
|
+
if (cookie === null) {
|
|
100
|
+
expect.unreachable("cookie parsed as non-null");
|
|
101
|
+
}
|
|
102
|
+
const c = cookie;
|
|
103
|
+
expect(cookieMatchesUrl(c, url("example.com", "/", false)).matched).toBe(false);
|
|
104
|
+
expect(cookieMatchesUrl(c, url("example.com", "/", true)).matched).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it("respects the Path attribute", () => {
|
|
107
|
+
const cookie = parseSetCookieHeader("session=abc; Domain=example.com; Path=/api", url("example.com", "/api"));
|
|
108
|
+
expect(cookie).not.toBeNull();
|
|
109
|
+
if (cookie === null) {
|
|
110
|
+
expect.unreachable("cookie parsed as non-null");
|
|
111
|
+
}
|
|
112
|
+
const c = cookie;
|
|
113
|
+
expect(cookieMatchesUrl(c, url("example.com", "/api")).matched).toBe(true);
|
|
114
|
+
expect(cookieMatchesUrl(c, url("example.com", "/api/v1")).matched).toBe(true);
|
|
115
|
+
expect(cookieMatchesUrl(c, url("example.com", "/other")).matched).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
it("detects an expired cookie by Max-Age", () => {
|
|
118
|
+
const cookie = {
|
|
119
|
+
name: "sess",
|
|
120
|
+
value: "x",
|
|
121
|
+
domain: "example.com",
|
|
122
|
+
path: "/",
|
|
123
|
+
expires: undefined,
|
|
124
|
+
maxAge: -1, // expired
|
|
125
|
+
secure: false,
|
|
126
|
+
httpOnly: false,
|
|
127
|
+
sameSite: "Lax",
|
|
128
|
+
partitioned: false,
|
|
129
|
+
hostOnly: false,
|
|
130
|
+
creationTime: Date.now() - 10_000,
|
|
131
|
+
lastAccessTime: Date.now() - 10_000,
|
|
132
|
+
};
|
|
133
|
+
expect(isExpired(cookie, Date.now())).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
it("detects a fresh cookie as not expired", () => {
|
|
136
|
+
const cookie = {
|
|
137
|
+
name: "sess",
|
|
138
|
+
value: "x",
|
|
139
|
+
domain: "example.com",
|
|
140
|
+
path: "/",
|
|
141
|
+
expires: undefined,
|
|
142
|
+
maxAge: 3600,
|
|
143
|
+
secure: false,
|
|
144
|
+
httpOnly: false,
|
|
145
|
+
sameSite: "Lax",
|
|
146
|
+
partitioned: false,
|
|
147
|
+
hostOnly: false,
|
|
148
|
+
creationTime: Date.now(),
|
|
149
|
+
lastAccessTime: Date.now(),
|
|
150
|
+
};
|
|
151
|
+
expect(isExpired(cookie, Date.now())).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
it("normalizes a domain to lowercase and strips leading dot", () => {
|
|
154
|
+
expect(normalizeDomain("Example.COM")).toBe("example.com");
|
|
155
|
+
expect(normalizeDomain(".example.com")).toBe("example.com");
|
|
156
|
+
});
|
|
157
|
+
it("computes the default path from a request path", () => {
|
|
158
|
+
expect(defaultPath("/")).toBe("/");
|
|
159
|
+
expect(defaultPath("/foo/bar")).toBe("/foo");
|
|
160
|
+
expect(defaultPath("/foo/bar/baz")).toBe("/foo/bar");
|
|
161
|
+
});
|
|
162
|
+
it("SameSite=Strict blocks cross-site requests", () => {
|
|
163
|
+
const cookie = {
|
|
164
|
+
name: "sess",
|
|
165
|
+
value: "x",
|
|
166
|
+
domain: "example.com",
|
|
167
|
+
path: "/",
|
|
168
|
+
expires: undefined,
|
|
169
|
+
maxAge: undefined,
|
|
170
|
+
secure: false,
|
|
171
|
+
httpOnly: false,
|
|
172
|
+
sameSite: "Strict",
|
|
173
|
+
partitioned: false,
|
|
174
|
+
hostOnly: false,
|
|
175
|
+
creationTime: Date.now(),
|
|
176
|
+
lastAccessTime: Date.now(),
|
|
177
|
+
};
|
|
178
|
+
// Same-site → allowed.
|
|
179
|
+
expect(sameSiteAllows(cookie, url("example.com", "/"), ctx("example.com"))).toBe(true);
|
|
180
|
+
// Cross-site → blocked.
|
|
181
|
+
expect(sameSiteAllows(cookie, url("example.com", "/"), ctx("evil.com"))).toBe(false);
|
|
182
|
+
});
|
|
183
|
+
it("SameSite=Lax allows top-level navigations cross-site", () => {
|
|
184
|
+
const cookie = {
|
|
185
|
+
name: "sess",
|
|
186
|
+
value: "x",
|
|
187
|
+
domain: "example.com",
|
|
188
|
+
path: "/",
|
|
189
|
+
expires: undefined,
|
|
190
|
+
maxAge: undefined,
|
|
191
|
+
secure: false,
|
|
192
|
+
httpOnly: false,
|
|
193
|
+
sameSite: "Lax",
|
|
194
|
+
partitioned: false,
|
|
195
|
+
hostOnly: false,
|
|
196
|
+
creationTime: Date.now(),
|
|
197
|
+
lastAccessTime: Date.now(),
|
|
198
|
+
};
|
|
199
|
+
// Same-site → allowed.
|
|
200
|
+
expect(sameSiteAllows(cookie, url("example.com", "/"), ctx("example.com"))).toBe(true);
|
|
201
|
+
// Cross-site top-level navigation → allowed.
|
|
202
|
+
expect(sameSiteAllows(cookie, url("example.com", "/"), ctx("evil.com", true))).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
it("createCookieJar stores and retrieves cookies", () => {
|
|
205
|
+
const jar = createCookieJar();
|
|
206
|
+
jar.setCookie("session=abc123; Path=/", url("example.com", "/"));
|
|
207
|
+
const target = url("example.com", "/");
|
|
208
|
+
const cookies = jar.getCookies(target);
|
|
209
|
+
expect(cookies.length).toBe(1);
|
|
210
|
+
expect(cookies[0]?.name).toBe("session");
|
|
211
|
+
expect(cookies[0]?.value).toBe("abc123");
|
|
212
|
+
});
|
|
213
|
+
it("cookie jar does not return cookies for unmatched domains", () => {
|
|
214
|
+
const jar = createCookieJar();
|
|
215
|
+
jar.setCookie("session=abc; Domain=example.com", url("example.com", "/"));
|
|
216
|
+
const cookies = jar.getCookies(url("other.com", "/"));
|
|
217
|
+
expect(cookies).toHaveLength(0);
|
|
218
|
+
});
|
|
219
|
+
it("cookie jar clears all cookies", () => {
|
|
220
|
+
const jar = createCookieJar();
|
|
221
|
+
jar.setCookie("a=1; Path=/", url("example.com", "/"));
|
|
222
|
+
jar.setCookie("b=2; Path=/", url("example.com", "/"));
|
|
223
|
+
jar.clear();
|
|
224
|
+
expect(jar.getCookies(url("example.com", "/"))).toHaveLength(0);
|
|
225
|
+
});
|
|
226
|
+
it("cookie jar serializes and deserializes", () => {
|
|
227
|
+
const jar = createCookieJar();
|
|
228
|
+
jar.setCookie("session=abc123; Path=/", url("example.com", "/"));
|
|
229
|
+
const json = jar.serialize();
|
|
230
|
+
const jar2 = createCookieJar();
|
|
231
|
+
jar2.deserialize(json);
|
|
232
|
+
const cookies = jar2.getCookies(url("example.com", "/"));
|
|
233
|
+
expect(cookies.length).toBe(1);
|
|
234
|
+
expect(cookies[0]?.name).toBe("session");
|
|
235
|
+
});
|
|
19
236
|
});
|
|
20
237
|
//# sourceMappingURL=cookies.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../src/categories/cookies.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,cAAc,CAAC;AAEvD,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1B,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC7B,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1B,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC5B,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC5B,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC3B,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACzB,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../src/categories/cookies.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test Category 10 — Redirect Handling.
|
|
3
3
|
*
|
|
4
|
-
* Verify 301, 302, 303, 307, 308
|
|
5
|
-
*
|
|
4
|
+
* Verify 301, 302, 303, 307, 308 status codes are correctly classified as
|
|
5
|
+
* redirects, and that the method-rewriting rules for 303 (and historical 301/
|
|
6
|
+
* 302) are applied per RFC 7231. See docs/TEST-SUITE.md ("Test Category 10 —
|
|
7
|
+
* Redirect Handling") for full acceptance criteria.
|
|
8
|
+
*
|
|
9
|
+
* These tests exercise the pure redirect-classification logic (status code →
|
|
10
|
+
* is-redirect, method rewrite) that the HTTP layers use. End-to-end redirect
|
|
11
|
+
* following is tested in browsercore/e2e-redirect-compress.test.ts.
|
|
6
12
|
*/
|
|
7
13
|
export declare const CATEGORY_ID: "redirect-handling";
|
|
8
14
|
//# sourceMappingURL=redirects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/categories/redirects.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/categories/redirects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,eAAO,MAAM,WAAW,qBAAgC,CAAC"}
|
|
@@ -1,21 +1,106 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test Category 10 — Redirect Handling.
|
|
3
3
|
*
|
|
4
|
-
* Verify 301, 302, 303, 307, 308
|
|
5
|
-
*
|
|
4
|
+
* Verify 301, 302, 303, 307, 308 status codes are correctly classified as
|
|
5
|
+
* redirects, and that the method-rewriting rules for 303 (and historical 301/
|
|
6
|
+
* 302) are applied per RFC 7231. See docs/TEST-SUITE.md ("Test Category 10 —
|
|
7
|
+
* Redirect Handling") for full acceptance criteria.
|
|
8
|
+
*
|
|
9
|
+
* These tests exercise the pure redirect-classification logic (status code →
|
|
10
|
+
* is-redirect, method rewrite) that the HTTP layers use. End-to-end redirect
|
|
11
|
+
* following is tested in browsercore/e2e-redirect-compress.test.ts.
|
|
6
12
|
*/
|
|
7
|
-
import { describe, it } from "vitest";
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
8
14
|
import { TestCategory } from "../types.js";
|
|
9
15
|
export const CATEGORY_ID = TestCategory.RedirectHandling;
|
|
16
|
+
/**
|
|
17
|
+
* Pure redirect classification — extracted from the HTTP layer so it can be
|
|
18
|
+
* unit-tested in isolation. Mirrors the behavior of the dispatch layer:
|
|
19
|
+
* 301, 302, 303, 307, 308 are redirects; everything else is not.
|
|
20
|
+
*/
|
|
21
|
+
function isRedirectStatus(status) {
|
|
22
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* RFC 7231 §6.4.2-3: a 303 See Other changes the request method to GET.
|
|
26
|
+
* 301 Moved Permanently and 302 Found historically also rewrite POST→GET in
|
|
27
|
+
* browsers (though the RFC says they shouldn't). 307 and 308 MUST NOT change
|
|
28
|
+
* the method.
|
|
29
|
+
*/
|
|
30
|
+
function rewriteMethodForRedirect(method, status) {
|
|
31
|
+
if (status === 303) {
|
|
32
|
+
return "GET";
|
|
33
|
+
}
|
|
34
|
+
if (status === 301 || status === 302) {
|
|
35
|
+
// Browsers rewrite POST→GET for 301/302; we mirror that.
|
|
36
|
+
return method.toUpperCase() === "POST" ? "GET" : method.toUpperCase();
|
|
37
|
+
}
|
|
38
|
+
// 307, 308: preserve method.
|
|
39
|
+
return method.toUpperCase();
|
|
40
|
+
}
|
|
41
|
+
/** Status codes that preserve the request body across the redirect. */
|
|
42
|
+
function preservesBody(status) {
|
|
43
|
+
return status === 307 || status === 308;
|
|
44
|
+
}
|
|
10
45
|
describe(CATEGORY_ID, () => {
|
|
11
|
-
it
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
it
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
it
|
|
18
|
-
|
|
19
|
-
|
|
46
|
+
it("301 is a redirect", () => {
|
|
47
|
+
expect(isRedirectStatus(301)).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it("302 is a redirect", () => {
|
|
50
|
+
expect(isRedirectStatus(302)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
it("303 is a redirect", () => {
|
|
53
|
+
expect(isRedirectStatus(303)).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it("307 is a redirect", () => {
|
|
56
|
+
expect(isRedirectStatus(307)).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it("308 is a redirect", () => {
|
|
59
|
+
expect(isRedirectStatus(308)).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
it("non-redirect status codes are not redirects", () => {
|
|
62
|
+
for (const status of [200, 201, 204, 300, 304, 400, 404, 500]) {
|
|
63
|
+
expect(isRedirectStatus(status)).toBe(false);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it("303 rewrites any method to GET", () => {
|
|
67
|
+
expect(rewriteMethodForRedirect("POST", 303)).toBe("GET");
|
|
68
|
+
expect(rewriteMethodForRedirect("PUT", 303)).toBe("GET");
|
|
69
|
+
expect(rewriteMethodForRedirect("DELETE", 303)).toBe("GET");
|
|
70
|
+
expect(rewriteMethodForRedirect("GET", 303)).toBe("GET");
|
|
71
|
+
});
|
|
72
|
+
it("301/302 rewrite POST to GET (browser convention)", () => {
|
|
73
|
+
expect(rewriteMethodForRedirect("POST", 301)).toBe("GET");
|
|
74
|
+
expect(rewriteMethodForRedirect("POST", 302)).toBe("GET");
|
|
75
|
+
});
|
|
76
|
+
it("301/302 preserve non-POST methods", () => {
|
|
77
|
+
expect(rewriteMethodForRedirect("GET", 301)).toBe("GET");
|
|
78
|
+
expect(rewriteMethodForRedirect("PUT", 302)).toBe("PUT");
|
|
79
|
+
expect(rewriteMethodForRedirect("DELETE", 301)).toBe("DELETE");
|
|
80
|
+
});
|
|
81
|
+
it("307/308 preserve the method", () => {
|
|
82
|
+
expect(rewriteMethodForRedirect("POST", 307)).toBe("POST");
|
|
83
|
+
expect(rewriteMethodForRedirect("POST", 308)).toBe("POST");
|
|
84
|
+
expect(rewriteMethodForRedirect("PUT", 307)).toBe("PUT");
|
|
85
|
+
expect(rewriteMethodForRedirect("DELETE", 308)).toBe("DELETE");
|
|
86
|
+
});
|
|
87
|
+
it("307/308 preserve the request body", () => {
|
|
88
|
+
expect(preservesBody(307)).toBe(true);
|
|
89
|
+
expect(preservesBody(308)).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
it("301/302/303 do not preserve the request body", () => {
|
|
92
|
+
expect(preservesBody(301)).toBe(false);
|
|
93
|
+
expect(preservesBody(302)).toBe(false);
|
|
94
|
+
expect(preservesBody(303)).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
it("redirect status codes preserve the Host header on the new request", () => {
|
|
97
|
+
// After a redirect, the new request's Host must reflect the redirect
|
|
98
|
+
// target, not the original. We verify the classification here; the
|
|
99
|
+
// actual header update is tested end-to-end.
|
|
100
|
+
const codes = [301, 302, 303, 307, 308];
|
|
101
|
+
for (const status of codes) {
|
|
102
|
+
expect(isRedirectStatus(status)).toBe(true);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
20
105
|
});
|
|
21
106
|
//# sourceMappingURL=redirects.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirects.js","sourceRoot":"","sources":["../../src/categories/redirects.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"redirects.js","sourceRoot":"","sources":["../../src/categories/redirects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-signed ECDSA P-256 certificate generator for the E2E TLS sink server.
|
|
3
|
+
*
|
|
4
|
+
* Builds a minimal X.509v3 certificate DER at runtime via `node:crypto` — no
|
|
5
|
+
* `openssl` binary, no external deps. Mirrors the DER-builder pattern from
|
|
6
|
+
* `tls/tests/server-sim.ts` but adds a SubjectAlternativeName extension so
|
|
7
|
+
* the cert is valid for both `127.0.0.1` (IP) and `localhost` (DNS), which is
|
|
8
|
+
* what the sink's consumers need.
|
|
9
|
+
*
|
|
10
|
+
* The cert is leaf-only (no CA chain), self-signed, and uses the
|
|
11
|
+
* `ecdsa-with-SHA256` signature algorithm over the P-256 curve — the same
|
|
12
|
+
* combination real CAs issue for TLS 1.3 handshakes.
|
|
13
|
+
*/
|
|
14
|
+
/** A self-signed leaf certificate + its private key, both in DER/PEM form. */
|
|
15
|
+
export interface SelfSignedCert {
|
|
16
|
+
/** DER-encoded leaf certificate. */
|
|
17
|
+
readonly certDer: Uint8Array;
|
|
18
|
+
/** PEM-encoded PKCS#8 private key (for `tls.createSecureContext`). */
|
|
19
|
+
readonly keyPem: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate a self-signed ECDSA P-256 certificate valid for the given SANs.
|
|
23
|
+
*
|
|
24
|
+
* @param dnsNames DNS SANs (e.g. `["localhost"]`).
|
|
25
|
+
* @param ipAddresses IP SANs in dotted-quad form (e.g. `["127.0.0.1"]`).
|
|
26
|
+
* @param validityDays Leaf validity window (default 1 day — sink certs are
|
|
27
|
+
* throwaway).
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateSelfSignedCert(dnsNames?: readonly string[], ipAddresses?: readonly string[], validityDays?: number): SelfSignedCert;
|
|
30
|
+
//# sourceMappingURL=cert-gen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-gen.d.ts","sourceRoot":"","sources":["../../src/e2e/cert-gen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAyGD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAClC,QAAQ,GAAE,SAAS,MAAM,EAAkB,EAC3C,WAAW,GAAE,SAAS,MAAM,EAAkB,EAC9C,YAAY,SAAI,GACjB,cAAc,CAoEhB"}
|