@slashgear/gdpr-cookie-scanner 3.2.2 → 3.4.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 (56) hide show
  1. package/.github/workflows/ci.yml +20 -1
  2. package/.github/workflows/release.yml +1 -1
  3. package/CHANGELOG.md +159 -0
  4. package/NEXT_STEPS.md +0 -35
  5. package/README.md +58 -12
  6. package/dist/classifiers/cookie-classifier.d.ts +1 -1
  7. package/dist/classifiers/cookie-classifier.d.ts.map +1 -1
  8. package/dist/classifiers/cookie-classifier.js +3 -2
  9. package/dist/classifiers/cookie-classifier.js.map +1 -1
  10. package/dist/classifiers/network-classifier.d.ts +1 -1
  11. package/dist/classifiers/network-classifier.d.ts.map +1 -1
  12. package/dist/classifiers/network-classifier.js +5 -3
  13. package/dist/classifiers/network-classifier.js.map +1 -1
  14. package/dist/classifiers/tracker-list.d.ts.map +1 -1
  15. package/dist/classifiers/tracker-list.js +29 -1
  16. package/dist/classifiers/tracker-list.js.map +1 -1
  17. package/dist/cli.js +37 -4
  18. package/dist/cli.js.map +1 -1
  19. package/dist/index.d.ts +9 -3
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/scanner/browser.d.ts.map +1 -1
  24. package/dist/scanner/browser.js +17 -7
  25. package/dist/scanner/browser.js.map +1 -1
  26. package/dist/scanner/consent-modal.d.ts +14 -1
  27. package/dist/scanner/consent-modal.d.ts.map +1 -1
  28. package/dist/scanner/consent-modal.js +148 -32
  29. package/dist/scanner/consent-modal.js.map +1 -1
  30. package/dist/scanner/cookies.d.ts +1 -1
  31. package/dist/scanner/cookies.d.ts.map +1 -1
  32. package/dist/scanner/cookies.js +2 -2
  33. package/dist/scanner/cookies.js.map +1 -1
  34. package/dist/scanner/index.d.ts.map +1 -1
  35. package/dist/scanner/index.js +17 -8
  36. package/dist/scanner/index.js.map +1 -1
  37. package/dist/scanner/network.d.ts +1 -1
  38. package/dist/scanner/network.d.ts.map +1 -1
  39. package/dist/scanner/network.js +2 -2
  40. package/dist/scanner/network.js.map +1 -1
  41. package/dist/types.d.ts +7 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/classifiers/cookie-classifier.ts +8 -2
  45. package/src/classifiers/network-classifier.ts +9 -3
  46. package/src/classifiers/tracker-list.ts +29 -1
  47. package/src/cli.ts +60 -5
  48. package/src/index.ts +11 -2
  49. package/src/scanner/browser.ts +23 -9
  50. package/src/scanner/consent-modal.ts +169 -32
  51. package/src/scanner/cookies.ts +2 -1
  52. package/src/scanner/index.ts +41 -8
  53. package/src/scanner/network.ts +2 -2
  54. package/src/types.ts +8 -0
  55. package/tests/scanner/button-classification.test.ts +241 -0
  56. package/tests/scanner/contrast-ratio.test.ts +172 -0
@@ -43,4 +43,23 @@ jobs:
43
43
  run: pnpm exec playwright install chromium --with-deps
44
44
 
45
45
  - name: Test
46
- run: pnpm test
46
+ id: test
47
+ run: |
48
+ start=$(date +%s)
49
+ pnpm test
50
+ echo "duration=$(( $(date +%s) - start ))" >> "$GITHUB_OUTPUT"
51
+
52
+ - name: Record test suite duration
53
+ if: always()
54
+ run: |
55
+ duration="${{ steps.test.outputs.duration }}"
56
+ echo "## Test suite duration" >> "$GITHUB_STEP_SUMMARY"
57
+ echo "" >> "$GITHUB_STEP_SUMMARY"
58
+ echo "| Suite | Duration |" >> "$GITHUB_STEP_SUMMARY"
59
+ echo "| ----- | -------- |" >> "$GITHUB_STEP_SUMMARY"
60
+ echo "| unit + e2e | ${duration}s |" >> "$GITHUB_STEP_SUMMARY"
61
+ if [ "${duration:-0}" -gt 300 ]; then
62
+ echo "" >> "$GITHUB_STEP_SUMMARY"
63
+ echo "> [!WARNING]" >> "$GITHUB_STEP_SUMMARY"
64
+ echo "> Suite exceeded 300 s — possible performance regression." >> "$GITHUB_STEP_SUMMARY"
65
+ fi
@@ -21,7 +21,7 @@ jobs:
21
21
 
