@slashgear/gdpr-cookie-scanner 2.0.4 → 3.1.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 (53) hide show
  1. package/.github/workflows/update-trackers.yml +95 -0
  2. package/CHANGELOG.md +102 -0
  3. package/CLAUDE.md +1 -1
  4. package/README.md +78 -5
  5. package/dist/analyzers/compliance.d.ts.map +1 -1
  6. package/dist/analyzers/compliance.js +52 -9
  7. package/dist/analyzers/compliance.js.map +1 -1
  8. package/dist/classifiers/cookie-classifier.d.ts.map +1 -1
  9. package/dist/classifiers/cookie-classifier.js +2 -1
  10. package/dist/classifiers/cookie-classifier.js.map +1 -1
  11. package/dist/classifiers/network-classifier.d.ts +1 -0
  12. package/dist/classifiers/network-classifier.d.ts.map +1 -1
  13. package/dist/classifiers/network-classifier.js +10 -1
  14. package/dist/classifiers/network-classifier.js.map +1 -1
  15. package/dist/classifiers/tracker-list.d.ts +1 -0
  16. package/dist/classifiers/tracker-list.d.ts.map +1 -1
  17. package/dist/classifiers/tracker-list.js +7 -1
  18. package/dist/classifiers/tracker-list.js.map +1 -1
  19. package/dist/cli.js +1 -1
  20. package/dist/cli.js.map +1 -1
  21. package/dist/index.d.ts +51 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +46 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/report/generator.d.ts.map +1 -1
  26. package/dist/report/generator.js +82 -41
  27. package/dist/report/generator.js.map +1 -1
  28. package/dist/scanner/index.js +4 -4
  29. package/dist/scanner/index.js.map +1 -1
  30. package/dist/scanner/network.d.ts.map +1 -1
  31. package/dist/scanner/network.js +1 -0
  32. package/dist/scanner/network.js.map +1 -1
  33. package/dist/types.d.ts +2 -1
  34. package/dist/types.d.ts.map +1 -1
  35. package/package.json +11 -2
  36. package/scripts/update-trackers.ts +273 -0
  37. package/src/analyzers/compliance.ts +54 -11
  38. package/src/classifiers/cookie-classifier.ts +2 -1
  39. package/src/classifiers/network-classifier.ts +11 -1
  40. package/src/classifiers/tracker-list.ts +9 -1
  41. package/src/cli.ts +1 -5
  42. package/src/index.ts +87 -0
  43. package/src/report/generator.ts +83 -44
  44. package/src/scanner/index.ts +4 -4
  45. package/src/scanner/network.ts +1 -0
  46. package/src/types.ts +2 -1
  47. package/tests/analyzers/compliance.test.ts +489 -0
  48. package/tests/analyzers/wording.test.ts +160 -0
  49. package/tests/classifiers/cookie-classifier.test.ts +270 -0
  50. package/tests/classifiers/network-classifier.test.ts +140 -0
  51. package/tests/e2e/scanner.test.ts +4 -7
  52. package/tests/unit/compliance.test.ts +99 -13
  53. package/tests/unit/network-classifier.test.ts +27 -0
