@ai-ecoverse/slicc-browsers 1.18.19 → 1.18.20
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 +8 -8
- package/package.json +2 -2
- package/protected-error-page.mjs +44 -15
package/guard-vectors.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"setVersion": "1.18.
|
|
3
|
+
"setVersion": "1.18.20",
|
|
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, 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",
|
|
1203
|
+
"means": "protected error-page recover: every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
|
@@ -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, 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",
|
|
1352
|
+
"means": "protected error-page recover (query): every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
|
@@ -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, 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",
|
|
1501
|
+
"means": "protected error-page recover (fragment): every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
|
@@ -1646,7 +1646,7 @@
|
|
|
1646
1646
|
}
|
|
1647
1647
|
},
|
|
1648
1648
|
"eventsRedacted": {
|
|
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",
|
|
1649
|
+
"means": "protected error-page restore: every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
|
@@ -1827,7 +1827,7 @@
|
|
|
1827
1827
|
}
|
|
1828
1828
|
},
|
|
1829
1829
|
"eventsRedacted": {
|
|
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",
|
|
1830
|
+
"means": "protected error-page sticky: every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
|
@@ -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, 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",
|
|
2023
|
+
"means": "protected error-page sticky (query): every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
|
@@ -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, 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",
|
|
2216
|
+
"means": "protected error-page sticky (fragment): every discovery event for the tab shows, decoded as often as it takes and without the characters the URL parser ignores, 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, with a title that names the protected host, if at all, only as that bare origin, 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",
|
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.20",
|
|
4
4
|
"description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"test:unit:guard": "mkdir -p coverage/unit && node --experimental-vm-modules --no-warnings --experimental-test-coverage --test --test-concurrency=1 --test-coverage-include=guard-runner.mjs --test-coverage-include=guard-driver.mjs --test-coverage-include=fixture-server.mjs --test-coverage-include=fixture-client.mjs --test-coverage-include=observer-target.mjs --test-coverage-include=frame-read.mjs --test-coverage-include=bfcache-restore.mjs --test-coverage-include=protected-error-page.mjs --test-coverage-include=unparseable-url.mjs --test-coverage-include=scripts/browser-runner.mjs --test-coverage-include=scripts/validate.mjs --test-reporter=lcov --test-reporter-destination=coverage/unit/guard.lcov test/unit/guard-*.test.mjs && slicc-diff-cover coverage/unit/guard.lcov"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
|
-
"@ai-ecoverse/slicc-cdp": "1.42.
|
|
82
|
+
"@ai-ecoverse/slicc-cdp": "1.42.4",
|
|
83
83
|
"@ai-ecoverse/slicc-shared-web": "2.13.6",
|
|
84
84
|
"@biomejs/biome": "2.6.2",
|
|
85
85
|
"ajv": "8.20.0",
|
package/protected-error-page.mjs
CHANGED
|
@@ -59,11 +59,27 @@ const plain = (value) =>
|
|
|
59
59
|
String.fromCharCode(Number.parseInt(hex, 16))
|
|
60
60
|
)
|
|
61
61
|
);
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
const utf8 = (value) =>
|
|
63
|
+
lower(
|
|
64
|
+
value.replace(/(?:%[0-9a-f]{2})+/gi, (run) =>
|
|
65
|
+
new TextDecoder().decode(
|
|
66
|
+
Uint8Array.from(run.slice(1).split('%'), (hex) => Number.parseInt(hex, 16))
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
const ignored = (form) => form.replace(/[\t\n\r]/g, '');
|
|
71
|
+
const readings = (value) =>
|
|
72
|
+
[
|
|
73
|
+
[(form) => form, plain],
|
|
74
|
+
[ignored, plain],
|
|
75
|
+
[ignored, utf8],
|
|
76
|
+
].map(([read, decode]) => {
|
|
77
|
+
const out = [read(lower(value))];
|
|
78
|
+
for (let next = read(decode(out[0])); next !== out.at(-1); next = read(decode(next)))
|
|
79
|
+
out.push(next);
|
|
80
|
+
return out;
|
|
81
|
+
});
|
|
82
|
+
const layers = (value) => readings(value).flat();
|
|
67
83
|
const unschemed = (value) => value.replace(/^[a-z][a-z\d+.-]*:\/\//, '');
|
|
68
84
|
|
|
69
85
|
const encoded = (url) =>
|
|
@@ -101,25 +117,38 @@ function discoveryRules({ failedURL, tag, trigger }) {
|
|
|
101
117
|
const { failed, leaks, names, carries } = failureRules({ failedURL, tag });
|
|
102
118
|
const { origin, host, hostname } = failed;
|
|
103
119
|
const named = [hostname, host, origin];
|
|
104
|
-
const cleanTitle = (
|
|
120
|
+
const cleanTitle = ({ title, url }) =>
|
|
121
|
+
!leaks(title) &&
|
|
122
|
+
(!names(title) ||
|
|
123
|
+
named.includes(lower(title)) ||
|
|
124
|
+
(!layers(url).includes(origin) && referenced(title)));
|
|
105
125
|
const ownTitle = ({ url, title }) =>
|
|
106
126
|
plain(title) !== '' && [plain(url), unschemed(plain(url))].includes(plain(title));
|
|
107
127
|
const inner = (u) => (u && !u.host ? inner(parseURL(u.pathname)) : u);
|
|
108
128
|
const onHost = (u) => u?.hostname.replace(/\.$/, '') === hostname;
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
129
|
+
const pattern = /(?:[a-z][a-z\d+.-]*:)+[\\/]*[^\\/?#&\s]*|[\\/]{2}[^\\/?#&\s]*/g;
|
|
130
|
+
const spaced = (form) => Array.from(form, (c) => (c > ' ' ? c : ' ')).join('');
|
|
131
|
+
const resolve = (ref) => inner(parseURL(ref, /^[\\/]/.test(ref) ? origin : undefined));
|
|
132
|
+
const fine = (text) =>
|
|
133
|
+
Array.from(text.matchAll(pattern), ([ref]) => resolve(ref)).every(
|
|
134
|
+
(u) => !onHost(u) || u.origin === origin
|
|
113
135
|
);
|
|
114
136
|
const exact = (form) =>
|
|
115
|
-
form === origin ||
|
|
116
|
-
|
|
117
|
-
|
|
137
|
+
form === origin || (!onHost(inner(parseURL(form))) && fine(form) && fine(spaced(form)));
|
|
138
|
+
const only = (ref, at, text) =>
|
|
139
|
+
parseURL(ref, /^[\\/]/.test(ref) ? origin : undefined)?.href === `${origin}/` &&
|
|
140
|
+
!/[\\/?#]/.test(text[at + ref.length] ?? '');
|
|
141
|
+
const bare = (form) =>
|
|
142
|
+
!spaced(form)
|
|
143
|
+
.replace(pattern, (ref, at, text) => (only(ref, at, text) ? ref.replace(hostname, ' ') : ref))
|
|
144
|
+
.includes(hostname);
|
|
145
|
+
const referenced = (title) =>
|
|
146
|
+
layers(title).every(exact) && readings(title).every((read) => bare(read.at(-1)));
|
|
118
147
|
const cleanURL = (url) => !leaks(url) && layers(url).every(exact);
|
|
119
148
|
const home = parseURL(trigger)?.href;
|
|
120
149
|
const clean = (info) => {
|
|
121
|
-
if (parseURL(info.url)?.href === home) return ownTitle(info) || cleanTitle(info
|
|
122
|
-
return cleanURL(info.url) && (cleanTitle(info
|
|
150
|
+
if (parseURL(info.url)?.href === home) return ownTitle(info) || cleanTitle(info);
|
|
151
|
+
return cleanURL(info.url) && (cleanTitle(info) || (ownTitle(info) && !leaks(info.title)));
|
|
123
152
|
};
|
|
124
153
|
return { clean, carries };
|
|
125
154
|
}
|