22
22
  - uses: actions/setup-node@v4
23
23
  with:
24
- node-version: 22
24
+ node-version: 24
25
25
  cache: pnpm
26
26
  registry-url: https://registry.npmjs.org
27
27
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,164 @@
1
1
  # @slashgear/gdpr-cookie-scanner
2
2
 
3
+ ## 3.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 39794dc: Crop consent modal screenshot to the element; make after-reject/accept screenshots opt-in.
8
+
9
+ Two behaviour changes:
10
+
11
+ **Modal screenshot is now always captured (cropped)**
12
+ The consent modal screenshot (`modal-initial.png`) is taken whenever a modal
13
+ is detected and `outputDir` is set, regardless of the `--screenshots` flag.
14
+ The screenshot is clipped to the bounding box of the modal element instead of
15
+ capturing the full viewport, giving a tighter, more readable image. If the
16
+ bounding box cannot be determined (rare), it falls back to the viewport
17
+ screenshot.
18
+
19
+ **`--no-screenshots` replaced by `--screenshots`**
20
+ Previously all three screenshots were enabled by default and `--no-screenshots`
21
+ opted out. Now only the modal screenshot is taken by default; passing
22
+ `--screenshots` additionally captures `after-reject.png` and `after-accept.png`
23
+ (full viewport, as before). The `screenshots` field in `ScanOptions` / the
24
+ programmatic API retains the same type (`boolean`) with updated semantics:
25
+ `false` (default) = modal only; `true` = modal + after-reject + after-accept.
26
+
27
+ - 6a71a18: Add multi-language consent button detection (de, es, it, nl, pl, pt).
28
+
29
+ Previously, button classification only covered French and English, causing
30
+ false "no reject button" findings on sites served in other EU locales.
31
+
32
+ The fix has two parts:
33
+
34
+ 1. **Locale-aware pattern map** — `ACCEPT_PATTERNS` / `REJECT_PATTERNS` /
35
+ `PREFERENCES_PATTERNS` are replaced by a `PATTERNS_BY_LOCALE` map keyed by
36
+ BCP 47 primary subtag, covering `en`, `fr`, `de`, `es`, `it`, `nl`, `pl`,
37
+ `pt`. Polish patterns use a negative lookbehind instead of `\b` because
38
+ several Polish words end in non-ASCII characters (ć, ę, ó) that fall
39
+ outside JS `\w`.
40
+
41
+ 2. **`<html lang>` detection** — `detectConsentModal` now reads the page's
42
+ declared language from `document.documentElement.lang` and normalises it to
43
+ a primary subtag (e.g. `"de-DE"` → `"de"`). When the language is
44
+ recognised, only that locale's patterns plus English (universal fallback)
45
+ are tested. When the language is missing or unsupported, all available
46
+ patterns are tried — preserving the previous behaviour for unknown pages.
47
+
48
+ The public export `classifyButtonText(text, lang)` is added for testing and
49
+ programmatic use; 56 new unit tests cover every supported locale.
50
+
51
+ ### Patch Changes
52
+
53
+ - ceed240: Add unit tests for `computeContrastRatio`, `parseRgb`, and `relativeLuminance`.
54
+
55
+ These three pure functions in `consent-modal.ts` were previously only exercised
56
+ indirectly through the E2E suite. The new test file
57
+ (`tests/scanner/contrast-ratio.test.ts`) covers the happy path, edge cases
58
+ (identical colours, fully transparent rgba, non-integer ratios), and documents
59
+ the known limitations — named colours (`white`, `black`) and hex values (`#fff`)
60
+ return `null` until the parser is extended.
61
+
62
+ The functions are now exported so they can be imported by the test suite without
63
+ moving them to a separate module.
64
+
65
+ - df24a36: Fix consent modal detection for CMPs that start hidden (e.g. Axeptio).
66
+
67
+ `MODAL_SELECTORS` was a single flat list where every candidate was required to
68
+ pass `isVisible()`. CMPs such as Axeptio inject their overlay as `display:none`
69
+ during initialisation and reveal it via JS animation a few hundred milliseconds
70
+ later. The visibility check caused the scanner to skip `#axeptio_overlay` and
71
+ fall through to the first matching generic heuristic (e.g. `[id*='consent']`),
72
+ which could be a completely unrelated element.
73
+
74
+ The list is now split into two:
75
+
76
+ - **`CMP_SELECTORS`** — precise, platform-specific identifiers. DOM presence
77
+ alone is treated as a reliable signal. Once the element is found the scanner
78
+ waits up to 3 s for it to become visible (so button extraction sees an
79
+ interactive state) but proceeds regardless, preventing a slow CMP from
80
+ silently falling back to a wrong heuristic.
81
+ - **`HEURISTIC_SELECTORS`** — broad patterns that could match unrelated
82
+ elements. Visibility is still required to avoid false positives.
83
+
84
+ - f9efe0b: Normalise button text whitespace before classification.
85
+
86
+ `classifyButtonType` previously received raw `textContent` that had only been
87
+ `.trim()`-ed. CMP HTML templates frequently embed `&nbsp;` (U+00A0), newlines,
88
+ or tabs inside button labels, causing pattern matching to silently fail.
89
+
90
+ A `normalizeText` helper now collapses any whitespace sequence (including
91
+ U+00A0 and all Unicode spaces covered by JS `\s`) into a single ASCII space
92
+ before the regex is tested. The normalisation is applied in two places:
93
+
94
+ - `classifyButtonText` (public export) — defensive normalisation of any caller-
95
+ provided string.
96
+ - `extractButtons` — the raw `el.textContent()` result is normalised before
97
+ being stored in `ConsentButton.text` and before classification, so the
98
+ report also shows the cleaned label.
99
+
100
+ ## 3.3.0
101
+
102
+ ### Minor Changes
103
+
104
+ - 7c128b9: Add `--json-summary` flag to emit a machine-readable JSON line on stdout after the scan.
105
+
106
+ CI pipelines that use `--fail-on` previously had to parse the full report file to extract
107
+ score, grade, and issue details programmatically. With `--json-summary`, a single JSON line
108
+ is written to stdout at the end of every scan (pass or fail), containing the URL, score,
109
+ grade, pass/fail status, threshold, score breakdown, and issue list.
110
+
111
+ ```bash
112
+ gdpr-scan scan https://example.com --fail-on B --json-summary \
113
+ | grep '^{' | jq '{grade: .grade, passed: .passed}'
114
+ ```
115
+
116
+ - faa6da8: Add `--strict` flag: treat unrecognised cookies and unknown third-party requests as requiring consent.
117
+
118
+ By default, cookies and network requests that do not match any known pattern are assumed
119
+ to be first-party and consent-free (conservative). This avoids false positives but lets
120
+ obfuscated or emerging tracking cookies slip through undetected.
121
+
122
+ With `--strict`, the classifier falls back to `requiresConsent: true` for anything
123
+ unrecognised, making the scan more aggressive. Use this when auditing sites where you
124
+ suspect custom tracking solutions not yet in the pattern database.
125
+
126
+ CLI: `gdpr-scan scan https://example.com --strict`
127
+
128
+ Programmatic API: `await scan(url, { strict: true })`
129
+
130
+ - df30f31: Add `--viewport` option to scan with desktop, tablet, or mobile browser dimensions.
131
+
132
+ All scans previously used a fixed 1280×900 desktop viewport. Many consent banners
133
+ have different layouts on mobile (bottom sheets, full-screen overlays) that can only
134
+ be tested with the correct viewport and user-agent.
135
+
136
+ Three presets are available:
137
+
138
+ | Preset | Dimensions | User-agent |
139
+ | --------- | ---------- | ---------------- |
140
+ | `desktop` | 1280×900 | Chrome on macOS |
141
+ | `tablet` | 768×1024 | Safari on iPad |
142
+ | `mobile` | 390×844 | Safari on iPhone |
143
+
144
+ CLI: `gdpr-scan scan https://example.com --viewport mobile`
145
+
146
+ Programmatic API: `await scan(url, { viewport: 'mobile' })`
147
+
148
+ Default is `desktop` — no change to existing behaviour.
149
+
150
+ ### Patch Changes
151
+
152
+ - 6eb4c3d: Add Fathom, Simple Analytics, Cabin, and Pirsch to the consent-exempt analytics list.
153
+
154
+ These tools are cookieless, collect no personal data, and do not cross-reference data
155
+ with other processing — meeting the CNIL conditions for analytics exempt from the
156
+ ePrivacy consent requirement. Only Plausible was previously listed; sites using any
157
+ of these four tools were incorrectly flagged as loading trackers before consent.
158
+
159
+ Domains added: `cdn.usefathom.com`, `scripts.simpleanalyticscdn.com`,
160
+ `api.simpleanalytics.io`, `scripts.withcabin.com`, `api.pirsch.io`.
161
+
3
162
  ## 3.2.2
