@slashgear/gdpr-cookie-scanner 1.0.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.
Files changed (85) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +24 -0
  6. package/.github/workflows/ci.yml +38 -0
  7. package/.github/workflows/release.yml +57 -0
  8. package/.idea/gdpr-report.iml +8 -0
  9. package/.idea/modules.xml +8 -0
  10. package/.idea/vcs.xml +6 -0
  11. package/CHANGELOG.md +7 -0
  12. package/CLAUDE.md +75 -0
  13. package/CODE_OF_CONDUCT.md +41 -0
  14. package/CONTRIBUTING.md +79 -0
  15. package/LICENSE +21 -0
  16. package/README.md +127 -0
  17. package/SECURITY.md +15 -0
  18. package/dist/analyzers/compliance.d.ts +13 -0
  19. package/dist/analyzers/compliance.d.ts.map +1 -0
  20. package/dist/analyzers/compliance.js +171 -0
  21. package/dist/analyzers/compliance.js.map +1 -0
  22. package/dist/analyzers/wording.d.ts +13 -0
  23. package/dist/analyzers/wording.d.ts.map +1 -0
  24. package/dist/analyzers/wording.js +91 -0
  25. package/dist/analyzers/wording.js.map +1 -0
  26. package/dist/classifiers/cookie-classifier.d.ts +8 -0
  27. package/dist/classifiers/cookie-classifier.d.ts.map +1 -0
  28. package/dist/classifiers/cookie-classifier.js +108 -0
  29. package/dist/classifiers/cookie-classifier.js.map +1 -0
  30. package/dist/classifiers/network-classifier.d.ts +9 -0
  31. package/dist/classifiers/network-classifier.d.ts.map +1 -0
  32. package/dist/classifiers/network-classifier.js +51 -0
  33. package/dist/classifiers/network-classifier.js.map +1 -0
  34. package/dist/classifiers/tracker-list.d.ts +16 -0
  35. package/dist/classifiers/tracker-list.d.ts.map +1 -0
  36. package/dist/classifiers/tracker-list.js +86 -0
  37. package/dist/classifiers/tracker-list.js.map +1 -0
  38. package/dist/cli.d.ts +3 -0
  39. package/dist/cli.d.ts.map +1 -0
  40. package/dist/cli.js +110 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/report/generator.d.ts +19 -0
  43. package/dist/report/generator.d.ts.map +1 -0
  44. package/dist/report/generator.js +552 -0
  45. package/dist/report/generator.js.map +1 -0
  46. package/dist/scanner/browser.d.ts +11 -0
  47. package/dist/scanner/browser.d.ts.map +1 -0
  48. package/dist/scanner/browser.js +38 -0
  49. package/dist/scanner/browser.js.map +1 -0
  50. package/dist/scanner/consent-modal.d.ts +5 -0
  51. package/dist/scanner/consent-modal.d.ts.map +1 -0
  52. package/dist/scanner/consent-modal.js +244 -0
  53. package/dist/scanner/consent-modal.js.map +1 -0
  54. package/dist/scanner/cookies.d.ts +11 -0
  55. package/dist/scanner/cookies.d.ts.map +1 -0
  56. package/dist/scanner/cookies.js +30 -0
  57. package/dist/scanner/cookies.js.map +1 -0
  58. package/dist/scanner/index.d.ts +9 -0
  59. package/dist/scanner/index.d.ts.map +1 -0
  60. package/dist/scanner/index.js +146 -0
  61. package/dist/scanner/index.js.map +1 -0
  62. package/dist/scanner/network.d.ts +8 -0
  63. package/dist/scanner/network.d.ts.map +1 -0
  64. package/dist/scanner/network.js +41 -0
  65. package/dist/scanner/network.js.map +1 -0
  66. package/dist/types.d.ts +105 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +2 -0
  69. package/dist/types.js.map +1 -0
  70. package/package.json +52 -0
  71. package/renovate.json +17 -0
  72. package/src/analyzers/compliance.ts +203 -0
  73. package/src/analyzers/wording.ts +112 -0
  74. package/src/classifiers/cookie-classifier.ts +125 -0
  75. package/src/classifiers/network-classifier.ts +65 -0
  76. package/src/classifiers/tracker-list.ts +105 -0
  77. package/src/cli.ts +134 -0
  78. package/src/report/generator.ts +703 -0
  79. package/src/scanner/browser.ts +52 -0
  80. package/src/scanner/consent-modal.ts +276 -0
  81. package/src/scanner/cookies.ts +43 -0
  82. package/src/scanner/index.ts +163 -0
  83. package/src/scanner/network.ts +51 -0
  84. package/src/types.ts +134 -0
  85. package/tsconfig.json +18 -0
