privalint 0.2.0 → 0.3.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.de.md +30 -2
- package/README.md +28 -2
- package/dist/assessment.d.ts +6 -0
- package/dist/assessment.js +79 -0
- package/dist/assessment.js.map +1 -0
- package/dist/capture.d.ts +5 -0
- package/dist/capture.js +155 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.js +4 -3
- package/dist/cli.js.map +1 -1
- package/dist/consent.d.ts +3 -0
- package/dist/consent.js +13 -6
- package/dist/consent.js.map +1 -1
- package/dist/diagnostics.d.ts +27 -0
- package/dist/diagnostics.js +187 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/network.d.ts +67 -0
- package/dist/network.js +235 -0
- package/dist/network.js.map +1 -0
- package/dist/observations.d.ts +3 -0
- package/dist/observations.js +4 -0
- package/dist/observations.js.map +1 -0
- package/dist/reporters/capture.d.ts +5 -0
- package/dist/reporters/capture.js +35 -0
- package/dist/reporters/capture.js.map +1 -0
- package/dist/reporters/markdown.js +7 -0
- package/dist/reporters/markdown.js.map +1 -1
- package/dist/reporters/messages.js +12 -6
- package/dist/reporters/messages.js.map +1 -1
- package/dist/reporters/sarif.js +24 -0
- package/dist/reporters/sarif.js.map +1 -1
- package/dist/reporters/text.js +6 -2
- package/dist/reporters/text.js.map +1 -1
- package/dist/rules/google-fonts.js +2 -1
- package/dist/rules/google-fonts.js.map +1 -1
- package/dist/rules/reject-option.js +3 -3
- package/dist/rules/reject-option.js.map +1 -1
- package/dist/rules/third-party-hits.js +2 -1
- package/dist/rules/third-party-hits.js.map +1 -1
- package/dist/rules/tracker-hits.js +2 -1
- package/dist/rules/tracker-hits.js.map +1 -1
- package/dist/scan-options.d.ts +39 -0
- package/dist/scan-options.js +2 -0
- package/dist/scan-options.js.map +1 -0
- package/dist/scanner.d.ts +4 -38
- package/dist/scanner.js +84 -109
- package/dist/scanner.js.map +1 -1
- package/dist/types.d.ts +62 -0
- package/package.json +1 -1
|
@@ -15,17 +15,20 @@ const en = {
|
|
|
15
15
|
howToFix: 'How to fix',
|
|
16
16
|
disclaimer: 'Automated checks only. A clean result is not proof of GDPR compliance.',
|
|
17
17
|
consent(consent) {
|
|
18
|
+
if (consent.state === 'interaction-failed') {
|
|
19
|
+
return `Consent check: interaction failed (${consent.error ?? 'browser-failure'}); reject path untested`;
|
|
20
|
+
}
|
|
18
21
|
if (!consent.bannerFound) {
|
|
19
|
-
return 'Consent banner: none
|
|
22
|
+
return 'Consent banner: none detected; reject path untested (not a privacy finding)';
|
|
20
23
|
}
|
|
21
24
|
const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
|
|
22
25
|
if (consent.error !== undefined) {
|
|
23
26
|
return `Consent banner${vendor}: found, but rejecting failed: ${consent.error}`;
|
|
24
27
|
}
|
|
25
28
|
if (consent.rejected) {
|
|
26
|
-
return `Consent banner${vendor}: clicked "${consent.rejectLabel}" and reloaded`;
|
|
29
|
+
return `Consent banner${vendor}: clicked "${consent.rejectLabel}" and reloaded${consent.afterRejectComplete === false ? '; observation incomplete' : ''}`;
|
|
27
30
|
}
|
|
28
|
-
return `Consent banner${vendor}: found, no reject
|
|
31
|
+
return `Consent banner${vendor}: found, no supported reject option; reject path untested`;
|
|
29
32
|
},
|
|
30
33
|
};
|
|
31
34
|
const de = {
|
|
@@ -44,17 +47,20 @@ const de = {
|
|
|
44
47
|
howToFix: 'So beheben Sie es',
|
|
45
48
|
disclaimer: 'Nur automatisierte Prüfungen. Ein sauberes Ergebnis ist kein Nachweis der DSGVO-Konformität.',
|
|
46
49
|
consent(consent) {
|
|
50
|
+
if (consent.state === 'interaction-failed') {
|
|
51
|
+
return `Consent-Prüfung: Interaktion fehlgeschlagen (${consent.error ?? 'browser-failure'}); Ablehnen-Pfad ungeprüft`;
|
|
52
|
+
}
|
|
47
53
|
if (!consent.bannerFound) {
|
|
48
|
-
return 'Cookie-Banner: keines
|
|
54
|
+
return 'Cookie-Banner: keines erkannt; Ablehnen-Pfad ungeprüft (kein Datenschutzbefund)';
|
|
49
55
|
}
|
|
50
56
|
const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
|
|
51
57
|
if (consent.error !== undefined) {
|
|
52
58
|
return `Cookie-Banner${vendor}: gefunden, aber Ablehnen ist fehlgeschlagen: ${consent.error}`;
|
|
53
59
|
}
|
|
54
60
|
if (consent.rejected) {
|
|
55
|
-
return `Cookie-Banner${vendor}: „${consent.rejectLabel}“ geklickt und neu geladen`;
|
|
61
|
+
return `Cookie-Banner${vendor}: „${consent.rejectLabel}“ geklickt und neu geladen${consent.afterRejectComplete === false ? '; Erfassung unvollständig' : ''}`;
|
|
56
62
|
}
|
|
57
|
-
return `Cookie-Banner${vendor}: gefunden,
|
|
63
|
+
return `Cookie-Banner${vendor}: gefunden, keine unterstützte Ablehnen-Möglichkeit; Ablehnen-Pfad ungeprüft`;
|
|
58
64
|
},
|
|
59
65
|
};
|
|
60
66
|
const MESSAGES = { en, de };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/reporters/messages.ts"],"names":[],"mappings":"AAsBA,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAEvF,MAAM,EAAE,GAAmB;IACzB,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC;IAC1C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC;IAChD,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC;IACvC,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;IAC9C,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,wBAAwB,KAAK,KAAK,QAAQ,IAAI;IAC/E,EAAE,EAAE,IAAI;IACR,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,UAAU;IACtC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG;IACnE,GAAG,EAAE,MAAM;IACX,UAAU,EAAE,cAAc;IAC1B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,YAAY;IACtB,UAAU,EAAE,wEAAwE;IACpF,OAAO,CAAC,OAAO;QACb,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACzB,OAAO,
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/reporters/messages.ts"],"names":[],"mappings":"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"}
|
package/dist/reporters/sarif.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { REPOSITORY_URL, ruleDocsUrl, VERSION } from '../meta.js';
|
|
3
|
+
import { coverageMessage, isPartial } from './capture.js';
|
|
3
4
|
const LEVELS = {
|
|
4
5
|
error: 'error',
|
|
5
6
|
warning: 'warning',
|
|
@@ -39,6 +40,29 @@ export function formatSarif(result) {
|
|
|
39
40
|
},
|
|
40
41
|
},
|
|
41
42
|
results: result.findings.map(toResult),
|
|
43
|
+
invocations: [
|
|
44
|
+
{
|
|
45
|
+
executionSuccessful: !isPartial(result),
|
|
46
|
+
toolExecutionNotifications: isPartial(result)
|
|
47
|
+
? [
|
|
48
|
+
{
|
|
49
|
+
descriptor: { id: 'incomplete-observation' },
|
|
50
|
+
level: 'warning',
|
|
51
|
+
message: { text: coverageMessage(result) },
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
: [],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
properties: {
|
|
58
|
+
coverage: result.coverage,
|
|
59
|
+
observations: result.pages.map(({ url, capture, ruleEvaluations }) => ({
|
|
60
|
+
url,
|
|
61
|
+
capture,
|
|
62
|
+
ruleEvaluations,
|
|
63
|
+
})),
|
|
64
|
+
consent: result.consent,
|
|
65
|
+
},
|
|
42
66
|
},
|
|
43
67
|
],
|
|
44
68
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"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"}
|
package/dist/reporters/text.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
|
+
import { captureLines, coverageMessage, isPartial } from './capture.js';
|
|
2
3
|
import { messagesFor } from './messages.js';
|
|
3
4
|
import { countBySeverity, groupByPage } from './shared.js';
|
|
4
5
|
const MARKS = {
|
|
@@ -27,13 +28,16 @@ export function formatText(result, color = false) {
|
|
|
27
28
|
const pages = m.pages(result.pages.length);
|
|
28
29
|
const duration = m.duration(result.durationMs);
|
|
29
30
|
lines.push('');
|
|
31
|
+
lines.push(...captureLines(result));
|
|
32
|
+
if (isPartial(result))
|
|
33
|
+
lines.push(paint('yellow', coverageMessage(result)));
|
|
30
34
|
if (result.consent !== undefined) {
|
|
31
35
|
lines.push(paint('dim', m.consent(result.consent)));
|
|
32
36
|
}
|
|
33
|
-
if (result.findings.length === 0) {
|
|
37
|
+
if (result.findings.length === 0 && !isPartial(result)) {
|
|
34
38
|
lines.push(paint('green', `✔ ${m.noProblems(pages, duration)}`));
|
|
35
39
|
}
|
|
36
|
-
else {
|
|
40
|
+
else if (result.findings.length > 0) {
|
|
37
41
|
lines.push(`${paint('red', m.errors(counts.error))}, ${paint('yellow', m.warnings(counts.warning))} ${m.on} ${pages} (${duration}).`);
|
|
38
42
|
}
|
|
39
43
|
lines.push(paint('dim', m.disclaimer));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/reporters/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,WAAW,EAAuB,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI3D,MAAM,KAAK,GAAsC;IAC/C,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC;IACnB,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC;IACxB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,MAAkB,EAAE,KAAK,GAAG,KAAK;IAC1D,MAAM,KAAK,GAAG,CAAC,KAAY,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtF,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IACvE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/D,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAE/C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/reporters/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { say } from '../i18n.js';
|
|
2
|
+
import { observedRequests } from '../observations.js';
|
|
2
3
|
import { hostMatches, safeHost } from '../url.js';
|
|
3
4
|
const ID = 'google-fonts';
|
|
4
5
|
const GOOGLE_FONT_HOSTS = ['fonts.googleapis.com', 'fonts.gstatic.com'];
|
|
@@ -25,7 +26,7 @@ export const googleFonts = {
|
|
|
25
26
|
'consent. LG München I awarded a visitor damages for this in 2022.',
|
|
26
27
|
references: ['Art. 6(1) GDPR', 'LG München I, 20.01.2022, Az. 3 O 17493/20'],
|
|
27
28
|
check({ page, lang }) {
|
|
28
|
-
const requests = page.requests.filter((request) => isGoogleFontUrl(request.url));
|
|
29
|
+
const requests = observedRequests(page.requests).filter((request) => isGoogleFontUrl(request.url));
|
|
29
30
|
if (requests.length > 0) {
|
|
30
31
|
const count = requests.length;
|
|
31
32
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-fonts.js","sourceRoot":"","sources":["../../src/rules/google-fonts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAa,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"google-fonts.js","sourceRoot":"","sources":["../../src/rules/google-fonts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAa,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,EAAE,GAAG,cAAc,CAAC;AAC1B,MAAM,iBAAiB,GAAG,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;AAExE,+EAA+E;AAC/E,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;AAEtF,MAAM,GAAG,GAAS;IAChB,EAAE,EACA,2FAA2F;QAC3F,+FAA+F;QAC/F,yFAAyF;QACzF,oBAAoB;IACtB,EAAE,EACA,8FAA8F;QAC9F,0FAA0F;QAC1F,8FAA8F;QAC9F,uDAAuD;CAC1D,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,GAAW,EAAW,EAAE;IAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,IAAI,KAAK,SAAS,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAC7F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAS;IAC/B,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,yCAAyC;IAChD,WAAW,EACT,qFAAqF;QACrF,mEAAmE;IACrE,UAAU,EAAE,CAAC,gBAAgB,EAAE,4CAA4C,CAAC;IAC5E,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;QAClB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAClE,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAC7B,CAAC;QACF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC9B,OAAO;gBACL;oBACE,MAAM,EAAE,EAAE;oBACV,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;wBACjB,EAAE,EAAE,iCAAiC,KAAK,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;wBAC/E,EAAE,EAAE,wCAAwC,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,IAAI;qBAC9F,CAAC;oBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;oBACtB,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC1E,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;iBACpB;aACF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CACrC,CAAC,IAAI,EAAE,EAAE,CACP,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CACjE,CAAC;QACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO;gBACL;oBACE,MAAM,EAAE,EAAE;oBACV,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;wBACjB,EAAE,EAAE,mIAAmI;wBACvI,EAAE,EAAE,0KAA0K;qBAC/K,CAAC;oBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;oBACtB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC,IAAI,IAAI,CAAC;oBAC7E,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;wBACb,EAAE,EAAE,2DAA2D;wBAC/D,EAAE,EAAE,8DAA8D;qBACnE,CAAC;iBACe;aACpB,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { say } from '../i18n.js';
|
|
|
2
2
|
const ID = 'reject-option';
|
|
3
3
|
export const rejectOption = {
|
|
4
4
|
id: ID,
|
|
5
|
-
title: 'No
|
|
5
|
+
title: 'No supported reject control detected on the first layer of the banner',
|
|
6
6
|
description: 'Rejecting cookies must be as easy as accepting them. Most European regulators treat a banner ' +
|
|
7
7
|
'that offers "accept" on its first layer, but hides "reject" in the settings or behind a ' +
|
|
8
8
|
'link, as invalid consent.',
|
|
@@ -50,8 +50,8 @@ export const rejectOption = {
|
|
|
50
50
|
ruleId: ID,
|
|
51
51
|
severity: 'warning',
|
|
52
52
|
message: say(lang, {
|
|
53
|
-
en: `The consent banner${vendor} offers "${accept}"
|
|
54
|
-
de: `Das Cookie-Banner${vendor} bietet „${accept}
|
|
53
|
+
en: `The consent banner${vendor} offers "${accept}"; no supported first-layer reject control was detected. Verify the banner manually.`,
|
|
54
|
+
de: `Das Cookie-Banner${vendor} bietet „${accept}“; eine unterstützte Ablehnen-Steuerung auf der ersten Ebene wurde nicht erkannt. Das Banner manuell prüfen.`,
|
|
55
55
|
}),
|
|
56
56
|
pageUrl: page.finalUrl,
|
|
57
57
|
evidence,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reject-option.js","sourceRoot":"","sources":["../../src/rules/reject-option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAGjC,MAAM,EAAE,GAAG,eAAe,CAAC;AAE3B,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"reject-option.js","sourceRoot":"","sources":["../../src/rules/reject-option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAGjC,MAAM,EAAE,GAAG,eAAe,CAAC;AAE3B,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,uEAAuE;IAC9E,WAAW,EACT,+FAA+F;QAC/F,0FAA0F;QAC1F,2BAA2B;IAC7B,UAAU,EAAE;QACV,iDAAiD;QACjD,wEAAwE;QACxE,+CAA+C;QAC/C,iBAAiB;QACjB,gBAAgB;QAChB,mBAAmB;KACpB;IACD,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,GAAG,GAAG,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QACnF,MAAM,QAAQ,GAAG;YACf,GAAG,CAAC,IAAI,EAAE;gBACR,EAAE,EAAE,kBAAkB,OAAO,CAAC,WAAW,IAAI,YAAY,EAAE;gBAC3D,EAAE,EAAE,qBAAqB,OAAO,CAAC,WAAW,IAAI,mBAAmB,EAAE;aACtE,CAAC;SACH,CAAC;QACF,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO;gBACL;oBACE,MAAM,EAAE,EAAE;oBACV,QAAQ,EAAE,MAAM;oBAChB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;wBACjB,EAAE,EAAE,qBAAqB,MAAM,YAAY,MAAM,+DAA+D;wBAChH,EAAE,EAAE,oBAAoB,MAAM,YAAY,MAAM,+DAA+D;qBAChH,CAAC;oBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;oBACtB,QAAQ;oBACR,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;wBACb,EAAE,EAAE,sQAAsQ;wBAC1Q,EAAE,EAAE,0UAA0U;qBAC/U,CAAC;iBACH;aACF,CAAC;QACJ,CAAC;QACD,OAAO;YACL;gBACE,MAAM,EAAE,EAAE;gBACV,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;oBACjB,EAAE,EAAE,qBAAqB,MAAM,YAAY,MAAM,sFAAsF;oBACvI,EAAE,EAAE,oBAAoB,MAAM,YAAY,MAAM,8GAA8G;iBAC/J,CAAC;gBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;gBACtB,QAAQ;gBACR,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;oBACb,EAAE,EAAE,sIAAsI;oBAC1I,EAAE,EAAE,+IAA+I;iBACpJ,CAAC;aACH;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { observedRequests } from '../observations.js';
|
|
1
2
|
const MAX_EVIDENCE = 5;
|
|
2
3
|
/** Groups requests by the vendor `find` resolves them to. */
|
|
3
4
|
export function groupRequestsByVendor(requests, find) {
|
|
4
5
|
const byVendor = new Map();
|
|
5
|
-
for (const request of requests) {
|
|
6
|
+
for (const request of observedRequests(requests)) {
|
|
6
7
|
const vendor = find(request.url)?.vendor;
|
|
7
8
|
if (vendor !== undefined) {
|
|
8
9
|
byVendor.set(vendor, (byVendor.get(vendor) ?? new Set()).add(request.url));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"third-party-hits.js","sourceRoot":"","sources":["../../src/rules/third-party-hits.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"third-party-hits.js","sourceRoot":"","sources":["../../src/rules/third-party-hits.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,6DAA6D;AAC7D,MAAM,UAAU,qBAAqB,CACnC,QAAoC,EACpC,IAA6C;IAE7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,KAAK,MAAM,OAAO,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { findTrackerByCookie, findTrackerByUrl, } from '../data/trackers.js';
|
|
2
2
|
import { say } from '../i18n.js';
|
|
3
|
+
import { observedRequests } from '../observations.js';
|
|
3
4
|
const MAX_EVIDENCE = 5;
|
|
4
5
|
/** Matches requests and cookies against the tracker list, grouped by vendor. */
|
|
5
6
|
export function findTrackerHits(requests, cookies, lang) {
|
|
@@ -10,7 +11,7 @@ export function findTrackerHits(requests, cookies, lang) {
|
|
|
10
11
|
hit.evidence.add(evidence);
|
|
11
12
|
hits.set(tracker.vendor, hit);
|
|
12
13
|
};
|
|
13
|
-
for (const request of requests) {
|
|
14
|
+
for (const request of observedRequests(requests)) {
|
|
14
15
|
const tracker = findTrackerByUrl(request.url);
|
|
15
16
|
if (tracker !== undefined) {
|
|
16
17
|
record(tracker, `${requestLabel} ${request.url}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker-hits.js","sourceRoot":"","sources":["../../src/rules/tracker-hits.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAa,GAAG,EAAa,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"tracker-hits.js","sourceRoot":"","sources":["../../src/rules/tracker-hits.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAa,GAAG,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,YAAY,GAAG,CAAC,CAAC;AAQvB,gFAAgF;AAChF,MAAM,UAAU,eAAe,CAC7B,QAAoC,EACpC,OAAkC,EAClC,IAAU;IAEV,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC5E,MAAM,MAAM,GAAG,CAAC,OAAgB,EAAE,QAAgB,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAU,EAAE,CAAC;QACjF,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,EAAE,GAAG,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GACX,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;YAChC,gBAAgB,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACnE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,EAAE,UAAU,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO;QACP,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;KAC/C,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,eAAe,GAAkC;IACrD,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE;IAC7C,WAAW,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE;IACjD,gBAAgB,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,gBAAgB,EAAE;IAChE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE;IAC5C,sBAAsB,EAAE,EAAE,EAAE,EAAE,sBAAsB,EAAE,EAAE,EAAE,2BAA2B,EAAE;IACvF,aAAa,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE;CACxD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAyB,EAAE,IAAU,EAAE,EAAE,CACrE,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Lang } from './i18n.js';
|
|
2
|
+
import type { Region } from './legal.js';
|
|
3
|
+
import type { NetworkAdapter, NetworkLimits } from './network.js';
|
|
4
|
+
import type { PageSnapshot, Rule } from './types.js';
|
|
5
|
+
export interface ScanOptions {
|
|
6
|
+
maxPages?: number | undefined;
|
|
7
|
+
settleMs?: number | undefined;
|
|
8
|
+
/** Navigation/network-idle timeout, distinct from transport and capture deadlines. */
|
|
9
|
+
timeoutMs?: number | undefined;
|
|
10
|
+
locale?: string | undefined;
|
|
11
|
+
lang?: Lang | undefined;
|
|
12
|
+
/** Tool classification profile; does not determine which law applies. */
|
|
13
|
+
region?: Region | undefined;
|
|
14
|
+
rules?: readonly Rule[];
|
|
15
|
+
/** Legacy test helper: third-party requests receive synthetic empty responses. */
|
|
16
|
+
offline?: boolean;
|
|
17
|
+
consentCheck?: boolean | undefined;
|
|
18
|
+
headed?: boolean | undefined;
|
|
19
|
+
channel?: string | undefined;
|
|
20
|
+
/** Trusted hook receiving RAW observations. Do not log/expose without redaction. */
|
|
21
|
+
onPage?: (snapshot: PageSnapshot) => void;
|
|
22
|
+
/** Caller-owned transport; scan owns browser, fresh per-page contexts and request signals. */
|
|
23
|
+
networkAdapter?: NetworkAdapter;
|
|
24
|
+
/** Per-page budgets across initial loading and rejection. Requires networkAdapter. */
|
|
25
|
+
networkLimits?: NetworkLimits;
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
/** Entire capture including queue wait and consent; default 60s with an adapter. */
|
|
28
|
+
captureTimeoutMs?: number;
|
|
29
|
+
/** Stored issue details per page; counters are never truncated. Default 100. */
|
|
30
|
+
maxDiagnostics?: number;
|
|
31
|
+
/** Legacy default: throw on start-page navigation failure. Adapter default: report it. */
|
|
32
|
+
failureMode?: 'throw' | 'report';
|
|
33
|
+
}
|
|
34
|
+
export declare const DEFAULTS: {
|
|
35
|
+
maxPages: number;
|
|
36
|
+
settleMs: number;
|
|
37
|
+
timeoutMs: number;
|
|
38
|
+
locale: string;
|
|
39
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-options.js","sourceRoot":"","sources":["../src/scan-options.ts"],"names":[],"mappings":"AAkCA,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/scanner.d.ts
CHANGED
|
@@ -1,39 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
/** Maximum number of pages on the same site to visit, starting with the given URL. */
|
|
6
|
-
maxPages?: number | undefined;
|
|
7
|
-
/** Extra time to wait after the network is idle, to catch delayed tags. */
|
|
8
|
-
settleMs?: number | undefined;
|
|
9
|
-
/** Navigation timeout per page. */
|
|
10
|
-
timeoutMs?: number | undefined;
|
|
11
|
-
locale?: string | undefined;
|
|
12
|
-
/** Language of messages and fixes in the findings. */
|
|
13
|
-
lang?: Lang | undefined;
|
|
14
|
-
/** Country whose law the findings are judged by. */
|
|
15
|
-
region?: Region | undefined;
|
|
16
|
-
rules?: readonly Rule[];
|
|
17
|
-
/**
|
|
18
|
-
* Answer every third-party request with an empty response instead of fetching it.
|
|
19
|
-
* Requests are still recorded. Used by the test suite to stay off the network.
|
|
20
|
-
*/
|
|
21
|
-
offline?: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Click "reject" on the start page's consent banner and record what still loads.
|
|
24
|
-
* On by default.
|
|
25
|
-
*/
|
|
26
|
-
consentCheck?: boolean | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* Open a visible browser window instead of running headless. Some sites only show their
|
|
29
|
-
* consent banner to regular browsers. Needs a display, so it doesn't work on CI runners.
|
|
30
|
-
*/
|
|
31
|
-
headed?: boolean | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* Use an installed browser instead of Playwright's bundled Chromium,
|
|
34
|
-
* e.g. `chrome` or `msedge`.
|
|
35
|
-
*/
|
|
36
|
-
channel?: string | undefined;
|
|
37
|
-
onPage?: (snapshot: PageSnapshot) => void;
|
|
38
|
-
}
|
|
1
|
+
import { type ScanOptions } from './scan-options.js';
|
|
2
|
+
import type { ScanResult } from './types.js';
|
|
3
|
+
export type { ScanOptions } from './scan-options.js';
|
|
4
|
+
export declare function throwIfAborted(signal?: AbortSignal): void;
|
|
39
5
|
export declare function scan(target: string, options?: ScanOptions): Promise<ScanResult>;
|
package/dist/scanner.js
CHANGED
|
@@ -1,44 +1,67 @@
|
|
|
1
1
|
import { chromium } from 'playwright';
|
|
2
|
-
import {
|
|
2
|
+
import { assessPage } from './assessment.js';
|
|
3
|
+
import { capturePage } from './capture.js';
|
|
4
|
+
import { diagnosticUrl } from './diagnostics.js';
|
|
3
5
|
import { applyRegion } from './legal.js';
|
|
6
|
+
import { networkLimits } from './network.js';
|
|
4
7
|
import { defaultRules } from './rules/index.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import { DEFAULTS } from './scan-options.js';
|
|
9
|
+
import { crawlTarget, withoutHash } from './url.js';
|
|
10
|
+
function integer(value, name, minimum) {
|
|
11
|
+
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
12
|
+
throw new RangeError(`${name} must be a safe integer of at least ${minimum}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function throwIfAborted(signal) {
|
|
16
|
+
if (signal?.aborted)
|
|
17
|
+
throw new DOMException('Scan aborted', 'AbortError');
|
|
18
|
+
}
|
|
14
19
|
export async function scan(target, options = {}) {
|
|
20
|
+
throwIfAborted(options.signal);
|
|
15
21
|
const startedAt = Date.now();
|
|
16
22
|
const rules = options.rules ?? defaultRules;
|
|
17
|
-
const maxPages =
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
const maxPages = options.maxPages ?? DEFAULTS.maxPages;
|
|
24
|
+
integer(maxPages, 'maxPages', 1);
|
|
25
|
+
integer(options.settleMs ?? DEFAULTS.settleMs, 'settleMs', 0);
|
|
26
|
+
integer(options.timeoutMs ?? DEFAULTS.timeoutMs, 'timeoutMs', 1);
|
|
27
|
+
integer(options.maxDiagnostics ?? 100, 'maxDiagnostics', 0);
|
|
28
|
+
if (options.captureTimeoutMs !== undefined)
|
|
29
|
+
integer(options.captureTimeoutMs, 'captureTimeoutMs', 1);
|
|
30
|
+
if (options.networkLimits && !options.networkAdapter) {
|
|
31
|
+
throw new TypeError('networkLimits requires networkAdapter');
|
|
32
|
+
}
|
|
33
|
+
if (options.networkAdapter && options.offline) {
|
|
34
|
+
throw new TypeError('offline cannot be combined with networkAdapter');
|
|
35
|
+
}
|
|
36
|
+
if (options.networkAdapter)
|
|
37
|
+
networkLimits(options.networkLimits);
|
|
38
|
+
const lang = options.lang ?? 'en';
|
|
39
|
+
const region = options.region ?? 'de';
|
|
20
40
|
let siteUrl = new URL(target);
|
|
41
|
+
if (!/^https?:$/.test(siteUrl.protocol))
|
|
42
|
+
throw new TypeError('Expected an HTTP(S) target');
|
|
21
43
|
const browser = await chromium.launch({
|
|
22
44
|
headless: options.headed !== true,
|
|
23
45
|
...(options.channel === undefined ? {} : { channel: options.channel }),
|
|
24
46
|
});
|
|
25
47
|
try {
|
|
48
|
+
throwIfAborted(options.signal);
|
|
26
49
|
const snapshots = [];
|
|
27
50
|
const queue = [siteUrl.href];
|
|
28
51
|
const seen = new Set(queue);
|
|
29
52
|
const captured = new Set();
|
|
30
53
|
let url = queue.shift();
|
|
31
54
|
while (url !== undefined && snapshots.length < maxPages) {
|
|
55
|
+
throwIfAborted(options.signal);
|
|
32
56
|
const isStart = snapshots.length === 0;
|
|
33
57
|
const snapshot = await capturePage(browser, url, siteUrl, options, isStart);
|
|
34
58
|
if (isStart) {
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
const failureMode = options.failureMode ?? (options.networkAdapter ? 'report' : 'throw');
|
|
60
|
+
if (snapshot.error !== undefined && failureMode === 'throw') {
|
|
61
|
+
throw new Error(`Could not load ${diagnosticUrl(url)}: ${snapshot.error}`);
|
|
37
62
|
}
|
|
38
|
-
// Follow redirects like http -> https or apex -> www for the rest of the crawl.
|
|
39
63
|
siteUrl = new URL(snapshot.finalUrl);
|
|
40
64
|
}
|
|
41
|
-
// Several links can redirect to the same page; only lint it once.
|
|
42
65
|
const finalUrl = withoutHash(snapshot.finalUrl);
|
|
43
66
|
if (!captured.has(finalUrl)) {
|
|
44
67
|
captured.add(finalUrl);
|
|
@@ -55,121 +78,73 @@ export async function scan(target, options = {}) {
|
|
|
55
78
|
}
|
|
56
79
|
url = queue.shift();
|
|
57
80
|
}
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
isFirstParty(page.finalUrl, siteUrl))
|
|
63
|
-
.flatMap((page) => rules.flatMap((rule) => rule.check({ siteUrl, page, lang })));
|
|
64
|
-
const findings = applyRegion(observed, region);
|
|
65
|
-
return {
|
|
81
|
+
throwIfAborted(options.signal);
|
|
82
|
+
const assessments = snapshots.map((page, index) => assessPage(page, rules, siteUrl, lang, index === 0, options.consentCheck !== false));
|
|
83
|
+
const partial = assessments.some((assessment) => assessment.evaluations.some((evaluation) => evaluation.partial || evaluation.reason === 'consent-disabled')) || snapshots.some((page) => !page.capture?.complete);
|
|
84
|
+
const result = {
|
|
66
85
|
siteUrl: siteUrl.href,
|
|
67
86
|
lang,
|
|
68
87
|
region,
|
|
69
88
|
scannedAt: new Date(startedAt).toISOString(),
|
|
70
89
|
durationMs: Date.now() - startedAt,
|
|
71
|
-
pages: snapshots.map((page) => ({
|
|
90
|
+
pages: snapshots.map((page, index) => ({
|
|
72
91
|
url: page.url,
|
|
73
92
|
finalUrl: page.finalUrl,
|
|
74
93
|
status: page.status,
|
|
75
|
-
requestCount: page.requests.length,
|
|
94
|
+
requestCount: page.requestCount ?? page.requests.length,
|
|
76
95
|
cookieCount: page.cookies.length,
|
|
77
96
|
...(page.error === undefined ? {} : { error: page.error }),
|
|
97
|
+
...(page.capture === undefined ? {} : { capture: page.capture }),
|
|
98
|
+
ruleEvaluations: assessments[index]?.evaluations ?? [],
|
|
78
99
|
})),
|
|
79
100
|
...consentSummary(snapshots[0]),
|
|
80
|
-
findings,
|
|
101
|
+
findings: applyRegion(assessments.flatMap((assessment) => assessment.findings), region),
|
|
81
102
|
rules: rules.map(({ check: _check, ...meta }) => meta),
|
|
103
|
+
coverage: partial ? 'partial' : 'complete',
|
|
82
104
|
};
|
|
105
|
+
return options.networkAdapter ? redactReport(result) : result;
|
|
83
106
|
}
|
|
84
107
|
finally {
|
|
85
108
|
await browser.close();
|
|
86
109
|
}
|
|
87
110
|
}
|
|
88
111
|
function consentSummary(start) {
|
|
89
|
-
if (start?.consent === undefined)
|
|
112
|
+
if (start?.consent === undefined)
|
|
90
113
|
return {};
|
|
91
|
-
}
|
|
92
114
|
const { afterReject: _afterReject, ...summary } = start.consent;
|
|
93
115
|
return { consent: summary };
|
|
94
116
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
.
|
|
117
|
-
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
.slice(0, 200),
|
|
128
|
-
})));
|
|
129
|
-
const resourceHints = await page.$$eval('link[rel][href]', (elements) => elements.map((link) => ({
|
|
130
|
-
rel: (link.getAttribute('rel') ?? '').toLowerCase(),
|
|
131
|
-
href: link.href,
|
|
132
|
-
})));
|
|
133
|
-
const cookies = (await context.cookies()).map(({ name, domain, path, expires }) => ({
|
|
134
|
-
name,
|
|
135
|
-
domain,
|
|
136
|
-
path,
|
|
137
|
-
expires,
|
|
138
|
-
}));
|
|
139
|
-
const snapshot = {
|
|
140
|
-
url,
|
|
141
|
-
finalUrl: page.url(),
|
|
142
|
-
status: response?.status() ?? null,
|
|
143
|
-
// Copy: the listener keeps writing to `requests` during the consent check.
|
|
144
|
-
requests: [...requests],
|
|
145
|
-
cookies,
|
|
146
|
-
links,
|
|
147
|
-
resourceHints,
|
|
148
|
-
};
|
|
149
|
-
if (checkConsent && options.consentCheck !== false) {
|
|
150
|
-
snapshot.consent = await observeConsent(page, context, requests, {
|
|
151
|
-
settleMs: options.settleMs ?? DEFAULTS.settleMs,
|
|
152
|
-
timeoutMs: options.timeoutMs ?? DEFAULTS.timeoutMs,
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
return snapshot;
|
|
156
|
-
}
|
|
157
|
-
catch (error) {
|
|
158
|
-
// Downloads, timeouts and crashed pages should not end the whole crawl.
|
|
159
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
160
|
-
return {
|
|
161
|
-
url,
|
|
162
|
-
finalUrl: url,
|
|
163
|
-
status: null,
|
|
164
|
-
requests,
|
|
165
|
-
cookies: [],
|
|
166
|
-
links: [],
|
|
167
|
-
resourceHints: [],
|
|
168
|
-
error: message.split('\n')[0] ?? message,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
finally {
|
|
172
|
-
await context.close();
|
|
173
|
-
}
|
|
117
|
+
/** Adapter reports omit URL credentials, paths, queries and fragments by default. */
|
|
118
|
+
function redactReport(result) {
|
|
119
|
+
const redactText = (text) => text.replace(/https?:\/\/[^\s<>"']+/gi, diagnosticUrl);
|
|
120
|
+
return {
|
|
121
|
+
...result,
|
|
122
|
+
siteUrl: diagnosticUrl(result.siteUrl),
|
|
123
|
+
...(result.consent === undefined
|
|
124
|
+
? {}
|
|
125
|
+
: {
|
|
126
|
+
consent: {
|
|
127
|
+
...result.consent,
|
|
128
|
+
...(result.consent.acceptLabel === undefined
|
|
129
|
+
? {}
|
|
130
|
+
: { acceptLabel: redactText(result.consent.acceptLabel) }),
|
|
131
|
+
...(result.consent.rejectLabel === undefined
|
|
132
|
+
? {}
|
|
133
|
+
: { rejectLabel: redactText(result.consent.rejectLabel) }),
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
pages: result.pages.map((page) => ({
|
|
137
|
+
...page,
|
|
138
|
+
url: diagnosticUrl(page.url),
|
|
139
|
+
finalUrl: diagnosticUrl(page.finalUrl),
|
|
140
|
+
})),
|
|
141
|
+
findings: result.findings.map((finding) => ({
|
|
142
|
+
...finding,
|
|
143
|
+
pageUrl: diagnosticUrl(finding.pageUrl),
|
|
144
|
+
message: redactText(finding.message),
|
|
145
|
+
evidence: finding.evidence.map(redactText),
|
|
146
|
+
...(finding.fix === undefined ? {} : { fix: redactText(finding.fix) }),
|
|
147
|
+
})),
|
|
148
|
+
};
|
|
174
149
|
}
|
|
175
150
|
//# sourceMappingURL=scanner.js.map
|