4
163
 
5
164
  ### Patch Changes
package/NEXT_STEPS.md CHANGED
@@ -14,25 +14,6 @@ Ideas and improvement areas for `gdpr-cookie-scanner`. Not a roadmap — pick wh
14
14
 
15
15
  ---
16
16
 
17
- ## Language support
18
-
19
- Currently only French and English patterns are covered. A lot of EU sites served in other locales will get false "no reject button" results.
20
-
21
- Languages to add at minimum (ordered by EU population / GDPR enforcement activity):
22
-
23
- | Locale | Reject examples | Accept examples |
24
- | ------- | ------------------------ | -------------------------------- |
25
- | `de-DE` | Ablehnen, Alle ablehnen | Alle akzeptieren, Zustimmen |
26
- | `es-ES` | Rechazar, Rechazar todo | Aceptar, Aceptar todo |
27
- | `it-IT` | Rifiuta, Rifiuta tutto | Accetta, Accetta tutto |
28
- | `nl-NL` | Weigeren, Alles weigeren | Accepteren, Alles accepteren |
29
- | `pl-PL` | Odrzuć, Odrzuć wszystkie | Zaakceptuj, Zaakceptuj wszystkie |
30
- | `pt-PT` | Rejeitar, Rejeitar tudo | Aceitar, Aceitar tudo |
31
-
32
- The patterns live in `src/scanner/consent-modal.ts`. A locale-aware pattern map keyed by BCP 47 tag would be cleaner than one giant regex.
33
-
34
- ---
35
-
36
17
  ## Dark pattern detection gaps
