@ai-ecoverse/slicc-browsers 1.18.17 → 1.18.19
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/guard-vectors.json +15 -15
- package/package.json +4 -4
- package/protected-error-page.mjs +80 -52
package/guard-vectors.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"setVersion": "1.18.
|
|
3
|
+
"setVersion": "1.18.19",
|
|
4
4
|
"sources": [
|
|
5
5
|
{
|
|
6
6
|
"repo": "ai-ecoverse/slicc-cli",
|
|
@@ -1200,7 +1200,7 @@
|
|
|
1200
1200
|
}
|
|
1201
1201
|
},
|
|
1202
1202
|
"eventsRedacted": {
|
|
1203
|
-
"means": "protected error-page recover: every discovery event for the tab shows the failed URL's origin only
|
|
1203
|
+
"means": "protected error-page recover: every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
1204
1204
|
"requires": ["discovery"],
|
|
1205
1205
|
"check": {
|
|
1206
1206
|
"result": "errorPage",
|
|
@@ -1210,7 +1210,7 @@
|
|
|
1210
1210
|
}
|
|
1211
1211
|
},
|
|
1212
1212
|
"reload": {
|
|
1213
|
-
"means": "protected error-page recover: reload",
|
|
1213
|
+
"means": "protected error-page recover: Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
1214
1214
|
"check": {
|
|
1215
1215
|
"result": "errorPage",
|
|
1216
1216
|
"path": "result.reload",
|
|
@@ -1349,7 +1349,7 @@
|
|
|
1349
1349
|
}
|
|
1350
1350
|
},
|
|
1351
1351
|
"eventsRedacted": {
|
|
1352
|
-
"means": "protected error-page recover (query): every discovery event for the tab shows the failed URL's origin only
|
|
1352
|
+
"means": "protected error-page recover (query): every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
1353
1353
|
"requires": ["discovery"],
|
|
1354
1354
|
"check": {
|
|
1355
1355
|
"result": "errorPage",
|
|
@@ -1359,7 +1359,7 @@
|
|
|
1359
1359
|
}
|
|
1360
1360
|
},
|
|
1361
1361
|
"reload": {
|
|
1362
|
-
"means": "protected error-page recover (query): reload",
|
|
1362
|
+
"means": "protected error-page recover (query): Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
1363
1363
|
"check": {
|
|
1364
1364
|
"result": "errorPage",
|
|
1365
1365
|
"path": "result.reload",
|
|
@@ -1498,7 +1498,7 @@
|
|
|
1498
1498
|
}
|
|
1499
1499
|
},
|
|
1500
1500
|
"eventsRedacted": {
|
|
1501
|
-
"means": "protected error-page recover (fragment): every discovery event for the tab shows the failed URL's origin only
|
|
1501
|
+
"means": "protected error-page recover (fragment): every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
1502
1502
|
"requires": ["discovery"],
|
|
1503
1503
|
"check": {
|
|
1504
1504
|
"result": "errorPage",
|
|
@@ -1508,7 +1508,7 @@
|
|
|
1508
1508
|
}
|
|
1509
1509
|
},
|
|
1510
1510
|
"reload": {
|
|
1511
|
-
"means": "protected error-page recover (fragment): reload",
|
|
1511
|
+
"means": "protected error-page recover (fragment): Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
1512
1512
|
"check": {
|
|
1513
1513
|
"result": "errorPage",
|
|
1514
1514
|
"path": "result.reload",
|
|
@@ -1646,7 +1646,7 @@
|
|
|
1646
1646
|
}
|
|
1647
1647
|
},
|
|
1648
1648
|
"eventsRedacted": {
|
|
1649
|
-
"means": "protected error-page restore: every discovery event for the tab shows the failed URL's origin only
|
|
1649
|
+
"means": "protected error-page restore: every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
1650
1650
|
"requires": ["discovery"],
|
|
1651
1651
|
"check": {
|
|
1652
1652
|
"result": "errorPage",
|
|
@@ -1656,7 +1656,7 @@
|
|
|
1656
1656
|
}
|
|
1657
1657
|
},
|
|
1658
1658
|
"reload": {
|
|
1659
|
-
"means": "protected error-page restore: reload",
|
|
1659
|
+
"means": "protected error-page restore: Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
1660
1660
|
"check": {
|
|
1661
1661
|
"result": "errorPage",
|
|
1662
1662
|
"path": "result.reload",
|
|
@@ -1827,7 +1827,7 @@
|
|
|
1827
1827
|
}
|
|
1828
1828
|
},
|
|
1829
1829
|
"eventsRedacted": {
|
|
1830
|
-
"means": "protected error-page sticky: every discovery event for the tab shows the failed URL's origin only
|
|
1830
|
+
"means": "protected error-page sticky: every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
1831
1831
|
"requires": ["discovery"],
|
|
1832
1832
|
"check": {
|
|
1833
1833
|
"result": "errorPage",
|
|
@@ -1837,7 +1837,7 @@
|
|
|
1837
1837
|
}
|
|
1838
1838
|
},
|
|
1839
1839
|
"reload": {
|
|
1840
|
-
"means": "protected error-page sticky: reload",
|
|
1840
|
+
"means": "protected error-page sticky: Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
1841
1841
|
"check": {
|
|
1842
1842
|
"result": "errorPage",
|
|
1843
1843
|
"path": "result.reload",
|
|
@@ -2020,7 +2020,7 @@
|
|
|
2020
2020
|
}
|
|
2021
2021
|
},
|
|
2022
2022
|
"eventsRedacted": {
|
|
2023
|
-
"means": "protected error-page sticky (query): every discovery event for the tab shows the failed URL's origin only
|
|
2023
|
+
"means": "protected error-page sticky (query): every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
2024
2024
|
"requires": ["discovery"],
|
|
2025
2025
|
"check": {
|
|
2026
2026
|
"result": "errorPage",
|
|
@@ -2030,7 +2030,7 @@
|
|
|
2030
2030
|
}
|
|
2031
2031
|
},
|
|
2032
2032
|
"reload": {
|
|
2033
|
-
"means": "protected error-page sticky (query): reload",
|
|
2033
|
+
"means": "protected error-page sticky (query): Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
2034
2034
|
"check": {
|
|
2035
2035
|
"result": "errorPage",
|
|
2036
2036
|
"path": "result.reload",
|
|
@@ -2213,7 +2213,7 @@
|
|
|
2213
2213
|
}
|
|
2214
2214
|
},
|
|
2215
2215
|
"eventsRedacted": {
|
|
2216
|
-
"means": "protected error-page sticky (fragment): every discovery event for the tab shows the failed URL's origin only
|
|
2216
|
+
"means": "protected error-page sticky (fragment): every discovery event for the tab shows, decoded as often as it takes, the failed URL's origin only, a masked or absent url, or a url off the protected host, wrappers such as blob: unwrapped, that names no other origin on that host, and no url or title carries the failed URL, its path, query or fragment; no discovery event for another or no target carries the row's tag; reporting no event for the tab also passes",
|
|
2217
2217
|
"requires": ["discovery"],
|
|
2218
2218
|
"check": {
|
|
2219
2219
|
"result": "errorPage",
|
|
@@ -2223,7 +2223,7 @@
|
|
|
2223
2223
|
}
|
|
2224
2224
|
},
|
|
2225
2225
|
"reload": {
|
|
2226
|
-
"means": "protected error-page sticky (fragment): reload",
|
|
2226
|
+
"means": "protected error-page sticky (fragment): Page.reload is answered, then the observer sees the protected error page again, or on the guarded leg exactly data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E with no unreachableUrl and no protected URL in its target url, title or location; a title or location the observer can't read is incomplete",
|
|
2227
2227
|
"check": {
|
|
2228
2228
|
"result": "errorPage",
|
|
2229
2229
|
"path": "result.reload",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-browsers",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.19",
|
|
4
4
|
"description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"validate": "node scripts/validate.mjs",
|
|
69
69
|
"lint": "slicc-lint && test -z \"$(gofmt -l .)\" && go mod tidy -diff && go vet ./... && GOOS=darwin go vet ./... && GOOS=windows go vet ./... && golangci-lint run && cargo fmt --check && cargo clippy --all-features --all-targets -- -D warnings && cargo check --target wasm32-wasip1 --no-default-features && cargo check --target wasm32-wasip1 --features serde && cargo check --target wasm32-wasip1 --all-features",
|
|
70
70
|
"format": "biome check --write . && gofmt -w . && cargo fmt",
|
|
71
|
-
"test": "export PATH=\"$HOME/.cargo/bin:$PATH\" && node --test --test-concurrency=1 test/integration/self-contained.test.mjs test/integration/browser-runner.test.mjs test/integration/fixture-client.test.mjs test/integration/guard-redirect-carrier.test.mjs test/integration/guard-redirect-session-end.test.mjs test/integration/guard-redirect-history.test.mjs test/integration/guard-redirect-iframe.test.mjs test/integration/guard-incomplete.test.mjs test/integration/guard-unparseable-wipe.test.mjs test/integration/guard-browser-ui.test.mjs test/integration/guard-snapshot-settle.test.mjs test/integration/guard-stall.test.mjs test/integration/guard-forged.test.mjs test/integration/guard-exit-steps.test.mjs test/integration/guard-exit-refusal.test.mjs test/integration/guard-frame-read.test.mjs test/integration/guard-bfcache.test.mjs test/integration/guard-bfcache-marker.test.mjs test/integration/guard-bfcache-history.test.mjs test/integration/guard-bfcache-review.test.mjs test/integration/guard-bfcache-quarantine.test.mjs test/integration/guard-error-page-navigation.test.mjs test/integration/guard-error-page-events.test.mjs test/integration/guard-world-paint.test.mjs test/integration/gates.test.mjs test/integration/validate.test.mjs test/integration/go.test.mjs test/integration/cargo.test.mjs test/integration/workflows.test.mjs test/integration/guard-sweep-union.test.mjs && node --test --test-concurrency=2 test/integration/guard-lifecycle.test.mjs test/integration/chromium-launch.test.mjs test/integration/guard-fit.test.mjs test/integration/guard-chain.test.mjs test/integration/guard-validation.test.mjs test/integration/guard-liveness.test.mjs test/integration/guard-observations.test.mjs test/integration/guard-child-latency.test.mjs test/integration/guard-adoption.test.mjs test/integration/guard-scoping.test.mjs test/integration/guard-late-pause.test.mjs test/integration/guard-legs.test.mjs test/integration/guard-fetch-enable.test.mjs test/integration/guard-diagnostics.test.mjs test/integration/guard-chrome.test.mjs test/integration/guard-worlds.test.mjs test/integration/guard-world-discovery.test.mjs test/integration/guard-world-guesses.test.mjs test/integration/guard-unparseable.test.mjs test/integration/guard-redirect-secret.test.mjs test/integration/guard-error-page.test.mjs test/integration/guard-discovery.test.mjs test/integration/guard-bfcache-chrome.test.mjs test/integration/guard-browser-page.test.mjs test/integration/guard-scales.test.mjs test/integration/guard-shared-log.test.mjs test/integration/guard-pre-beacon.test.mjs test/integration/guard-world-pause.test.mjs test/integration/guard-parallel.test.mjs test/integration/guard-client-exit.test.mjs test/integration/guard-runner.test.mjs test/integration/guard-sweep-ordinary.test.mjs test/integration/guard-sweep-seven.test.mjs test/integration/guard-sweep-vault.test.mjs test/integration/guard-sweep-vault-x.test.mjs test/integration/guard-sweep-apex.test.mjs test/integration/guard-sweep-others.test.mjs",
|
|
71
|
+
"test": "export PATH=\"$HOME/.cargo/bin:$PATH\" && node --test --test-concurrency=1 test/integration/self-contained.test.mjs test/integration/browser-runner.test.mjs test/integration/fixture-client.test.mjs test/integration/guard-redirect-carrier.test.mjs test/integration/guard-redirect-session-end.test.mjs test/integration/guard-redirect-history.test.mjs test/integration/guard-redirect-iframe.test.mjs test/integration/guard-incomplete.test.mjs test/integration/guard-unparseable-wipe.test.mjs test/integration/guard-browser-ui.test.mjs test/integration/guard-snapshot-settle.test.mjs test/integration/guard-stall.test.mjs test/integration/guard-forged.test.mjs test/integration/guard-exit-steps.test.mjs test/integration/guard-exit-refusal.test.mjs test/integration/guard-frame-read.test.mjs test/integration/guard-bfcache.test.mjs test/integration/guard-bfcache-marker.test.mjs test/integration/guard-bfcache-history.test.mjs test/integration/guard-bfcache-review.test.mjs test/integration/guard-bfcache-quarantine.test.mjs test/integration/guard-error-page-navigation.test.mjs test/integration/guard-error-page-events.test.mjs test/integration/guard-error-page-reload.test.mjs test/integration/guard-world-paint.test.mjs test/integration/gates.test.mjs test/integration/validate.test.mjs test/integration/go.test.mjs test/integration/cargo.test.mjs test/integration/workflows.test.mjs test/integration/guard-sweep-union.test.mjs && node --test --test-concurrency=2 test/integration/guard-lifecycle.test.mjs test/integration/chromium-launch.test.mjs test/integration/guard-fit.test.mjs test/integration/guard-chain.test.mjs test/integration/guard-validation.test.mjs test/integration/guard-liveness.test.mjs test/integration/guard-observations.test.mjs test/integration/guard-child-latency.test.mjs test/integration/guard-adoption.test.mjs test/integration/guard-scoping.test.mjs test/integration/guard-late-pause.test.mjs test/integration/guard-legs.test.mjs test/integration/guard-fetch-enable.test.mjs test/integration/guard-diagnostics.test.mjs test/integration/guard-chrome.test.mjs test/integration/guard-worlds.test.mjs test/integration/guard-world-discovery.test.mjs test/integration/guard-world-guesses.test.mjs test/integration/guard-unparseable.test.mjs test/integration/guard-redirect-secret.test.mjs test/integration/guard-error-page.test.mjs test/integration/guard-discovery.test.mjs test/integration/guard-bfcache-chrome.test.mjs test/integration/guard-browser-page.test.mjs test/integration/guard-scales.test.mjs test/integration/guard-shared-log.test.mjs test/integration/guard-pre-beacon.test.mjs test/integration/guard-world-pause.test.mjs test/integration/guard-parallel.test.mjs test/integration/guard-client-exit.test.mjs test/integration/guard-runner.test.mjs test/integration/guard-sweep-ordinary.test.mjs test/integration/guard-sweep-seven.test.mjs test/integration/guard-sweep-vault.test.mjs test/integration/guard-sweep-vault-x.test.mjs test/integration/guard-sweep-apex.test.mjs test/integration/guard-sweep-others.test.mjs",
|
|
72
72
|
"test:unit": "mkdir -p coverage/unit && node --experimental-test-coverage --test --test-concurrency=1 --test-reporter=lcov --test-reporter-destination=coverage/unit/lcov.info test/unit/*.test.mjs && go test -race -cover ./...",
|
|
73
73
|
"build": "go build ./... && cargo build --all-features && cargo build --target wasm32-wasip1 --all-features && npm pack --dry-run",
|
|
74
74
|
"prepublishOnly": "node scripts/set-crate-version.mjs \"$npm_package_version\"",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@ai-ecoverse/slicc-cdp": "1.42.3",
|
|
83
|
-
"@ai-ecoverse/slicc-shared-web": "2.13.
|
|
84
|
-
"@biomejs/biome": "2.
|
|
83
|
+
"@ai-ecoverse/slicc-shared-web": "2.13.6",
|
|
84
|
+
"@biomejs/biome": "2.6.2",
|
|
85
85
|
"ajv": "8.20.0",
|
|
86
86
|
"ajv-formats": "3.0.1",
|
|
87
87
|
"lefthook": "2.2.2",
|
package/protected-error-page.mjs
CHANGED
|
@@ -52,7 +52,6 @@ async function lockChecks({ client, session, targetId, result }) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const discoveryMethods = ['Target.targetCreated', 'Target.targetInfoChanged'];
|
|
55
|
-
const errorPageURL = 'chrome-error://chromewebdata/';
|
|
56
55
|
const lower = (value) => String(value ?? '').toLowerCase();
|
|
57
56
|
const plain = (value) =>
|
|
58
57
|
lower(
|
|
@@ -60,6 +59,11 @@ const plain = (value) =>
|
|
|
60
59
|
String.fromCharCode(Number.parseInt(hex, 16))
|
|
61
60
|
)
|
|
62
61
|
);
|
|
62
|
+
const layers = (value) => {
|
|
63
|
+
const out = [lower(value)];
|
|
64
|
+
for (let next = plain(out[0]); next !== out.at(-1); next = plain(next)) out.push(next);
|
|
65
|
+
return out;
|
|
66
|
+
};
|
|
63
67
|
const unschemed = (value) => value.replace(/^[a-z][a-z\d+.-]*:\/\//, '');
|
|
64
68
|
|
|
65
69
|
const encoded = (url) =>
|
|
@@ -70,10 +74,12 @@ const encoded = (url) =>
|
|
|
70
74
|
|
|
71
75
|
const triggerURL = (ordinary, url) => `${ordinary}/page?k=deferred&defer=0&to=${encoded(url)}`;
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
const errorPageURL = 'chrome-error://chromewebdata/';
|
|
78
|
+
const privateBlankURL = 'data:text/html,%3Ctitle%3Eblocked%3C%2Ftitle%3E';
|
|
79
|
+
|
|
80
|
+
function failureRules({ failedURL, tag }) {
|
|
74
81
|
const failed = new URL(failedURL);
|
|
75
|
-
const { origin,
|
|
76
|
-
const named = [hostname, host, origin];
|
|
82
|
+
const { origin, hostname } = failed;
|
|
77
83
|
const parts = [
|
|
78
84
|
failedURL,
|
|
79
85
|
`${failed.pathname}${failed.search}${failed.hash}`,
|
|
@@ -84,49 +90,74 @@ function discoveryRules({ failedURL, tag, trigger }) {
|
|
|
84
90
|
]
|
|
85
91
|
.filter((part) => part && part !== '/')
|
|
86
92
|
.map(plain);
|
|
87
|
-
const
|
|
88
|
-
const leaks = (value) => forms(value).some((form) => parts.some((part) => form.includes(part)));
|
|
93
|
+
const leaks = (value) => layers(value).some((form) => parts.some((part) => form.includes(part)));
|
|
89
94
|
const names = (value) =>
|
|
90
|
-
|
|
95
|
+
layers(value).some((form) => form.includes(hostname)) || parseURL(value)?.origin === origin;
|
|
96
|
+
const carries = (value) => layers(value).some((form) => form.includes(plain(tag)));
|
|
97
|
+
return { failed, leaks, names, carries };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function discoveryRules({ failedURL, tag, trigger }) {
|
|
101
|
+
const { failed, leaks, names, carries } = failureRules({ failedURL, tag });
|
|
102
|
+
const { origin, host, hostname } = failed;
|
|
103
|
+
const named = [hostname, host, origin];
|
|
91
104
|
const cleanTitle = (title) => !leaks(title) && (!names(title) || named.includes(lower(title)));
|
|
92
105
|
const ownTitle = ({ url, title }) =>
|
|
93
106
|
plain(title) !== '' && [plain(url), unschemed(plain(url))].includes(plain(title));
|
|
107
|
+
const inner = (u) => (u && !u.host ? inner(parseURL(u.pathname)) : u);
|
|
108
|
+
const onHost = (u) => u?.hostname.replace(/\.$/, '') === hostname;
|
|
109
|
+
const references = (form) =>
|
|
110
|
+
Array.from(
|
|
111
|
+
form.matchAll(/(?:[a-z][a-z\d+.-]*:)+[\\/]*[^\\/?#&\s]*|[\\/]{2}[^\\/?#&\s]*/g),
|
|
112
|
+
([ref]) => inner(parseURL(ref, /^[\\/]/.test(ref) ? origin : undefined))
|
|
113
|
+
);
|
|
114
|
+
const exact = (form) =>
|
|
115
|
+
form === origin ||
|
|
116
|
+
(!onHost(inner(parseURL(form))) &&
|
|
117
|
+
references(form).every((u) => !onHost(u) || u.origin === origin));
|
|
118
|
+
const cleanURL = (url) => !leaks(url) && layers(url).every(exact);
|
|
94
119
|
const home = parseURL(trigger)?.href;
|
|
95
120
|
const clean = (info) => {
|
|
96
121
|
if (parseURL(info.url)?.href === home) return ownTitle(info) || cleanTitle(info.title);
|
|
97
|
-
return (
|
|
98
|
-
!leaks(info.url) && (lower(info.url) === origin || !names(info.url)) && cleanTitle(info.title)
|
|
99
|
-
);
|
|
122
|
+
return cleanURL(info.url) && (cleanTitle(info.title) || (ownTitle(info) && !leaks(info.title)));
|
|
100
123
|
};
|
|
101
|
-
|
|
102
|
-
[origin, errorPageURL].includes(lower(url)) ||
|
|
103
|
-
(lower(url) === '' && named.includes(lower(title)));
|
|
104
|
-
return { clean, shows };
|
|
124
|
+
return { clean, carries };
|
|
105
125
|
}
|
|
106
126
|
|
|
107
|
-
function eventsRedacted({ events, targetId, start,
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
127
|
+
function eventsRedacted({ events, targetId, start, ...failure }) {
|
|
128
|
+
const { clean, carries } = discoveryRules(failure);
|
|
129
|
+
return events
|
|
130
|
+
.slice(start)
|
|
131
|
+
.filter((e) => discoveryMethods.includes(e.method))
|
|
132
|
+
.every((e) =>
|
|
133
|
+
e.params?.targetInfo?.targetId === targetId
|
|
134
|
+
? clean(e.params.targetInfo)
|
|
135
|
+
: !carries(JSON.stringify(e.params ?? null))
|
|
136
|
+
);
|
|
117
137
|
}
|
|
118
138
|
|
|
119
|
-
async function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
139
|
+
async function privateBlank({ frame, reader, observer, targetId, failedURL, tag }) {
|
|
140
|
+
const { leaks, names } = failureRules({ failedURL, tag });
|
|
141
|
+
if (frame.url !== privateBlankURL || frame.unreachableUrl) return false;
|
|
142
|
+
const { targetInfo } = await reader.send('Target.getTargetInfo', { targetId });
|
|
143
|
+
if (targetInfo.url !== privateBlankURL) return false;
|
|
144
|
+
const read = async (expression) => {
|
|
145
|
+
const out = await outcome(
|
|
146
|
+
reader.send('Runtime.evaluate', { expression, returnByValue: true }, observer)
|
|
147
|
+
);
|
|
148
|
+
const value = out.result?.result?.value;
|
|
149
|
+
return out.ok && !out.result.exceptionDetails && typeof value === 'string' ? value : undefined;
|
|
150
|
+
};
|
|
151
|
+
const href = await read('location.href');
|
|
152
|
+
const title = await read('document.title');
|
|
153
|
+
if (href === undefined || title === undefined) return 'incomplete';
|
|
154
|
+
return (
|
|
155
|
+
href === privateBlankURL &&
|
|
156
|
+
![targetInfo.title, title].some((value) => leaks(value) || names(value))
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function redaction({ client, targetId, failedURL, ordinary, tag, start, result, discovery }) {
|
|
130
161
|
const info = await outcome(client.send('Target.getTargetInfo', { targetId }));
|
|
131
162
|
const list = await outcome(client.send('Target.getTargets'));
|
|
132
163
|
const before = client.events.length;
|
|
@@ -155,7 +186,6 @@ async function redaction({
|
|
|
155
186
|
events: client.events,
|
|
156
187
|
targetId,
|
|
157
188
|
start,
|
|
158
|
-
sent,
|
|
159
189
|
failedURL,
|
|
160
190
|
tag,
|
|
161
191
|
trigger: triggerURL(ordinary, failedURL),
|
|
@@ -290,7 +320,6 @@ export async function protectedErrorPage({
|
|
|
290
320
|
);
|
|
291
321
|
}
|
|
292
322
|
await outcome(reader.send('Page.bringToFront', {}, observer));
|
|
293
|
-
const sent = client.events.length;
|
|
294
323
|
const unsent = await scripted(client, session, ordinary, failedURL);
|
|
295
324
|
if (unsent) return missing(unsent);
|
|
296
325
|
let evidence;
|
|
@@ -300,7 +329,7 @@ export async function protectedErrorPage({
|
|
|
300
329
|
const { targetInfo } = await reader.send('Target.getTargetInfo', { targetId });
|
|
301
330
|
evidence = { frame: f, targetInfo };
|
|
302
331
|
return (
|
|
303
|
-
f.url ===
|
|
332
|
+
f.url === errorPageURL &&
|
|
304
333
|
f.securityOrigin === '://' &&
|
|
305
334
|
f.unreachableUrl === failedURL &&
|
|
306
335
|
targetInfo.url === failedURL
|
|
@@ -317,25 +346,24 @@ export async function protectedErrorPage({
|
|
|
317
346
|
return missing(`missing error commit ${JSON.stringify(evidence)}`);
|
|
318
347
|
result.live = live;
|
|
319
348
|
if (!live) return { ...result, liveWhy: commitWhy(result.diagnostics.errorCommit) };
|
|
320
|
-
await redaction({
|
|
321
|
-
client,
|
|
322
|
-
targetId,
|
|
323
|
-
failedURL,
|
|
324
|
-
ordinary,
|
|
325
|
-
tag,
|
|
326
|
-
start,
|
|
327
|
-
sent,
|
|
328
|
-
result,
|
|
329
|
-
discovery,
|
|
330
|
-
});
|
|
349
|
+
await redaction({ client, targetId, failedURL, ordinary, tag, start, result, discovery });
|
|
331
350
|
const beforeReload = (await frame()).loaderId;
|
|
332
351
|
result.reload = (await outcome(client.send('Page.reload', {}, session))).ok;
|
|
333
352
|
if (result.reload) {
|
|
334
|
-
result.
|
|
353
|
+
result.reload = await until(async () => {
|
|
335
354
|
const f = await frame();
|
|
336
|
-
|
|
355
|
+
result.reloadedError =
|
|
356
|
+
f.loaderId !== beforeReload && f.url === errorPageURL && f.unreachableUrl === failedURL;
|
|
357
|
+
result.reloadedBlank =
|
|
358
|
+
!result.reloadedError &&
|
|
359
|
+
side === 'guarded' &&
|
|
360
|
+
(await privateBlank({ frame: f, reader, observer, targetId, failedURL, tag }));
|
|
361
|
+
return result.reloadedError || result.reloadedBlank === true;
|
|
337
362
|
});
|
|
338
|
-
result.reload
|
|
363
|
+
if (!result.reload && result.reloadedBlank === 'incomplete') {
|
|
364
|
+
result.reload = 'incomplete';
|
|
365
|
+
result.incomplete = 'protected-error-page: the private blank page could not be read';
|
|
366
|
+
}
|
|
339
367
|
}
|
|
340
368
|
const recovery = `${ordinary}/blank?n=${tag}-recover`;
|
|
341
369
|
result.blank = (await outcome(client.send('Page.navigate', { url: recovery }, session))).ok;
|