@@ -0,0 +1,95 @@
1
+ name: Update Tracker DB
2
+
3
+ on:
4
+ schedule:
5
+ # 1st of every month at 04:00 UTC
6
+ - cron: "0 4 1 * *"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ update:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+ pull-requests: write
15
+
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+
19
+ - uses: pnpm/action-setup@v4
20
+ with:
21
+ version: latest
22
+
23
+ - uses: actions/setup-node@v4
24
+ with:
25
+ node-version: 24
26
+ cache: pnpm
27
+
28
+ - name: Install dependencies
29
+ run: pnpm install --frozen-lockfile
30
+
31
+ - name: Fetch & merge tracker lists
32
+ run: pnpm update-trackers
33
+
34
+ - name: Detect changes
35
+ id: diff
36
+ run: |
37
+ git diff --quiet src/classifiers/tracker-list.ts \
38
+ && echo "changed=false" >> "$GITHUB_OUTPUT" \
39
+ || echo "changed=true" >> "$GITHUB_OUTPUT"
40
+
41
+ - name: Format
42
+ if: steps.diff.outputs.changed == 'true'
43
+ run: pnpm format
44
+
45
+ - name: Type-check
46
+ if: steps.diff.outputs.changed == 'true'
47
+ run: pnpm typecheck
48
+
49
+ - name: Create PR
50
+ if: steps.diff.outputs.changed == 'true'
51
+ env:
52
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53
+ run: |
54
+ BRANCH="chore/tracker-db-$(date +%Y%m)"
55
+ DATE="$(date +%Y-%m-%d)"
56
+ SLUG="tracker-db-update-${DATE}"
57
+
58
+ git config user.name "github-actions[bot]"
59
+ git config user.email "github-actions[bot]@users.noreply.github.com"
60
+ git checkout -b "$BRANCH"
61
+
62
+ # Write changeset
63
+ cat > ".changeset/${SLUG}.md" << EOF
64
+ ---
65
+ "@slashgear/gdpr-cookie-scanner": patch
66
+ ---
67
+
68
+ chore: monthly tracker DB update from Disconnect.me and DuckDuckGo Tracker Radar
69
+ EOF
70
+
71
+ git add src/classifiers/tracker-list.ts ".changeset/${SLUG}.md"
72
+ git commit -m "chore: update tracker DB from Disconnect.me and DuckDuckGo Tracker Radar"
73
+ git push origin "$BRANCH"
74
+
75
+ gh pr create \
76
+ --title "chore: monthly tracker DB update ($(date +%B %Y))" \
77
+ --body "$(cat <<'BODY'
78
+ ## Summary
79
+
80
+ Automated monthly update of `src/classifiers/tracker-list.ts`.
81
+
82
+ - **Sources**: [Disconnect.me](https://github.com/disconnectme/disconnect-tracking-protection) · [DuckDuckGo Tracker Radar](https://github.com/duckduckgo/tracker-radar)
83
+ - Manually curated entries and `consentRequired: false` overrides are preserved unchanged.
84
+ - New entries are appended in the `AUTO-GENERATED` section (prevalence ≥ 0.1 %).
85
+
86
+ ## Test plan
87
+
88
+ - [ ] `pnpm typecheck` passes (validated by CI)
89
+ - [ ] Review the diff in `tracker-list.ts` for obviously incorrect category assignments
90
+ - [ ] Spot-check 2–3 new domains against their actual tracker type
91
+
92
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
93
+ BODY
94
+ )" \
95
+ --base main
package/CHANGELOG.md CHANGED
@@ -1,5 +1,107 @@
1
1
  # @slashgear/gdpr-cookie-scanner
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 305c80d: Add programmatic API (`scan()` function and public exports)
8
+
9
+ Exposes a `scan(url, options?)` convenience function and re-exports `Scanner`, `ReportGenerator`, and all public TypeScript types from the package entry point (`dist/index.js`).
10
+
11
+ This allows using the scanner as a library without going through the CLI:
12
+
13
+ ```ts
14
+ import { scan, ReportGenerator } from "@slashgear/gdpr-cookie-scanner";
15
+
16
+ const result = await scan("https://example.com", { locale: "fr-FR" });
17
+ console.log(result.compliance.grade);
18
+
19
+ // Optionally generate a report
20
+ const generator = new ReportGenerator({
21
+ outputDir: "./reports",
22
+ formats: ["html"],
23
+ ...result,
24
+ });
25
+ const paths = await generator.generate(result);
26
+ ```
27
+
28
+ `ScanOptions.outputDir` is now optional: it is only required when screenshots or report generation is needed. `ReportGenerator.generate()` throws a clear error if called without `outputDir`.
29
+
30
+ - cd4d616: feat: add automated tracker DB update script
31
+
32
+ Adds `scripts/update-trackers.ts`, a maintenance script that fetches
33
+ Disconnect.me and DuckDuckGo Tracker Radar and merges new tracker entries
34
+ into `src/classifiers/tracker-list.ts`. Manually curated entries (including
35
+ `consentRequired: false` overrides like Plausible) are preserved as-is; only
36
+ previously unknown domains are appended in a clearly delimited auto-generated
37
+ section.
38
+
39
+ Also adds a monthly GitHub Actions workflow (`.github/workflows/update-trackers.yml`)
40
+ that runs the script automatically and opens a PR when new trackers are found.
41
+
42
+ ### Patch Changes
43
+
44
+ - 578a778: Wire `contrastRatio` into compliance scoring (section B — Easy Refusal).
45
+
46
+ The contrast ratio was already computed and displayed in reports but had no effect on the score. A "Refuser" button rendered in grey on white would silently pass. Now:
47
+
48
+ - Reject button contrast < 3.0 → critical issue, −10 pts
49
+ - Reject button contrast < 4.5 (WCAG AA) → warning, −5 pts
50
+ - Accept contrast ≥ 1.5× reject contrast → relative asymmetry warning, −3 pts
51
+
52
+ - 6113643: Add unit test suite (224 tests) and fix two classifier bugs
53
+
54
+ Introduces a full vitest test suite covering the four pure-function modules:
55
+ `cookie-classifier`, `network-classifier`, `wording` analyzer, and `compliance` analyzer.
56
+
57
+ Two production bugs were discovered and fixed in the process:
58
+
59
+ - **`cookie-classifier`**: the YouTube pattern `^(yt-|VISITOR_INFO|YSC|GPS)$` used a `$` anchor
60
+ that prevented `VISITOR_INFO1_LIVE` (the real cookie name) from matching. Split into two
61
+ entries so `VISITOR_INFO` is matched as a prefix.
62
+ - **`tracker-list`**: the entry `"facebook.com/tr"` included a URL path, making it unmatchable
63
+ by the hostname-only classifier. Replaced with the dedicated `pixel.facebook.com` hostname.
64
+
65
+ ## 3.0.0
66
+
67
+ ### Major Changes
68
+
69
+ - db3e538: Change the default output format from `md,pdf` to `html`.
70
+
71
+ Previously running `gdpr-scan scan <url>` with no `--format` flag produced both a Markdown bundle (3 files) and a PDF — requiring a full Playwright PDF render on every invocation. The HTML report is self-contained, opens in any browser without extra tooling, and is faster to generate, making it a better default for first-time users and CI pipelines alike. Pipelines that relied on the implicit `md` or `pdf` output must now pass `--format md,pdf` explicitly.
72
+
73
+ Also fixes the erroneous `npx` invocation in the README (issue #22): the correct command is `npx @slashgear/gdpr-cookie-scanner scan <url>`, not `npx @slashgear/gdpr-cookie-scanner gdpr-scan scan <url>`.
74
+
75
+ ### Minor Changes
76
+
77
+ - db3e538: Add `requiresConsent` field to `NetworkRequest`, mark Plausible Analytics as consent-exempt, and fix scoring for tracking-free sites.
78
+
79
+ Two related issues are fixed:
80
+
81
+ 1. **Plausible Analytics false positive** — Plausible is cookieless and exempt from ePrivacy consent under CNIL guidance, but requests to `plausible.io/api/event` were matching the generic pixel pattern and penalising the score. A `requiresConsent: boolean` field is added to `NetworkRequest` (mirroring the same field on `ScannedCookie`). A new optional `consentRequired` flag on `TrackerEntry` lets known-exempt services opt out of the default consent requirement. All compliance and report logic now uses `requiresConsent` instead of testing `trackerCategory !== "cdn"` directly. Plausible Analytics is added to `TRACKER_DB` with `consentRequired: false`.
82
+
83
+ 2. **Tracking-free sites capped at 97** — The "no privacy policy link on page" check deducted 3 points unconditionally, even when no consent was required. A site with no non-essential cookies or trackers now correctly scores 100/100.
84
+
85
+ ### Patch Changes
86
+
87
+ - 5f0e14e: Fix false non-compliance for sites with no cookies or trackers
88
+
89
+ A site with no consent modal but also no non-essential cookies and no
90
+ third-party trackers was previously scored 0/75 and graded F, because
91
+ the three consent-related dimensions (consent validity, easy refusal,
92
+ transparency) were zeroed out whenever no modal was detected.
93
+
94
+ GDPR and the ePrivacy Directive only require a consent mechanism when
95
+ the site actually uses cookies or trackers that need consent. A
96
+ tracking-free site has no such obligation and must now correctly receive
97
+ a full score (grade A) and raise no compliance issues.
98
+
99
+ The fix adds a `consentRequired` guard in `analyzeCompliance`: the
100
+ three modal-related dimensions are only penalised when non-essential
101
+ cookies or non-CDN trackers are present. The report generator
102
+ (executive summary, recommendations, checklist) is updated to reflect
103
+ the same distinction. Unit and E2E tests are updated accordingly.
104
+
3
105
  ## 2.0.4
4
106
 
5
107
  ### Patch Changes
package/CLAUDE.md CHANGED
@@ -68,7 +68,7 @@ Phase 3 and 4 require two separate browser sessions so cookie state is fully iso
68
68
  - **`src/classifiers/tracker-list.ts`** — Static database of tracker domains by category
69
69
  - **`src/analyzers/compliance.ts`** — Scores 4 dimensions (0–25 each) and surfaces `DarkPatternIssue` objects: consent validity, easy refusal, transparency, cookie behavior
70
70
  - **`src/analyzers/wording.ts`** — Text analysis of button labels and modal copy
71
- - **`src/report/generator.ts`** — Renders 3 Markdown files from `ScanResult`: the main compliance report (`gdpr-report-*.md`), the checklist (`gdpr-checklist-*.md`), and the cookie inventory (`gdpr-cookies-*.md`); runs `oxfmt` on all generated files
71
+ - **`src/report/generator.ts`** — Renders report files from `ScanResult` in the requested formats. The default output format is HTML. Markdown output produces 3 files: the main compliance report (`gdpr-report-*.md`), the checklist (`gdpr-checklist-*.md`), and the cookie inventory (`gdpr-cookies-*.md`); runs `oxfmt` on all generated Markdown files
72
72
  - **`src/types.ts`** — All shared TypeScript interfaces (`ScanResult`, `ScanOptions`, `ComplianceScore`, `ConsentModal`, etc.)
73
73
 
74
74
  ### Compliance scoring
package/README.md CHANGED
@@ -30,7 +30,7 @@ npx playwright install chromium
30
30
  Or run without installing:
31
31
 
32
32
  ```bash
33
- npx @slashgear/gdpr-cookie-scanner gdpr-scan scan https://example.com
33
+ npx @slashgear/gdpr-cookie-scanner scan https://example.com
34
34
  # Playwright is still required the first time:
35
35
  npx playwright install chromium
36
36
  ```
@@ -61,7 +61,7 @@ gdpr-scan scan <url> [options]
61
61
  | ------------------------ | ---------------- | ------------------------------------------------------------- |
62
62
  | `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
63
63
  | `-t, --timeout <ms>` | `30000` | Navigation timeout |
64
- | `-f, --format <formats>` | `md,pdf` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
64
+ | `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
65
65
  | `--no-screenshots` | — | Disable screenshot capture |
66
66
  | `-l, --locale <locale>` | `fr-FR` | Browser locale |
67
67
  | `-v, --verbose` | — | Show full stack trace on error |
@@ -69,7 +69,7 @@ gdpr-scan scan <url> [options]
69
69
  ### Examples
70
70
 
71
71
  ```bash
72
- # Basic scan
72
+ # Basic scan — produces an HTML report by default
73
73
  gdpr-scan scan https://example.com
74
74
 
75
75
  # With custom output directory
@@ -78,8 +78,8 @@ gdpr-scan scan https://example.com -o ./reports
78
78
  # Scan in English, without screenshots
79
79
  gdpr-scan scan https://example.com --locale en-US --no-screenshots
80
80
 
81
- # Generate only an HTML report
82
- gdpr-scan scan https://example.com -f html
81
+ # Generate a Markdown report instead
82
+ gdpr-scan scan https://example.com -f md
83
83
 
84
84
  # Generate all formats at once
85
85
  gdpr-scan scan https://example.com -f md,html,json,pdf
@@ -88,6 +88,79 @@ gdpr-scan scan https://example.com -f md,html,json,pdf
88
88
  gdpr-scan list-trackers
89
89
  ```
90
90
 
91
+ ## Programmatic API
92
+
93
+ The package can be used as a Node.js library — no CLI required.
94
+
95
+ ```bash
96
+ npm install @slashgear/gdpr-cookie-scanner
97
+ npx playwright install chromium
98
+ ```
99
+
100
+ ### Quick scan
101
+
102
+ ```ts
103
+ import { scan } from "@slashgear/gdpr-cookie-scanner";
104
+
105
+ const result = await scan("https://example.com");
106
+ console.log(result.compliance.grade); // 'A' | 'B' | 'C' | 'D' | 'F'
107
+ console.log(result.compliance.totalScore); // 0–100
108
+ console.log(result.compliance.issues); // DarkPatternIssue[]
109
+ ```
110
+
111
+ All fields of `ScanResult` — cookies, network requests, modal analysis, compliance score — are available in the returned object.
112
+
113
+ ### Options
114
+
115
+ ```ts
116
+ const result = await scan("https://example.com", {
117
+ locale: "fr-FR", // browser locale, also controls report language
118
+ timeout: 60_000, // navigation timeout in ms (default: 30 000)
119
+ screenshots: true, // capture screenshots (requires outputDir)
120
+ outputDir: "./reports", // where to save screenshots
121
+ verbose: false, // log scanner phases to stdout
122
+ });
123
+ ```
124
+
125
+ ### Generating reports
126
+
127
+ Pass the result to `ReportGenerator` to write files in one or more formats:
128
+
129
+ ```ts
130
+ import { scan, ReportGenerator } from "@slashgear/gdpr-cookie-scanner";
131
+
132
+ const result = await scan("https://example.com", { locale: "fr-FR" });
133
+
134
+ const generator = new ReportGenerator({
135
+ url: result.url,
136
+ outputDir: "./reports",
137
+ formats: ["html", "json"], // 'md' | 'html' | 'json' | 'pdf'
138
+ locale: "fr-FR",
139
+ timeout: 30_000,
140
+ screenshots: false,
141
+ verbose: false,
142
+ });
143
+
144
+ const paths = await generator.generate(result);
145
+ console.log(paths.html); // './reports/example.com/gdpr-report-example.com-2024-01-01.html'
146
+ ```
147
+
148
+ ### TypeScript types
149
+
150
+ All interfaces are exported from the package root:
151
+
152
+ ```ts
153
+ import type {
154
+ ScanResult,
155
+ ScanOptions,
156
+ ComplianceScore,
157
+ DarkPatternIssue,
158
+ ScannedCookie,
159
+ NetworkRequest,
160
+ ConsentModal,
161
+ } from "@slashgear/gdpr-cookie-scanner";
162
+ ```
163
+
91
164
  ## How it works
92
165
 
93
166
  ```mermaid
@@ -1 +1 @@
1
- {"version":3,"file":"compliance.d.ts","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAEZ,aAAa,EACb,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,UAAU,eAAe;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,wBAAwB,EAAE,aAAa,EAAE,CAAC;IAC1C,kBAAkB,EAAE,aAAa,EAAE,CAAC;IACpC,kBAAkB,EAAE,aAAa,EAAE,CAAC;IACpC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC3C,kBAAkB,EAAE,cAAc,EAAE,CAAC;IACrC,kBAAkB,EAAE,cAAc,EAAE,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,CAqMzE"}
1
+ {"version":3,"file":"compliance.d.ts","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAEZ,aAAa,EACb,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,UAAU,eAAe;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,wBAAwB,EAAE,aAAa,EAAE,CAAC;IAC1C,kBAAkB,EAAE,aAAa,EAAE,CAAC;IACpC,kBAAkB,EAAE,aAAa,EAAE,CAAC;IACpC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC3C,kBAAkB,EAAE,cAAc,EAAE,CAAC;IACrC,kBAAkB,EAAE,cAAc,EAAE,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,CAgPzE"}
@@ -1,9 +1,19 @@
1
1
  import { analyzeButtonWording, analyzeModalText } from "./wording.js";
2
2
  export function analyzeCompliance(input) {
3
3
  const issues = [];
4
+ // Determine whether a consent mechanism is actually required
5
+ const hasNonEssentialCookies = [
6
+ ...input.cookiesBeforeInteraction,
7
+ ...input.cookiesAfterAccept,
8
+ ].some((c) => c.requiresConsent);
9
+ const hasNonEssentialTrackers = [
10
+ ...input.networkBeforeInteraction,
11
+ ...input.networkAfterAccept,
12
+ ].some((r) => r.requiresConsent);
13
+ const consentRequired = hasNonEssentialCookies || hasNonEssentialTrackers;
4
14
  // ── A. Consent validity (0-25) ────────────────────────────────
5
15
  let consentValidity = 25;
6
- if (!input.modal.detected) {
16
+ if (!input.modal.detected && consentRequired) {
7
17
  issues.push({
8
18
  type: "no-reject-button",
9
19
  severity: "critical",
@@ -12,7 +22,7 @@ export function analyzeCompliance(input) {
12
22
  });
13
23
  consentValidity = 0;
14
24
  }
15
- else {
25
+ else if (input.modal.detected) {
16
26
  // Wording analysis
17
27
  const wordingResult = analyzeButtonWording(input.modal.buttons);
18
28
  const textResult = analyzeModalText(input.modal.text);
@@ -38,10 +48,10 @@ export function analyzeCompliance(input) {
38
48
  }
39
49
  // ── B. Easy refusal (0-25) ────────────────────────────────────
40
50
  let easyRefusal = 25;
41
- if (!input.modal.detected) {
51
+ if (!input.modal.detected && consentRequired) {
42
52
  easyRefusal = 0;
43
53
  }
44
- else {
54
+ else if (input.modal.detected) {
45
55
  const acceptButton = input.modal.buttons.find((b) => b.type === "accept");
46
56
  const rejectButton = input.modal.buttons.find((b) => b.type === "reject");
47
57
  if (!rejectButton) {
@@ -88,13 +98,46 @@ export function analyzeCompliance(input) {
88
98
  easyRefusal -= 5;
89
99
  }
90
100
  }
101
+ // Contrast ratio: reject button must meet minimum legibility
102
+ if (rejectButton && rejectButton.contrastRatio !== null) {
103
+ const ratio = rejectButton.contrastRatio;
104
+ if (ratio < 3.0) {
105
+ issues.push({
106
+ type: "asymmetric-prominence",
107
+ severity: "critical",
108
+ description: "Reject button has critically low contrast ratio",
109
+ evidence: `Contrast ratio ${ratio}:1 — WCAG AA requires 4.5:1 for normal text (${rejectButton.backgroundColor ?? "?"} / ${rejectButton.textColor ?? "?"})`,
110
+ });
111
+ easyRefusal -= 10;
112
+ }
113
+ else if (ratio < 4.5) {
114
+ issues.push({
115
+ type: "asymmetric-prominence",
116
+ severity: "warning",
117
+ description: "Reject button contrast ratio is below WCAG AA threshold",
118
+ evidence: `Contrast ratio ${ratio}:1 — WCAG AA requires 4.5:1 for normal text (${rejectButton.backgroundColor ?? "?"} / ${rejectButton.textColor ?? "?"})`,
119
+ });
120
+ easyRefusal -= 5;
121
+ }
122
+ // Relative contrast asymmetry: accept visually pops, reject is muted
123
+ const acceptContrast = acceptButton?.contrastRatio ?? null;
124
+ if (acceptContrast !== null && acceptContrast >= rejectButton.contrastRatio * 1.5) {
125
+ issues.push({
126
+ type: "asymmetric-prominence",
127
+ severity: "warning",
128
+ description: "Accept button has significantly higher contrast than reject button",
129
+ evidence: `Accept: ${acceptContrast}:1, Reject: ${rejectButton.contrastRatio}:1`,
130
+ });
131
+ easyRefusal -= 3;
132
+ }
133
+ }
91
134
  }
92
135
  // ── C. Transparency (0-25) ────────────────────────────────────
93
136
  let transparency = 25;
94
- if (!input.modal.detected) {
137
+ if (!input.modal.detected && consentRequired) {
95
138
  transparency = 0;
96
139
  }
97
- else {
140
+ else if (input.modal.detected) {
98
141
  if (!input.modal.hasGranularControls) {
99
142
  transparency -= 10;
100
143
  }
@@ -114,8 +157,8 @@ export function analyzeCompliance(input) {
114
157
  transparency -= 5;
115
158
  }
116
159
  }
117
- // No privacy policy link anywhere on the page
118
- if (!input.privacyPolicyUrl) {
160
+ // No privacy policy link anywhere on the page (only relevant when consent is required)
161
+ if (!input.privacyPolicyUrl && consentRequired) {
119
162
  issues.push({
120
163
  type: "missing-info",
121
164
  severity: "warning",
@@ -149,7 +192,7 @@ export function analyzeCompliance(input) {
149
192
  cookieBehavior -= Math.min(15, consentCookiesAfterReject.length * 3);
150
193
  }
151
194
  // Network trackers firing before interaction
152
- const preInteractionTrackers = input.networkBeforeInteraction.filter((r) => r.trackerCategory !== null && r.trackerCategory !== "cdn");
195
+ const preInteractionTrackers = input.networkBeforeInteraction.filter((r) => r.requiresConsent);
153
196
  if (preInteractionTrackers.length > 0) {
154
197
  issues.push({
155
198
  type: "auto-consent",
@@ -1 +1 @@
1
- {"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"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"}
@@ -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;AA0GD,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,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAahG"}
@@ -80,7 +80,8 @@ const COOKIE_PATTERNS = [
80
80
  { pattern: /^_ttp$/i, category: "advertising", requiresConsent: true }, // TikTok
81
81
  // ── Social ─────────────────────────────────────────────────────
82
82
  { pattern: /^(fbsr_|fbm_)/, category: "social", requiresConsent: true }, // Facebook login
83
- { pattern: /^(yt-|VISITOR_INFO|YSC|GPS)$/i, category: "social", requiresConsent: true }, // YouTube
83
+ { pattern: /^(yt-|YSC|GPS)$/i, category: "social", requiresConsent: true }, // YouTube
84
+ { pattern: /^VISITOR_INFO/i, category: "social", requiresConsent: true }, // YouTube VISITOR_INFO1_LIVE etc.
84
85
  // ── Personalization ────────────────────────────────────────────
85
86
  {
86
87
  pattern: /^(ab_|abt_|abtest|experiment|variant|split[-_]test)/i,
@@ -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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"}
@@ -3,6 +3,7 @@ interface NetworkClassification {
3
3
  isThirdParty: boolean;
4
4
  trackerCategory: TrackerCategory | null;
5
5
  trackerName: string | null;
6
+ requiresConsent: boolean;
6
7
  }
7
8
  export declare function classifyNetworkRequest(url: string, resourceType: string): NetworkClassification;
8
9
  export {};
@@ -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;CAC5B;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,qBAAqB,CA2C/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,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,qBAAqB,CAoD/F"}
@@ -5,7 +5,12 @@ export function classifyNetworkRequest(url, resourceType) {
5
5
  hostname = new URL(url).hostname.replace(/^www\./, "");
6
6
  }
7
7
  catch {
8
- return { isThirdParty: false, trackerCategory: null, trackerName: null };
8
+ return {
9
+ isThirdParty: false,
10
+ trackerCategory: null,
11
+ trackerName: null,
12
+ requiresConsent: false,
13
+ };
9
14
  }
10
15
  // Check tracker database (exact match or suffix match)
11
16
  for (const [domain, entry] of Object.entries(TRACKER_DB)) {
@@ -14,6 +19,7 @@ export function classifyNetworkRequest(url, resourceType) {
14
19
  isThirdParty: true,
15
20
  trackerCategory: entry.category,
16
21
  trackerName: entry.name,
22
+ requiresConsent: entry.consentRequired !== false && entry.category !== "cdn",
17
23
  };
18
24
  }
19
25
  }
@@ -23,6 +29,7 @@ export function classifyNetworkRequest(url, resourceType) {
23
29
  isThirdParty: true,
24
30
  trackerCategory: "pixel",
25
31
  trackerName: "Tracking Pixel",
32
+ requiresConsent: true,
26
33
  };
27
34
  }
28
35
  // Resource type heuristics
@@ -31,12 +38,14 @@ export function classifyNetworkRequest(url, resourceType) {
31
38
  isThirdParty: true,
32
39
  trackerCategory: "pixel",
33
40
  trackerName: "Tracking Pixel (image)",
41
+ requiresConsent: true,
34
42
  };
35
43
  }
36
44
  return {
37
45
  isThirdParty: false,
38
46
  trackerCategory: null,
39
47
  trackerName: null,
48
+ requiresConsent: false,
40
49
  };
41
50
  }
42
51
  /**
@@ -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;AAS/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,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC3E,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;aACxB,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;SAC9B,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;SACtC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,IAAI;KAClB,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,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"}
@@ -2,6 +2,7 @@ import type { TrackerCategory } from "../types.js";
2
2
  interface TrackerEntry {
3
3
  name: string;
4
4
  category: TrackerCategory;
5
+ consentRequired?: boolean;
5
6
  }
6
7
  /**
7
8
  * Known tracker domains and their categories.
@@ -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;CAC3B;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAgFnD,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,CAuFnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,EAQlC,CAAC"}
@@ -17,7 +17,7 @@ export const TRACKER_DB = {
17
17
  // ── Meta / Facebook ───────────────────────────────────────────
18
18
  "connect.facebook.net": { name: "Facebook SDK", category: "social" },
19
19
  "graph.facebook.com": { name: "Facebook Graph API", category: "social" },
20
- "facebook.com/tr": { name: "Meta Pixel", category: "advertising" },
20
+ "pixel.facebook.com": { name: "Meta Pixel", category: "advertising" },
21
21
  "fbcdn.net": { name: "Facebook CDN", category: "social" },
22
22
  // ── Microsoft ─────────────────────────────────────────────────
23
23
  "bat.bing.com": { name: "Bing Ads", category: "advertising" },
@@ -70,6 +70,12 @@ 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) ───────
74
+ "plausible.io": {
75
+ name: "Plausible Analytics",
76
+ category: "analytics",
77
+ consentRequired: false,
78
+ },
73
79
  };
74
80
  /**
75
81
  * Patterns for detecting tracking pixels and beacons by URL shape.