37
18
 
38
19
  Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected:
@@ -53,8 +34,6 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
53
34
 
54
35
  - **Configurable wait times** — the `waitForTimeout(2000)` / `waitForTimeout(3000)` values in `scanner/index.ts` are hardcoded. Some pages need more time (heavy SPAs); others waste time. Expose them as `ScanOptions` fields with sensible defaults.
55
36
 
56
- - **Mobile viewport** — all scans use a 1280×900 desktop viewport. Many consent banners have different layouts on mobile (bottom sheets, full-screen overlays). A `--viewport mobile|tablet|desktop` option would let users test the responsive behaviour.
57
-
58
37
  - **Multi-page scanning** — run the scan across several URLs of the same domain (home page + one inner page) and merge results. Useful for detecting banners that only appear on the first visit, or trackers that fire on specific pages.
59
38
 
60
39
  - **Batch mode** — accept a list of URLs (file or `--url` repeated) and produce a summary report alongside individual reports. Useful for agencies auditing multiple client sites.
@@ -67,10 +46,6 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
67
46
 
68
47
  - **Tracker database size** — the hardcoded list (`src/classifiers/tracker-list.ts`) currently has ~55 entries. The monthly auto-update workflow merges Disconnect.me and DuckDuckGo Tracker Radar entries but the result needs review before merge. Consider auto-approving updates that only add entries (no removals or category changes).
69
48
 
70
- - **Cookieless analytics exemptions** — only Plausible is marked `consentRequired: false`. Fathom, Simple Analytics, Cabin, and Pirsch have the same privacy-by-design model and should be listed.
71
-
72
- - **Unknown first-party cookies default** — unknown cookies default to `requiresConsent: false` (conservative). This means new or obfuscated tracking cookies slip through. Consider a stricter mode (`--strict`) that flips the default to `requiresConsent: true` for unrecognised cookies.
73
-
74
49
  ---
75
50
 
76
51
  ## Report improvements
@@ -81,24 +56,14 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
81
56
 
82
57
  - **Historical comparison** — if a previous JSON report for the same hostname exists in the output directory, surface a diff (score delta, issues resolved/introduced). Useful for tracking progress over time.
83
58
 
84
- - **Structured exit summary** — when `--fail-on` causes an exit 1, emit a machine-readable summary to stdout (JSON lines) so CI systems can parse it without reading the full report file.
85
-
86
59
  ---
87
60
 
88
61
  ## Testing
89
62
 
90
63
  - **Report output tests** — no tests currently validate the content of generated Markdown, HTML, or JSON files. Add snapshot tests for at least the JSON output and spot-checks for key sections in HTML.
91
64
 
92
- - **Contrast ratio unit tests** — `computeContrastRatio` is pure logic but only exercised through E2E tests. Deserves a dedicated unit test file covering edge cases (identical colours, transparent backgrounds, named/hex inputs once supported).
93
-
94
- - **Locale-specific button pattern tests** — once multi-language patterns land, add a test case per locale to prevent regressions.
95
-
96
- - **Performance baseline** — the E2E suite takes ~2 minutes. As features grow, tracking suite duration in CI would help catch regressions early.
97
-
98
65
  ---
99
66
 
100
67
  ## Infrastructure
101
68
 
102
- - **Node version consistency** — CI runs Node 24 but the release workflow runs Node 22. Align to a single version across all workflows.
103
-
104
69
  - **Pre-built GitHub Action** — a dedicated `uses: slashgear/gdpr-cookie-scanner-action@v1` action would make the GitHub Actions integration one step instead of running the Docker container manually. The action wrapper would handle artifact upload and PR comments automatically.