@@ -0,0 +1,552 @@
1
+ import { execFile } from "child_process";
2
+ import { writeFile, mkdir } from "fs/promises";
3
+ import { basename, dirname, join } from "path";
4
+ import { promisify } from "util";
5
+ import { fileURLToPath } from "url";
6
+ const execFileAsync = promisify(execFile);
7
+ const oxfmtBin = join(dirname(fileURLToPath(import.meta.url)), "../../node_modules/.bin/oxfmt");
8
+ export class ReportGenerator {
9
+ options;
10
+ constructor(options) {
11
+ this.options = options;
12
+ }
13
+ async generate(result) {
14
+ await mkdir(this.options.outputDir, { recursive: true });
15
+ const hostname = new URL(result.url).hostname.replace(/^www\./, "");
16
+ const date = new Date(result.scanDate).toISOString().split("T")[0];
17
+ const filename = `gdpr-report-${hostname}-${date}.md`;
18
+ const outputPath = join(this.options.outputDir, filename);
19
+ const markdown = this.buildMarkdown(result);
20
+ await writeFile(outputPath, markdown, "utf-8");
21
+ await execFileAsync(oxfmtBin, [outputPath]).catch(() => { });
22
+ const checklistFilename = `gdpr-checklist-${hostname}-${date}.md`;
23
+ const checklistPath = join(this.options.outputDir, checklistFilename);
24
+ const checklist = this.buildChecklist(result);
25
+ await writeFile(checklistPath, checklist, "utf-8");
26
+ await execFileAsync(oxfmtBin, [checklistPath]).catch(() => { });
27
+ return outputPath;
28
+ }
29
+ buildMarkdown(r) {
30
+ const hostname = new URL(r.url).hostname;
31
+ const scanDate = new Date(r.scanDate).toLocaleString("en-GB");
32
+ const durationSec = (r.duration / 1000).toFixed(1);
33
+ const grade = r.compliance.grade;
34
+ const score = r.compliance.total;
35
+ const gradeEmoji = grade === "A" ? "🟢" : grade === "B" ? "🟡" : grade === "C" ? "🟠" : "🔴";
36
+ const sections = [];
37
+ // ── Header ────────────────────────────────────────────────────
38
+ sections.push(`# GDPR Compliance Report — ${hostname}`);
39
+ sections.push(`
40
+ > **Scan date:** ${scanDate}
41
+ > **Scanned URL:** ${r.url}
42
+ > **Scan duration:** ${durationSec}s
43
+ > **Tool:** gdpr-cookie-scanner v0.1.0
44
+ `);
45
+ // ── Global score ──────────────────────────────────────────────
46
+ sections.push(`## Global Compliance Score\n`);
47
+ sections.push(`### ${gradeEmoji} ${score}/100 — Grade ${grade}\n`);
48
+ sections.push(this.buildScoreTable(r));
49
+ // ── Executive summary ─────────────────────────────────────────
50
+ sections.push(`## Executive Summary\n`);
51
+ sections.push(this.buildExecutiveSummary(r));
52
+ // ── Consent modal ─────────────────────────────────────────────
53
+ sections.push(`## 1. Consent Modal\n`);
54
+ sections.push(this.buildModalSection(r));
55
+ // ── Dark patterns ─────────────────────────────────────────────
56
+ sections.push(`## 2. Dark Patterns and Detected Issues\n`);
57
+ sections.push(this.buildIssuesSection(r.compliance.issues));
58
+ // ── Cookies before interaction ────────────────────────────────
59
+ sections.push(`## 3. Cookies Set Before Any Interaction\n`);
60
+ sections.push(this.buildCookiesTable(r.cookiesBeforeInteraction, "before-interaction"));
61
+ // ── Cookies after reject ──────────────────────────────────────
62
+ sections.push(`## 4. Cookies After Consent Rejection\n`);
63
+ sections.push(this.buildCookiesAfterRejectSection(r));
64
+ // ── Cookies after accept ──────────────────────────────────────
65
+ sections.push(`## 5. Cookies After Consent Acceptance\n`);
66
+ sections.push(this.buildCookiesTable(r.cookiesAfterAccept, "after-accept"));
67
+ // ── Network tracker requests ──────────────────────────────────
68
+ sections.push(`## 6. Network Requests — Detected Trackers\n`);
69
+ sections.push(this.buildNetworkSection(r));
70
+ // ── Recommendations ───────────────────────────────────────────
71
+ sections.push(`## 7. Recommendations\n`);
72
+ sections.push(this.buildRecommendations(r));
73
+ // ── Scan errors ───────────────────────────────────────────────
74
+ if (r.errors.length > 0) {
75
+ sections.push(`## Scan Errors and Warnings\n`);
76
+ sections.push(r.errors.map((e) => `- ⚠️ ${e}`).join("\n"));
77
+ }
78
+ // ── Legal references ──────────────────────────────────────────
79
+ sections.push(`## Legal References\n`);
80
+ sections.push(`
81
+ - **RGPD Art. 7** — Conditions for consent
82
+ - **RGPD Recital 32** — Consent must result from an unambiguous positive action
83
+ - **ePrivacy Directive 2002/58/EC** — Consent requirement for non-essential cookies
84
+ - **CEPD Guidelines 05/2020** — Consent under the RGPD
85
+ - **CEPD Guidelines 03/2022** — Dark patterns on platforms
86
+ - **CNIL Recommendation 2022** — Rejection must be as easy as acceptance (same number of clicks)
87
+ `);
88
+ return sections.join("\n\n") + "\n";
89
+ }
90
+ buildScoreTable(r) {
91
+ const { breakdown } = r.compliance;
92
+ const row = (label, score, max) => {
93
+ const pct = Math.round((score / max) * 100);
94
+ const bar = "█".repeat(Math.round(pct / 10)) + "░".repeat(10 - Math.round(pct / 10));
95
+ const status = pct >= 80 ? "✅" : pct >= 50 ? "⚠️" : "❌";
96
+ return `| ${label} | ${score}/${max} | ${bar} | ${status} |`;
97
+ };
98
+ return `| Criterion | Score | Progress | Status |
99
+ |-----------|-------|----------|--------|
100
+ ${row("Consent validity", breakdown.consentValidity, 25)}
101
+ ${row("Easy refusal", breakdown.easyRefusal, 25)}
102
+ ${row("Transparency", breakdown.transparency, 25)}
103
+ ${row("Cookie behavior", breakdown.cookieBehavior, 25)}
104
+ | **TOTAL** | **${r.compliance.total}/100** | | **${r.compliance.grade}** |
105
+ `;
106
+ }
107
+ buildExecutiveSummary(r) {
108
+ const criticalCount = r.compliance.issues.filter((i) => i.severity === "critical").length;
109
+ const warningCount = r.compliance.issues.filter((i) => i.severity === "warning").length;
110
+ const illegalPreCookies = r.cookiesBeforeInteraction.filter((c) => c.requiresConsent);
111
+ const persistAfterReject = r.cookiesAfterReject.filter((c) => c.requiresConsent);
112
+ const preInteractionTrackers = r.networkBeforeInteraction.filter((n) => n.trackerCategory !== null);
113
+ const lines = [];
114
+ if (!r.modal.detected) {
115
+ lines.push("❌ **No consent modal detected.** The site sets cookies without requesting consent.");
116
+ }
117
+ else {
118
+ lines.push(`✅ Consent modal detected (\`${r.modal.selector}\`).`);
119
+ }
120
+ if (illegalPreCookies.length > 0) {
121
+ lines.push(`❌ **${illegalPreCookies.length} non-essential cookie(s)** set before any interaction (RGPD violation).`);
122
+ }
123
+ else {
124
+ lines.push("✅ No non-essential cookie set before interaction.");
125
+ }
126
+ if (persistAfterReject.length > 0) {
127
+ lines.push(`❌ **${persistAfterReject.length} non-essential cookie(s)** persisting after rejection (RGPD violation).`);
128
+ }
129
+ else {
130
+ lines.push("✅ Non-essential cookies are correctly removed after rejection.");
131
+ }
132
+ if (preInteractionTrackers.length > 0) {
133
+ lines.push(`❌ **${preInteractionTrackers.length} tracker request(s)** fired before consent.`);
134
+ }
135
+ else {
136
+ lines.push("✅ No tracker requests before consent.");
137
+ }
138
+ lines.push(`\n**${criticalCount} critical issue(s)** and **${warningCount} warning(s)** identified.`);
139
+ return lines.join("\n");
140
+ }
141
+ buildModalSection(r) {
142
+ if (!r.modal.detected) {
143
+ return "_No consent modal detected on the page._\n";
144
+ }
145
+ const { modal } = r;
146
+ const acceptBtn = modal.buttons.find((b) => b.type === "accept");
147
+ const rejectBtn = modal.buttons.find((b) => b.type === "reject");
148
+ const prefBtn = modal.buttons.find((b) => b.type === "preferences");
149
+ const preTicked = modal.checkboxes.filter((c) => c.isCheckedByDefault);
150
+ const lines = [
151
+ `**CSS selector:** \`${modal.selector}\``,
152
+ `**Granular controls:** ${modal.hasGranularControls ? "✅ Yes" : "❌ No"}`,
153
+ `**Layer count:** ${modal.layerCount}`,
154
+ "",
155
+ "### Detected buttons",
156
+ "",
157
+ "| Button | Text | Visible | Font size | Contrast ratio |",
158
+ "|--------|------|---------|-----------|----------------|",
159
+ ...modal.buttons.map((b) => this.buildButtonRow(b)),
160
+ "",
161
+ ];
162
+ if (acceptBtn && rejectBtn) {
163
+ lines.push("### Comparative analysis: Accept / Reject\n");
164
+ if (acceptBtn.fontSize &&
165
+ rejectBtn.fontSize &&
166
+ acceptBtn.fontSize > rejectBtn.fontSize * 1.2) {
167
+ lines.push(`⚠️ The **Accept** button (${acceptBtn.fontSize}px) is larger than the **Reject** button (${rejectBtn.fontSize}px).`);
168
+ }
169
+ else {
170
+ lines.push("✅ Accept / Reject button sizes are comparable.");
171
+ }
172
+ const acceptArea = acceptBtn.boundingBox
173
+ ? acceptBtn.boundingBox.width * acceptBtn.boundingBox.height
174
+ : 0;
175
+ const rejectArea = rejectBtn.boundingBox
176
+ ? rejectBtn.boundingBox.width * rejectBtn.boundingBox.height
177
+ : 0;
178
+ if (acceptArea > rejectArea * 2) {
179
+ lines.push(`⚠️ **Accept** button area (${Math.round(acceptArea)}px²) is significantly larger than **Reject** (${Math.round(rejectArea)}px²).`);
180
+ }
181
+ }
182
+ if (preTicked.length > 0) {
183
+ lines.push("\n### Pre-ticked checkboxes (RGPD violation)\n");
184
+ lines.push("| Name | Label |");
185
+ lines.push("|------|-------|");
186
+ for (const cb of preTicked) {
187
+ lines.push(`| \`${cb.name}\` | ${cb.label} |`);
188
+ }
189
+ }
190
+ if (modal.screenshotPath) {
191
+ lines.push(`\n### Screenshot\n`);
192
+ lines.push(`![Consent modal](${basename(modal.screenshotPath)})`);
193
+ }
194
+ lines.push("\n### Modal text excerpt\n");
195
+ lines.push(`> ${modal.text.substring(0, 500)}${modal.text.length > 500 ? "..." : ""}`);
196
+ return lines.join("\n");
197
+ }
198
+ buildButtonRow(b) {
199
+ const visible = b.isVisible ? "✅" : "❌";
200
+ const fontSize = b.fontSize ? `${b.fontSize}px` : "—";
201
+ const contrast = b.contrastRatio !== null ? `${b.contrastRatio}:1` : "—";
202
+ const typeLabel = {
203
+ accept: "🟢 Accept",
204
+ reject: "🔴 Reject",
205
+ preferences: "⚙️ Preferences",
206
+ close: "✕ Close",
207
+ unknown: "❓ Unknown",
208
+ }[b.type];
209
+ return `| ${typeLabel} | ${b.text.substring(0, 30)} | ${visible} | ${fontSize} | ${contrast} |`;
210
+ }
211
+ buildIssuesSection(issues) {
212
+ if (issues.length === 0) {
213
+ return "✅ No dark pattern or compliance issue detected.\n";
214
+ }
215
+ const critical = issues.filter((i) => i.severity === "critical");
216
+ const warnings = issues.filter((i) => i.severity === "warning");
217
+ const infos = issues.filter((i) => i.severity === "info");
218
+ const lines = [];
219
+ if (critical.length > 0) {
220
+ lines.push("### ❌ Critical issues\n");
221
+ for (const issue of critical) {
222
+ lines.push(`**${issue.description}**`);
223
+ lines.push(`> ${issue.evidence}\n`);
224
+ }
225
+ }
226
+ if (warnings.length > 0) {
227
+ lines.push("### ⚠️ Warnings\n");
228
+ for (const issue of warnings) {
229
+ lines.push(`**${issue.description}**`);
230
+ lines.push(`> ${issue.evidence}\n`);
231
+ }
232
+ }
233
+ if (infos.length > 0) {
234
+ lines.push("### ℹ️ Information\n");
235
+ for (const issue of infos) {
236
+ lines.push(`- ${issue.description}`);
237
+ }
238
+ }
239
+ return lines.join("\n");
240
+ }
241
+ buildCookiesTable(cookies, phase) {
242
+ const filtered = cookies.filter((c) => c.capturedAt === phase);
243
+ if (filtered.length === 0) {
244
+ return "_No cookies detected._\n";
245
+ }
246
+ const consent = (c) => (c.requiresConsent ? "⚠️ Yes" : "✅ No");
247
+ const expires = (c) => {
248
+ if (c.expires === null)
249
+ return "Session";
250
+ const days = Math.round((c.expires * 1000 - Date.now()) / 86400000);
251
+ if (days < 0)
252
+ return "Expired";
253
+ if (days === 0)
254
+ return "< 1 day";
255
+ if (days < 30)
256
+ return `${days} days`;
257
+ return `${Math.round(days / 30)} months`;
258
+ };
259
+ const rows = filtered.map((c) => `| \`${c.name}\` | ${c.domain} | ${c.category} | ${expires(c)} | ${consent(c)} |`);
260
+ return `| Name | Domain | Category | Expiry | Consent required |
261
+ |------|--------|----------|--------|------------------|
262
+ ${rows.join("\n")}
263
+ `;
264
+ }
265
+ buildCookiesAfterRejectSection(r) {
266
+ const afterReject = r.cookiesAfterReject.filter((c) => c.capturedAt === "after-reject");
267
+ const violating = afterReject.filter((c) => c.requiresConsent);
268
+ const lines = [];
269
+ if (violating.length > 0) {
270
+ lines.push(`❌ **${violating.length} non-essential cookie(s)** detected after rejection:\n`);
271
+ }
272
+ else {
273
+ lines.push("✅ No non-essential cookie detected after rejection.\n");
274
+ }
275
+ lines.push(this.buildCookiesTable(r.cookiesAfterReject, "after-reject"));
276
+ return lines.join("\n");
277
+ }
278
+ buildNetworkSection(r) {
279
+ const allRequests = [
280
+ ...r.networkBeforeInteraction,
281
+ ...r.networkAfterAccept,
282
+ ...r.networkAfterReject,
283
+ ].filter((req) => req.trackerCategory !== null);
284
+ if (allRequests.length === 0) {
285
+ return "_No known network tracker detected._\n";
286
+ }
287
+ const phases = [
288
+ {
289
+ label: "Before interaction",
290
+ requests: r.networkBeforeInteraction.filter((r) => r.trackerCategory !== null),
291
+ },
292
+ {
293
+ label: "After acceptance",
294
+ requests: r.networkAfterAccept.filter((r) => r.trackerCategory !== null),
295
+ },
296
+ {
297
+ label: "After rejection",
298
+ requests: r.networkAfterReject.filter((r) => r.trackerCategory !== null),
299
+ },
300
+ ];
301
+ const lines = [];
302
+ for (const { label, requests } of phases) {
303
+ if (requests.length === 0)
304
+ continue;
305
+ lines.push(`### ${label} (${requests.length} tracker(s))\n`);
306
+ lines.push("| Tracker | Category | URL | Type |");
307
+ lines.push("|---------|-----------|-----|------|");
308
+ for (const req of requests.slice(0, 20)) {
309
+ const url = req.url.length > 60 ? req.url.substring(0, 57) + "..." : req.url;
310
+ lines.push(`| ${req.trackerName ?? "Unknown"} | ${req.trackerCategory} | \`${url}\` | ${req.resourceType} |`);
311
+ }
312
+ if (requests.length > 20) {
313
+ lines.push(`\n_... and ${requests.length - 20} additional request(s)._`);
314
+ }
315
+ lines.push("");
316
+ }
317
+ return lines.join("\n");
318
+ }
319
+ buildRecommendations(r) {
320
+ const recs = [];
321
+ const issues = r.compliance.issues;
322
+ if (!r.modal.detected) {
323
+ recs.push("1. **Deploy a CMP solution** (e.g. Axeptio, Didomi, OneTrust, Cookiebot) that displays a consent modal before any non-essential cookie.");
324
+ }
325
+ if (issues.some((i) => i.type === "pre-ticked")) {
326
+ recs.push("1. **Remove pre-ticked checkboxes.** Consent must result from an explicit positive action (RGPD Recital 32).");
327
+ }
328
+ if (issues.some((i) => i.type === "no-reject-button" || i.type === "buried-reject")) {
329
+ recs.push('1. **Add a "Reject all" button** at the first layer of the modal, requiring no more clicks than "Accept all" (CNIL 2022).');
330
+ }
331
+ if (issues.some((i) => i.type === "click-asymmetry")) {
332
+ recs.push("1. **Balance the number of clicks** to accept and reject. Rejection must not require more steps than acceptance.");
333
+ }
334
+ if (issues.some((i) => i.type === "asymmetric-prominence" || i.type === "nudging")) {
335
+ recs.push("1. **Equalise the styling** of the Accept / Reject buttons: same size, same colour, same level of visibility.");
336
+ }
337
+ if (issues.some((i) => i.type === "auto-consent")) {
338
+ recs.push("1. **Do not set any non-essential cookie before consent.** Gate the initialisation of third-party scripts on acceptance.");
339
+ }
340
+ if (issues.some((i) => i.type === "missing-info")) {
341
+ recs.push("1. **Complete the modal information**: purposes, identity of sub-processors, retention period, right to withdraw.");
342
+ }
343
+ if (r.cookiesAfterReject.filter((c) => c.requiresConsent).length > 0) {
344
+ recs.push("1. **Remove or block non-essential cookies** after rejection, and verify consent handling server-side.");
345
+ }
346
+ if (recs.length === 0) {
347
+ recs.push("✅ No critical recommendation. Conduct regular audits to maintain compliance.");
348
+ }
349
+ return recs.join("\n\n");
350
+ }
351
+ buildChecklist(r) {
352
+ const hostname = new URL(r.url).hostname;
353
+ const scanDate = new Date(r.scanDate).toLocaleString("en-GB");
354
+ const issues = r.compliance.issues;
355
+ const hasIssue = (type) => issues.some((i) => i.type === type);
356
+ const getIssue = (type) => issues.find((i) => i.type === type);
357
+ const ok = "✅ Compliant";
358
+ const ko = "❌ Non-compliant";
359
+ const warn = "⚠️ Warning";
360
+ const rows = [];
361
+ // ── A. Consent presence and validity ─────────────────────────
362
+ rows.push({
363
+ category: "Consent",
364
+ rule: "Consent modal detected",
365
+ reference: "RGPD Art. 7 · Dir. ePrivacy Art. 5(3)",
366
+ status: r.modal.detected ? ok : ko,
367
+ detail: r.modal.detected
368
+ ? `Detected (\`${r.modal.selector}\`)`
369
+ : "No consent banner detected",
370
+ });
371
+ const preTicked = r.modal.checkboxes.filter((c) => c.isCheckedByDefault);
372
+ rows.push({
373
+ category: "Consent",
374
+ rule: "No pre-ticked checkboxes",
375
+ reference: "RGPD Recital 32",
376
+ status: preTicked.length === 0 ? ok : ko,
377
+ detail: preTicked.length === 0
378
+ ? "No pre-ticked checkbox detected"
379
+ : `${preTicked.length} pre-ticked box(es): ${preTicked.map((c) => c.label || c.name).join(", ")}`,
380
+ });
381
+ const misleadingAccept = getIssue("misleading-wording");
382
+ const acceptBtn = r.modal.buttons.find((b) => b.type === "accept");
383
+ rows.push({
384
+ category: "Consent",
385
+ rule: "Accept button label is unambiguous",
386
+ reference: "RGPD Art. 4(11)",
387
+ status: !r.modal.detected || !misleadingAccept
388
+ ? ok
389
+ : misleadingAccept.severity === "critical"
390
+ ? ko
391
+ : warn,
392
+ detail: !r.modal.detected
393
+ ? "Modal not detected"
394
+ : acceptBtn
395
+ ? misleadingAccept
396
+ ? `Ambiguous label: "${acceptBtn.text}"`
397
+ : `Clear label: "${acceptBtn.text}"`
398
+ : "No Accept button detected",
399
+ });
400
+ // ── B. Easy refusal ───────────────────────────────────────────
401
+ const rejectBtn = r.modal.buttons.find((b) => b.type === "reject");
402
+ const noReject = hasIssue("no-reject-button") || hasIssue("buried-reject");
403
+ rows.push({
404
+ category: "Easy refusal",
405
+ rule: "Reject button present at first layer",
406
+ reference: "CNIL Recommendation 2022",
407
+ status: !r.modal.detected ? ko : noReject ? ko : ok,
408
+ detail: !r.modal.detected
409
+ ? "Modal not detected"
410
+ : rejectBtn
411
+ ? `Detected: "${rejectBtn.text}"`
412
+ : "No Reject button at first layer",
413
+ });
414
+ const clickIssue = getIssue("click-asymmetry");
415
+ rows.push({
416
+ category: "Easy refusal",
417
+ rule: "Rejecting requires no more clicks than accepting",
418
+ reference: "CNIL Recommendation 2022",
419
+ status: !r.modal.detected ? ko : clickIssue ? ko : ok,
420
+ detail: !r.modal.detected
421
+ ? "Modal not detected"
422
+ : clickIssue
423
+ ? clickIssue.evidence
424
+ : acceptBtn && rejectBtn
425
+ ? `Accept: ${acceptBtn.clickDepth} click(s) · Reject: ${rejectBtn.clickDepth} click(s)`
426
+ : "Cannot verify (missing buttons)",
427
+ });
428
+ const sizeIssue = getIssue("asymmetric-prominence");
429
+ rows.push({
430
+ category: "Easy refusal",
431
+ rule: "Size symmetry between Accept and Reject",
432
+ reference: "CEPD Guidelines 03/2022",
433
+ status: !r.modal.detected ? ko : sizeIssue ? warn : ok,
434
+ detail: !r.modal.detected
435
+ ? "Modal not detected"
436
+ : sizeIssue
437
+ ? sizeIssue.evidence
438
+ : "Button sizes are comparable",
439
+ });
440
+ const nudgeIssue = getIssue("nudging");
441
+ rows.push({
442
+ category: "Easy refusal",
443
+ rule: "Font symmetry between Accept and Reject",
444
+ reference: "CEPD Guidelines 03/2022",
445
+ status: !r.modal.detected ? ko : nudgeIssue ? warn : ok,
446
+ detail: !r.modal.detected
447
+ ? "Modal not detected"
448
+ : nudgeIssue
449
+ ? nudgeIssue.evidence
450
+ : "Font sizes are comparable",
451
+ });
452
+ // ── C. Transparency ───────────────────────────────────────────
453
+ rows.push({
454
+ category: "Transparency",
455
+ rule: "Granular controls available",
456
+ reference: "CEPD Guidelines 05/2020",
457
+ status: !r.modal.detected ? ko : r.modal.hasGranularControls ? ok : warn,
458
+ detail: !r.modal.detected
459
+ ? "Modal not detected"
460
+ : r.modal.hasGranularControls
461
+ ? `${r.modal.checkboxes.length} checkbox(es) or preferences panel detected`
462
+ : "No granular controls (checkboxes or panel) detected",
463
+ });
464
+ const infoChecks = [
465
+ { key: "purposes", label: "Processing purposes mentioned", ref: "RGPD Art. 13-14" },
466
+ {
467
+ key: "third-parties",
468
+ label: "Sub-processors / third parties mentioned",
469
+ ref: "RGPD Art. 13-14",
470
+ },
471
+ {
472
+ key: "duration",
473
+ label: "Retention period mentioned",
474
+ ref: "RGPD Art. 13(2)(a)",
475
+ },
476
+ {
477
+ key: "withdrawal",
478
+ label: "Right to withdraw consent mentioned",
479
+ ref: "RGPD Art. 7(3)",
480
+ },
481
+ ];
482
+ for (const { key, label, ref } of infoChecks) {
483
+ const missing = issues.find((i) => i.type === "missing-info" && i.description.includes(`"${key}"`));
484
+ rows.push({
485
+ category: "Transparency",
486
+ rule: label,
487
+ reference: ref,
488
+ status: !r.modal.detected ? ko : missing ? warn : ok,
489
+ detail: !r.modal.detected
490
+ ? "Modal not detected"
491
+ : missing
492
+ ? `Information absent from the modal text`
493
+ : "Mention found in the modal text",
494
+ });
495
+ }
496
+ // ── D. Cookie behavior ────────────────────────────────────────
497
+ const illegalPre = r.cookiesBeforeInteraction.filter((c) => c.requiresConsent);
498
+ rows.push({
499
+ category: "Cookie behavior",
500
+ rule: "No non-essential cookie before consent",
501
+ reference: "RGPD Art. 7 · Dir. ePrivacy Art. 5(3)",
502
+ status: illegalPre.length === 0 ? ok : ko,
503
+ detail: illegalPre.length === 0
504
+ ? "No non-essential cookie set before interaction"
505
+ : `${illegalPre.length} illegal cookie(s): ${illegalPre.map((c) => `\`${c.name}\` (${c.category})`).join(", ")}`,
506
+ });
507
+ const persistAfterReject = r.cookiesAfterReject.filter((c) => c.requiresConsent && c.capturedAt === "after-reject");
508
+ rows.push({
509
+ category: "Cookie behavior",
510
+ rule: "Non-essential cookies removed after rejection",
511
+ reference: "RGPD Art. 7 · CNIL Recommendation 2022",
512
+ status: persistAfterReject.length === 0 ? ok : ko,
513
+ detail: persistAfterReject.length === 0
514
+ ? "No non-essential cookie persisting after rejection"
515
+ : `${persistAfterReject.length} cookie(s) persisting: ${persistAfterReject.map((c) => `\`${c.name}\``).join(", ")}`,
516
+ });
517
+ const preTrackers = r.networkBeforeInteraction.filter((req) => req.trackerCategory !== null && req.trackerCategory !== "cdn");
518
+ rows.push({
519
+ category: "Cookie behavior",
520
+ rule: "No network tracker before consent",
521
+ reference: "RGPD Art. 7 · Dir. ePrivacy Art. 5(3)",
522
+ status: preTrackers.length === 0 ? ok : ko,
523
+ detail: preTrackers.length === 0
524
+ ? "No tracker request fired before interaction"
525
+ : `${preTrackers.length} tracker(s): ${[...new Set(preTrackers.map((r) => r.trackerName ?? r.url))].slice(0, 3).join(", ")}`,
526
+ });
527
+ // ── Totals ────────────────────────────────────────────────────
528
+ const conformeCount = rows.filter((r) => r.status === ok).length;
529
+ const nonConformeCount = rows.filter((r) => r.status === ko).length;
530
+ const avertissementCount = rows.filter((r) => r.status === warn).length;
531
+ const lines = [];
532
+ lines.push(`# GDPR Compliance Checklist — ${hostname}`);
533
+ lines.push(`
534
+ > **Scan date:** ${scanDate}
535
+ > **Scanned URL:** ${r.url}
536
+ > **Global score:** ${r.compliance.total}/100 — Grade **${r.compliance.grade}**
537
+ `);
538
+ lines.push(`**${conformeCount} rule(s) compliant** · **${nonConformeCount} non-compliant** · **${avertissementCount} warning(s)**\n`);
539
+ const categories = [...new Set(rows.map((r) => r.category))];
540
+ for (const category of categories) {
541
+ lines.push(`## ${category}\n`);
542
+ lines.push("| Rule | Reference | Status | Detail |");
543
+ lines.push("|------|-----------|--------|--------|");
544
+ for (const row of rows.filter((r) => r.category === category)) {
545
+ lines.push(`| ${row.rule} | ${row.reference} | ${row.status} | ${row.detail} |`);
546
+ }
547
+ lines.push("");
548
+ }
549
+ return lines.join("\n") + "\n";
550
+ }
551
+ }
552
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type Browser, type BrowserContext, type Page } from "playwright";
2
+ import type { ScanOptions } from "../types.js";
3
+ export interface BrowserSession {
4
+ browser: Browser;
5
+ context: BrowserContext;
6
+ page: Page;
7
+ }
8
+ export declare function createBrowser(options: ScanOptions): Promise<BrowserSession>;
9
+ export declare function clearState(context: BrowserContext): Promise<void>;
10
+ export declare function closeBrowser(session: BrowserSession): Promise<void>;
11
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/scanner/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CA+BjF;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvE;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzE"}
@@ -0,0 +1,38 @@
1
+ import { chromium } from "playwright";
2
+ export async function createBrowser(options) {
3
+ const browser = await chromium.launch({
4
+ headless: true,
5
+ args: [
6
+ "--no-sandbox",
7
+ "--disable-setuid-sandbox",
8
+ "--disable-dev-shm-usage",
9
+ "--disable-blink-features=AutomationControlled",
10
+ ],
11
+ });
12
+ const context = await browser.newContext({
13
+ locale: options.locale,
14
+ viewport: { width: 1280, height: 900 },
15
+ userAgent: options.userAgent ??
16
+ [
17
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
18
+ "AppleWebKit/537.36 (KHTML, like Gecko)",
19
+ "Chrome/131.0.0.0 Safari/537.36",
20
+ ].join(" "),
21
+ // Disable existing cookies to get a clean state
22
+ storageState: undefined,
23
+ });
24
+ // Block known resource types that we don't need (speed up)
25
+ await context.route("**/*.{woff,woff2,ttf,eot,ico}", (route) => route.abort());
26
+ const page = await context.newPage();
27
+ return { browser, context, page };
28
+ }
29
+ export async function clearState(context) {
30
+ await context.clearCookies();
31
+ await context.clearPermissions();
32
+ }
33
+ export async function closeBrowser(session) {
34
+ await session.page.close().catch(() => null);
35
+ await session.context.close().catch(() => null);
36
+ await session.browser.close().catch(() => null);
37
+ }
38
+ //# sourceMappingURL=browser.js.map