package/README.md CHANGED
@@ -63,15 +63,18 @@ gdpr-scan scan <url> [options]
63
63
 
64
64
  ### Options
65
65
 
66
- | Option | Default | Description |
67
- | ------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------ |
68
- | `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
69
- | `-t, --timeout <ms>` | `30000` | Navigation timeout |
70
- | `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
71
- | `--fail-on <threshold>` | `F` | Exit with code 1 if grade is below this letter (`A`/`B`/`C`/`D`/`F`) or score is below this number (`0–100`) |
72
- | `--no-screenshots` | | Disable screenshot capture |
73
- | `-l, --locale <locale>` | `fr-FR` | Browser locale |
74
- | `-v, --verbose` | — | Show full stack trace on error |
66
+ | Option | Default | Description |
67
+ | ------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
68
+ | `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
69
+ | `-t, --timeout <ms>` | `30000` | Navigation timeout |
70
+ | `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
71
+ | `--viewport <preset>` | `desktop` | Viewport preset: `desktop` (1280×900), `tablet` (768×1024), `mobile` (390×844) |
72
+ | `--fail-on <threshold>` | `F` | Exit with code 1 if grade is below this letter (`A`/`B`/`C`/`D`/`F`) or score is below this number (`0–100`) |
73
+ | `--json-summary` | | Emit a machine-readable JSON line to stdout after the scan (parseable by `jq`) |
74
+ | `--strict` | — | Treat unrecognised cookies and unknown third-party requests as requiring consent |
75
+ | `--screenshots` | — | Also capture full-page screenshots after reject and accept interactions (the consent modal is always screenshotted when detected) |
76
+ | `-l, --locale <locale>` | `fr-FR` | Browser locale |
77
+ | `-v, --verbose` | — | Show full stack trace on error |
75
78
 
76
79
  ### Examples
77
80
 
@@ -82,8 +85,8 @@ gdpr-scan scan https://example.com
82
85
  # With custom output directory
83
86
  gdpr-scan scan https://example.com -o ./reports
84
87
 
85
- # Scan in English, without screenshots
86
- gdpr-scan scan https://example.com --locale en-US --no-screenshots
88
+ # Scan in English with full interaction screenshots (reject + accept)
89
+ gdpr-scan scan https://example.com --locale en-US --screenshots
87
90
 
88
91
  # Generate a Markdown report instead
89
92
  gdpr-scan scan https://example.com -f md
@@ -91,6 +94,12 @@ gdpr-scan scan https://example.com -f md
91
94
  # Generate all formats at once
92
95
  gdpr-scan scan https://example.com -f md,html,json,pdf
93
96
 
97
+ # Scan with a mobile viewport (390×844, iPhone UA)
98
+ gdpr-scan scan https://example.com --viewport mobile
99
+
100
+ # Scan with a tablet viewport (768×1024, iPad UA)
101
+ gdpr-scan scan https://example.com --viewport tablet
102
+
94
103
  # Fail (exit 1) if the site is graded below B — useful in CI
95
104
  gdpr-scan scan https://example.com --fail-on B
96
105
 
@@ -159,6 +168,42 @@ gdpr-scan:
159
168
  - if: $CI_PIPELINE_SOURCE == "web"
160
169
  ```
161
170
 
171
+ ### Machine-readable output
172
+
173
+ Add `--json-summary` to get a single JSON line on stdout after the scan — useful when
174
+ you need to parse results in a script or post them to a webhook without reading the full
175
+ report file.
176
+
177
+ ```bash
178
+ gdpr-scan scan https://example.com --fail-on B --json-summary 2>/dev/null \
179
+ | grep '^{' | jq '{grade: .grade, score: .score, passed: .passed}'
180
+ ```
181
+
182
+ The JSON line is always emitted (pass or fail) and contains:
183
+
184
+ ```jsonc
185
+ {
186
+ "url": "https://example.com",
187
+ "scanDate": "2026-01-01T00:00:00.000Z",
188
+ "score": 62,
189
+ "grade": "C",
190
+ "passed": false,
191
+ "threshold": "B",
192
+ "breakdown": {
193
+ "consentValidity": 20,
194
+ "easyRefusal": 12,
195
+ "transparency": 15,
196
+ "cookieBehavior": 15,
197
+ },
198
+ "issues": {
199
+ "total": 4,
200
+ "critical": 2,
201
+ "items": [{ "type": "buried-reject", "severity": "critical", "description": "..." }],
202
+ },
203
+ "reportPaths": { "html": "./gdpr-reports/example.com/gdpr-report-example.com-2026-01-01.html" },
204
+ }
205
+ ```
206
+
162
207
  ### Threshold reference
163
208
 
164
209
  | `--fail-on` value | Fails when grade is… | Fails when score is… |
@@ -198,9 +243,10 @@ All fields of `ScanResult` — cookies, network requests, modal analysis, compli
198
243
  const result = await scan("https://example.com", {
199
244
  locale: "fr-FR", // browser locale, also controls report language
200
245
  timeout: 60_000, // navigation timeout in ms (default: 30 000)
201
- screenshots: true, // capture screenshots (requires outputDir)
246
+ screenshots: true, // also capture after-reject and after-accept screenshots (modal is always screenshotted)
202
247
  outputDir: "./reports", // where to save screenshots
203
248
  verbose: false, // log scanner phases to stdout
249
+ viewport: "mobile", // 'desktop' (default) | 'tablet' | 'mobile'
204
250
  });
205
251
  ```
206
252
 
@@ -3,6 +3,6 @@ interface CookieClassification {
3
3
  category: CookieCategory;
4
4
  requiresConsent: boolean;
5
5
  }
6
- export declare function classifyCookie(name: string, domain: string, value: string): CookieClassification;
6
+ export declare function classifyCookie(name: string, domain: string, value: string, strict?: boolean): CookieClassification;
7
7
  export {};
8
8
  //# sourceMappingURL=cookie-classifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-classifier.d.ts","sourceRoot":"","sources":["../../src/classifiers/cookie-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AA2GD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAahG"}
1
+ {"version":3,"file":"cookie-classifier.d.ts","sourceRoot":"","sources":["../../src/classifiers/cookie-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AA2GD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,UAAQ,GACb,oBAAoB,CActB"}
@@ -94,7 +94,7 @@ const COOKIE_PATTERNS = [
94
94
  requiresConsent: true,
95
95
  },
96
96
  ];
97
- export function classifyCookie(name, domain, value) {
97
+ export function classifyCookie(name, domain, value, strict = false) {
98
98
  for (const { pattern, category, requiresConsent } of COOKIE_PATTERNS) {
99
99
  if (pattern.test(name)) {
100
100
  return { category, requiresConsent };
@@ -104,6 +104,7 @@ export function classifyCookie(name, domain, value) {
104
104
  if (name.length <= 4 && !value.includes("=")) {
105
105
  return { category: "unknown", requiresConsent: true };
106
106
  }
107
- return { category: "unknown", requiresConsent: false };
107
+ // In strict mode, unrecognised cookies are assumed to require consent
108
+ return { category: "unknown", requiresConsent: strict };
108
109
  }
109
110
  //# sourceMappingURL=cookie-classifier.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-classifier.js","sourceRoot":"","sources":["../../src/classifiers/cookie-classifier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cookie-classifier.js","sourceRoot":"","sources":["../../src/classifiers/cookie-classifier.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,6 @@ interface NetworkClassification {
5
5
  trackerName: string | null;
6
6
  requiresConsent: boolean;
7
7
  }
8
- export declare function classifyNetworkRequest(url: string, resourceType: string): NetworkClassification;
8
+ export declare function classifyNetworkRequest(url: string, resourceType: string, strict?: boolean): NetworkClassification;
9
9
  export {};
10
10
  //# sourceMappingURL=network-classifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network-classifier.d.ts","sourceRoot":"","sources":["../../src/classifiers/network-classifier.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,qBAAqB,CAoD/F"}
1
+ {"version":3,"file":"network-classifier.d.ts","sourceRoot":"","sources":["../../src/classifiers/network-classifier.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,MAAM,UAAQ,GACb,qBAAqB,CAsDvB"}
@@ -1,5 +1,5 @@
1
1
  import { TRACKER_DB, PIXEL_PATTERNS } from "./tracker-list.js";
2
- export function classifyNetworkRequest(url, resourceType) {
2
+ export function classifyNetworkRequest(url, resourceType, strict = false) {
3
3
  let hostname;
4
4
  try {
5
5
  hostname = new URL(url).hostname.replace(/^www\./, "");
@@ -41,11 +41,13 @@ export function classifyNetworkRequest(url, resourceType) {
41
41
  requiresConsent: true,
42
42
  };
43
43
  }
44
+ // In strict mode, unrecognised third-party requests are assumed to require consent
45
+ const isThirdParty = strict;
44
46
  return {
45
- isThirdParty: false,
47
+ isThirdParty,
46
48
  trackerCategory: null,
47
49
  trackerName: null,
48
- requiresConsent: false,
50
+ requiresConsent: strict,
49
51
  };
50
52
  }
51
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"network-classifier.js","sourceRoot":"","sources":["../../src/classifiers/network-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAU/D,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,YAAoB;IACtE,IAAI,QAAgB,CAAC;IAErB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,WAAW,EAAE,IAAI;YACjB,eAAe,EAAE,KAAK;SACvB,CAAC;IACJ,CAAC;IAED,uDAAuD;IACvD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACzD,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC;YAC3D,OAAO;gBACL,YAAY,EAAE,IAAI;gBAClB,eAAe,EAAE,KAAK,CAAC,QAAQ;gBAC/B,WAAW,EAAE,KAAK,CAAC,IAAI;gBACvB,eAAe,EAAE,KAAK,CAAC,eAAe,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK;aAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC5C,OAAO;YACL,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,OAAO;YACxB,WAAW,EAAE,gBAAgB;YAC7B,eAAe,EAAE,IAAI;SACtB,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,IAAI,YAAY,KAAK,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO;YACL,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,OAAO;YACxB,WAAW,EAAE,wBAAwB;YACrC,eAAe,EAAE,IAAI;SACtB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,IAAI;QACjB,eAAe,EAAE,KAAK;KACvB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC5B,OAAO,CACL,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;QACf,4CAA4C,CAAC,IAAI,CAAC,GAAG,CAAC,CACvD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"network-classifier.js","sourceRoot":"","sources":["../../src/classifiers/network-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAU/D,MAAM,UAAU,sBAAsB,CACpC,GAAW,EACX,YAAoB,EACpB,MAAM,GAAG,KAAK;IAEd,IAAI,QAAgB,CAAC;IAErB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,WAAW,EAAE,IAAI;YACjB,eAAe,EAAE,KAAK;SACvB,CAAC;IACJ,CAAC;IAED,uDAAuD;IACvD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACzD,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC;YAC3D,OAAO;gBACL,YAAY,EAAE,IAAI;gBAClB,eAAe,EAAE,KAAK,CAAC,QAAQ;gBAC/B,WAAW,EAAE,KAAK,CAAC,IAAI;gBACvB,eAAe,EAAE,KAAK,CAAC,eAAe,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK;aAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC5C,OAAO;YACL,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,OAAO;YACxB,WAAW,EAAE,gBAAgB;YAC7B,eAAe,EAAE,IAAI;SACtB,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,IAAI,YAAY,KAAK,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO;YACL,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,OAAO;YACxB,WAAW,EAAE,wBAAwB;YACrC,eAAe,EAAE,IAAI;SACtB,CAAC;IACJ,CAAC;IAED,mFAAmF;IACnF,MAAM,YAAY,GAAG,MAAM,CAAC;IAC5B,OAAO;QACL,YAAY;QACZ,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,IAAI;QACjB,eAAe,EAAE,MAAM;KACxB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC5B,OAAO,CACL,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;QACf,4CAA4C,CAAC,IAAI,CAAC,GAAG,CAAC,CACvD,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracker-list.d.ts","sourceRoot":"","sources":["../../src/classifiers/tracker-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAuFnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,EAQlC,CAAC"}
1
+ {"version":3,"file":"tracker-list.d.ts","sourceRoot":"","sources":["../../src/classifiers/tracker-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAmHnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,EAQlC,CAAC"}
@@ -70,12 +70,40 @@ export const TRACKER_DB = {
70
70
  "optimizely.com": { name: "Optimizely", category: "analytics" },
71
71
  "vwo.com": { name: "VWO", category: "analytics" },
72
72
  "app.convert.com": { name: "Convert", category: "analytics" },
73
- // ── Consent-exempt analytics (CNIL ePrivacy exemption) ───────
73
+ // ── Consent-exempt analytics ──────────────────────────────────
74
+ // These tools are cookieless, collect no personal data, and do not
75
+ // cross-reference with other processing — meeting the CNIL conditions
76
+ // for analytics tools exempt from the ePrivacy consent requirement.
74
77
  "plausible.io": {
75
78
  name: "Plausible Analytics",
76
79
  category: "analytics",
77
80
  consentRequired: false,
78
81
  },
82
+ "cdn.usefathom.com": {
83
+ name: "Fathom Analytics",
84
+ category: "analytics",
85
+ consentRequired: false,
86
+ },
87
+ "scripts.simpleanalyticscdn.com": {
88
+ name: "Simple Analytics",
89
+ category: "analytics",
90
+ consentRequired: false,
91
+ },
92
+ "api.simpleanalytics.io": {
93
+ name: "Simple Analytics",
94
+ category: "analytics",
95
+ consentRequired: false,
96
+ },
97
+ "scripts.withcabin.com": {
98
+ name: "Cabin Analytics",
99
+ category: "analytics",
100
+ consentRequired: false,
101
+ },
102
+ "api.pirsch.io": {
103
+ name: "Pirsch Analytics",
104
+ category: "analytics",
105
+ consentRequired: false,
106
+ },
79
107
  };
80
108
  /**
81
109
  * Patterns for detecting tracking pixels and beacons by URL shape.
@@ -1 +1 @@
1
- {"version":3,"file":"tracker-list.js","sourceRoot":"","sources":["../../src/classifiers/tracker-list.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tracker-list.js","sourceRoot":"","sources":["../../src/classifiers/tracker-list.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -16,11 +16,14 @@ program
16
16
  .argument("<url>", "URL of the website to scan")
17
17
  .option("-o, --output <dir>", "Output directory for the report", "./gdpr-reports")
18
18
  .option("-t, --timeout <ms>", "Navigation timeout in milliseconds", "30000")
19
- .option("--no-screenshots", "Disable screenshot capture")
19
+ .option("--screenshots", "Capture full-page screenshots after reject and accept interactions (the consent modal is always screenshotted when detected)")
20
20
  .option("-l, --locale <locale>", "Browser locale for language detection", "fr-FR")
21
21
  .option("-v, --verbose", "Show detailed output", false)
22
22
  .option("-f, --format <formats>", "Output formats: md, html, json, pdf (comma-separated)", "html")
23
+ .option("--viewport <preset>", "Viewport preset: desktop (1280×900), tablet (768×1024), mobile (390×844)", "desktop")
23
24
  .option("--fail-on <threshold>", "Exit with code 1 if grade is below this letter (A/B/C/D/F) or score is below this number", "F")
25
+ .option("--json-summary", "Emit a JSON summary line to stdout after the scan (machine-readable)", false)
26
+ .option("--strict", "Treat unrecognised cookies and unknown third-party requests as requiring consent", false)
24
27
  .action(async (url, opts) => {
25
28
  console.log();
26
29
  console.log(styleText(["bold", "blue"], " GDPR Cookie Scanner"));
@@ -28,8 +31,15 @@ program
28
31
  const normalizedUrl = normalizeUrl(url);
29
32
  const hostname = new URL(normalizedUrl).hostname;
30
33
  const outputDir = join(resolve(opts.output), hostname);
31
- console.log(styleText("gray", ` Target : ${url}`));
32
- console.log(styleText("gray", ` Output : ${outputDir}`));
34
+ const validViewports = new Set(["desktop", "tablet", "mobile"]);
35
+ const viewport = opts.viewport.toLowerCase();
36
+ if (!validViewports.has(viewport)) {
37
+ console.error(styleText("red", " Invalid --viewport value. Valid options: desktop, tablet, mobile"));
38
+ process.exit(2);
39
+ }
40
+ console.log(styleText("gray", ` Target : ${url}`));
41
+ console.log(styleText("gray", ` Output : ${outputDir}`));
42
+ console.log(styleText("gray", ` Viewport : ${viewport}`));
33
43
  console.log();
34
44
  const validFormats = new Set(["md", "html", "json", "pdf"]);
35
45
  const formats = opts.format
@@ -44,10 +54,12 @@ program
44
54
  url: normalizedUrl,
45
55
  outputDir,
46
56
  timeout: parseInt(opts.timeout, 10),
47
- screenshots: opts.screenshots !== false,
57
+ screenshots: Boolean(opts.screenshots),
48
58
  locale: opts.locale,
49
59
  verbose: opts.verbose,
50
60
  formats,
61
+ viewport: viewport,
62
+ strict: opts.strict,
51
63
  };
52
64
  const spinner = createSpinner("Launching browser...").start();
53
65
  try {
@@ -89,6 +101,27 @@ program
89
101
  console.log(styleText("red", ` Failed threshold: score ${result.compliance.total}/100 (grade ${result.compliance.grade}) is below --fail-on ${threshold.toUpperCase()}`));
90
102
  console.log();
91
103
  }
104
+ if (opts.jsonSummary) {
105
+ process.stdout.write(JSON.stringify({
106
+ url: result.url,
107
+ scanDate: result.scanDate,
108
+ score: result.compliance.total,
109
+ grade: result.compliance.grade,
110
+ passed: !failed,
111
+ threshold: threshold.toUpperCase(),
112
+ breakdown: result.compliance.breakdown,
113
+ issues: {
114
+ total: result.compliance.issues.length,
115
+ critical: result.compliance.issues.filter((i) => i.severity === "critical").length,
116
+ items: result.compliance.issues.map((i) => ({
117
+ type: i.type,
118
+ severity: i.severity,
119
+ description: i.description,
120
+ })),
121
+ },
122
+ reportPaths: paths,
123
+ }) + "\n");
124
+ }
92
125
  process.exit(failed ? 1 : 0);
93
126
  }
94
127
  catch (err) {