@slashgear/gdpr-cookie-scanner 3.6.0 → 3.8.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 (149) hide show
  1. package/.dockerignore +3 -0
  2. package/.gitattributes +1 -0
  3. package/.github/workflows/website.yml +80 -0
  4. package/CHANGELOG.md +52 -0
  5. package/CLAUDE.md +12 -1
  6. package/CONTRIBUTING.md +32 -4
  7. package/NEXT_STEPS.md +37 -3
  8. package/README.md +23 -0
  9. package/dist/analyzers/colour.d.ts +36 -0
  10. package/dist/analyzers/colour.d.ts.map +1 -0
  11. package/dist/analyzers/colour.js +75 -0
  12. package/dist/analyzers/colour.js.map +1 -0
  13. package/dist/analyzers/compliance.d.ts.map +1 -1
  14. package/dist/analyzers/compliance.js +24 -6
  15. package/dist/analyzers/compliance.js.map +1 -1
  16. package/dist/analyzers/tcf-decoder.d.ts +9 -0
  17. package/dist/analyzers/tcf-decoder.d.ts.map +1 -0
  18. package/dist/analyzers/tcf-decoder.js +123 -0
  19. package/dist/analyzers/tcf-decoder.js.map +1 -0
  20. package/dist/analyzers/wording.d.ts +1 -0
  21. package/dist/analyzers/wording.d.ts.map +1 -1
  22. package/dist/analyzers/wording.js +39 -0
  23. package/dist/analyzers/wording.js.map +1 -1
  24. package/dist/report/generator.d.ts +1 -0
  25. package/dist/report/generator.d.ts.map +1 -1
  26. package/dist/report/generator.js +71 -1
  27. package/dist/report/generator.js.map +1 -1
  28. package/dist/report/html.d.ts.map +1 -1
  29. package/dist/report/html.js +123 -0
  30. package/dist/report/html.js.map +1 -1
  31. package/dist/scanner/consent-modal.d.ts.map +1 -1
  32. package/dist/scanner/consent-modal.js +4 -2
  33. package/dist/scanner/consent-modal.js.map +1 -1
  34. package/dist/scanner/index.d.ts.map +1 -1
  35. package/dist/scanner/index.js +4 -0
  36. package/dist/scanner/index.js.map +1 -1
  37. package/dist/scanner/tcf.d.ts +9 -0
  38. package/dist/scanner/tcf.d.ts.map +1 -0
  39. package/dist/scanner/tcf.js +72 -0
  40. package/dist/scanner/tcf.js.map +1 -0
  41. package/dist/types.d.ts +26 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +7 -3
  44. package/pnpm-workspace.yaml +3 -0
  45. package/scripts/build-showcase.mjs +113 -0
  46. package/src/analyzers/colour.ts +89 -0
  47. package/src/analyzers/compliance.ts +35 -10
  48. package/src/analyzers/tcf-decoder.ts +130 -0
  49. package/src/analyzers/wording.ts +44 -0
  50. package/src/report/generator.ts +83 -1
  51. package/src/report/html.ts +146 -0
  52. package/src/scanner/consent-modal.ts +3 -1
  53. package/src/scanner/index.ts +5 -0
  54. package/src/scanner/tcf.ts +80 -0
  55. package/src/types.ts +29 -0
  56. package/tests/analyzers/colour.test.ts +187 -0
  57. package/tests/analyzers/compliance.test.ts +102 -0
  58. package/tests/analyzers/tcf-decoder.test.ts +292 -0
  59. package/tests/analyzers/wording.test.ts +38 -0
  60. package/tests/scanner/button-classification.test.ts +32 -0
  61. package/website/Dockerfile +55 -0
  62. package/website/node_modules/.bin/oxfmt +21 -0
  63. package/website/node_modules/.bin/oxlint +21 -0
  64. package/website/node_modules/.bin/tsc +21 -0
  65. package/website/node_modules/.bin/tsserver +21 -0
  66. package/website/node_modules/.bin/tsx +21 -0
  67. package/website/package.json +29 -0
  68. package/{docs → website/public}/index.html +88 -50
  69. package/website/public/reports/www.20minutes.fr/after-accept.png +3 -0
  70. package/website/public/reports/www.20minutes.fr/after-reject.png +3 -0
  71. package/website/public/reports/www.20minutes.fr/gdpr-report-20minutes.fr-2026-02-22.html +907 -0
  72. package/website/public/reports/www.20minutes.fr/modal-initial.png +3 -0
  73. package/website/public/reports/www.arte.tv/after-accept.png +3 -0
  74. package/website/public/reports/www.arte.tv/after-reject.png +3 -0
  75. package/website/public/reports/www.arte.tv/gdpr-report-arte.tv-2026-02-24.html +998 -0
  76. package/website/public/reports/www.arte.tv/modal-initial.png +3 -0
  77. package/website/public/reports/www.backmarket.fr/after-accept.png +3 -0
  78. package/website/public/reports/www.backmarket.fr/after-reject.png +3 -0
  79. package/website/public/reports/www.backmarket.fr/gdpr-report-backmarket.fr-2026-02-24.html +1530 -0
  80. package/website/public/reports/www.backmarket.fr/modal-initial.png +3 -0
  81. package/website/public/reports/www.deezer.com/after-accept.png +3 -0
  82. package/website/public/reports/www.deezer.com/after-reject.png +3 -0
  83. package/website/public/reports/www.deezer.com/gdpr-report-deezer.com-2026-02-22.html +1668 -0
  84. package/website/public/reports/www.deezer.com/modal-initial.png +3 -0
  85. package/website/public/reports/www.france.tv/after-accept.png +3 -0
  86. package/website/public/reports/www.france.tv/after-reject.png +3 -0
  87. package/website/public/reports/www.france.tv/gdpr-report-france.tv-2026-02-23.html +977 -0
  88. package/website/public/reports/www.france.tv/modal-initial.png +3 -0
  89. package/website/public/reports/www.m6.fr/after-accept.png +3 -0
  90. package/website/public/reports/www.m6.fr/after-reject.png +3 -0
  91. package/website/public/reports/www.m6.fr/gdpr-report-m6.fr-2026-02-28.html +1862 -0
  92. package/website/public/reports/www.m6.fr/modal-initial.png +3 -0
  93. package/website/public/reports/www.netflix.com/after-accept.png +3 -0
  94. package/website/public/reports/www.netflix.com/after-reject.png +3 -0
  95. package/website/public/reports/www.netflix.com/gdpr-report-netflix.com-2026-02-23.html +1051 -0
  96. package/website/public/reports/www.netflix.com/modal-initial.png +3 -0
  97. package/website/public/reports/www.radiofrance.fr/after-accept.png +3 -0
  98. package/website/public/reports/www.radiofrance.fr/after-reject.png +3 -0
  99. package/website/public/reports/www.radiofrance.fr/gdpr-report-radiofrance.fr-2026-02-24.html +1146 -0
  100. package/website/public/reports/www.radiofrance.fr/modal-initial.png +3 -0
  101. package/website/public/reports/www.tf1.fr/after-accept.png +3 -0
  102. package/website/public/reports/www.tf1.fr/after-reject.png +3 -0
  103. package/website/public/reports/www.tf1.fr/gdpr-report-tf1.fr-2026-02-23.html +1512 -0
  104. package/website/public/reports/www.tf1.fr/modal-initial.png +3 -0
  105. package/website/src/index.ts +15 -0
  106. package/website/src/security.ts +26 -0
  107. package/website/tsconfig.json +14 -0
  108. package/.github/workflows/pages.yml +0 -40
  109. package/docs/reports/github.com/after-accept.png +0 -0
  110. package/docs/reports/github.com/after-reject.png +0 -0
  111. package/docs/reports/github.com/gdpr-checklist-github.com-2026-02-22.md +0 -44
  112. package/docs/reports/github.com/gdpr-cookies-github.com-2026-02-22.md +0 -29
  113. package/docs/reports/github.com/gdpr-report-github.com-2026-02-22.md +0 -102
  114. package/docs/reports/github.com/gdpr-report-github.com-2026-02-22.pdf +0 -0
  115. package/docs/reports/gitlab.com/after-accept.png +0 -0
  116. package/docs/reports/gitlab.com/after-reject.png +0 -0
  117. package/docs/reports/gitlab.com/gdpr-checklist-gitlab.com-2026-02-22.md +0 -44
  118. package/docs/reports/gitlab.com/gdpr-cookies-gitlab.com-2026-02-22.md +0 -55
  119. package/docs/reports/gitlab.com/gdpr-report-gitlab.com-2026-02-22.md +0 -200
  120. package/docs/reports/gitlab.com/gdpr-report-gitlab.com-2026-02-22.pdf +0 -0
  121. package/docs/reports/gitlab.com/modal-initial.png +0 -0
  122. package/docs/reports/npmjs.com/after-accept.png +0 -0
  123. package/docs/reports/npmjs.com/after-reject.png +0 -0
  124. package/docs/reports/npmjs.com/gdpr-checklist-npmjs.com-2026-02-22.md +0 -44
  125. package/docs/reports/npmjs.com/gdpr-cookies-npmjs.com-2026-02-22.md +0 -25
  126. package/docs/reports/npmjs.com/gdpr-report-npmjs.com-2026-02-22.md +0 -88
  127. package/docs/reports/npmjs.com/gdpr-report-npmjs.com-2026-02-22.pdf +0 -0
  128. package/docs/reports/reddit.com/after-accept.png +0 -0
  129. package/docs/reports/reddit.com/after-reject.png +0 -0
  130. package/docs/reports/reddit.com/gdpr-checklist-reddit.com-2026-02-22.md +0 -44
  131. package/docs/reports/reddit.com/gdpr-cookies-reddit.com-2026-02-22.md +0 -33
  132. package/docs/reports/reddit.com/gdpr-report-reddit.com-2026-02-22.md +0 -148
  133. package/docs/reports/reddit.com/gdpr-report-reddit.com-2026-02-22.pdf +0 -0
  134. package/docs/reports/reddit.com/modal-initial.png +0 -0
  135. package/docs/reports/stackoverflow.com/after-accept.png +0 -0
  136. package/docs/reports/stackoverflow.com/after-reject.png +0 -0
  137. package/docs/reports/stackoverflow.com/gdpr-checklist-stackoverflow.com-2026-02-22.md +0 -44
  138. package/docs/reports/stackoverflow.com/gdpr-cookies-stackoverflow.com-2026-02-22.md +0 -67
  139. package/docs/reports/stackoverflow.com/gdpr-report-stackoverflow.com-2026-02-22.md +0 -206
  140. package/docs/reports/stackoverflow.com/gdpr-report-stackoverflow.com-2026-02-22.pdf +0 -0
  141. package/docs/reports/stackoverflow.com/modal-initial.png +0 -0
  142. package/docs/reports/www.afp.com/after-accept.png +0 -0
  143. package/docs/reports/www.afp.com/after-reject.png +0 -0
  144. package/docs/reports/www.afp.com/gdpr-checklist-afp.com-2026-02-22.md +0 -44
  145. package/docs/reports/www.afp.com/gdpr-cookies-afp.com-2026-02-22.md +0 -42
  146. package/docs/reports/www.afp.com/gdpr-report-afp.com-2026-02-22.md +0 -202
  147. package/docs/reports/www.afp.com/gdpr-report-afp.com-2026-02-22.pdf +0 -0
  148. package/docs/reports/www.afp.com/modal-initial.png +0 -0
  149. /package/{docs → website/public}/style.css +0 -0
package/.dockerignore CHANGED
@@ -7,6 +7,9 @@ dist/
7
7
  reports/
8
8
  gdpr-reports/
9
9
  tests/
10
+ docs/
11
+ website/node_modules/
12
+ website/dist/
10
13
  *.md
11
14
  *.log
12
15
  .DS_Store
package/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ website/public/reports/**/*.png filter=lfs diff=lfs merge=lfs -text
@@ -0,0 +1,80 @@
1
+ name: Website
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "website/**"
8
+ - "pnpm-workspace.yaml"
9
+ - ".github/workflows/website.yml"
10
+
11
+ env:
12
+ SCW_DEFAULT_REGION: fr-par
13
+
14
+ jobs:
15
+ build-and-push:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ contents: read
19
+ packages: write
20
+
21
+ outputs:
22
+ image: ${{ steps.meta.outputs.image }}
23
+
24
+ steps:
25
+ - uses: actions/checkout@v6
26
+ with:
27
+ lfs: true
28
+
29
+ - name: Log in to GitHub Container Registry
30
+ uses: docker/login-action@v3
31
+ with:
32
+ registry: ghcr.io
33
+ username: ${{ github.actor }}
34
+ password: ${{ secrets.GITHUB_TOKEN }}
35
+
36
+ - name: Set up QEMU
37
+ uses: docker/setup-qemu-action@v3
38
+
39
+ - name: Set up Docker Buildx
40
+ uses: docker/setup-buildx-action@v3
41
+
42
+ - name: Compute image name
43
+ id: meta
44
+ run: |
45
+ echo "image=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')-website" >> "$GITHUB_OUTPUT"
46
+
47
+ - name: Build and push
48
+ uses: docker/build-push-action@v6
49
+ with:
50
+ context: .
51
+ file: website/Dockerfile
52
+ push: true
53
+ platforms: linux/amd64,linux/arm64
54
+ tags: |
55
+ ${{ steps.meta.outputs.image }}:latest
56
+ ${{ steps.meta.outputs.image }}:${{ github.sha }}
57
+ cache-from: type=gha
58
+ cache-to: type=gha,mode=max
59
+
60
+ deploy:
61
+ needs: build-and-push
62
+ runs-on: ubuntu-latest
63
+ environment: production
64
+
65
+ steps:
66
+ - name: Install Scaleway CLI
67
+ run: |
68
+ curl -fsSL https://raw.githubusercontent.com/scaleway/scaleway-cli/master/scripts/get.sh | sh
69
+
70
+ - name: Deploy to Scaleway Serverless Container
71
+ run: |
72
+ scw container container update ${{ secrets.SCW_CONTAINER_ID }} \
73
+ registry-image=${{ needs.build-and-push.outputs.image }}:${{ github.sha }} \
74
+ region=${{ env.SCW_DEFAULT_REGION }} \
75
+ redeploy=true
76
+ env:
77
+ SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY }}
78
+ SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY }}
79
+ SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID }}
80
+ SCW_DEFAULT_PROJECT_ID: ${{ secrets.SCW_PROJECT_ID }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @slashgear/gdpr-cookie-scanner
2
2
 
3
+ ## 3.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 88d944f: Introduce pnpm workspace monorepo and `website` package.
8
+
9
+ Converts the repo to a pnpm workspace and adds a new private `website` package (`@slashgear/gdpr-website`) built with Hono on Node.js. The package exposes a Docker image (`ghcr.io/slashgear/gdpr-website`) intended for deployment as a Scaleway Serverless Container at `gdpr.slashgear.dev`. A dedicated GitHub Actions workflow (`website.yml`) builds and pushes the image on every push to `main` that touches `website/**`, then redeploys the container via the Scaleway CLI.
10
+
11
+ ## 3.7.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 439a24d: feat: detect colour nudging dark pattern (green accept + grey/red reject)
16
+
17
+ Using a "positive" colour (green) on the accept button while the reject button
18
+ is visually de-emphasised (grey or red) is a documented dark pattern per
19
+ EDPB Guidelines 03/2022 § 3.3.3. The easyRefusal score now deducts 5 points
20
+ and surfaces a `nudging` warning when this pattern is detected.
21
+
22
+ A new `src/analyzers/colour.ts` module implements RGB→HSL conversion, perceptual
23
+ hue classification (green / red / grey / blue / neutral), and the nudging check.
24
+ 32 unit tests cover the colour math and the compliance integration.
25
+
26
+ ### Patch Changes
27
+
28
+ - ee162de: fix: classify reject before accept to handle "continuer sans accepter" dark pattern
29
+
30
+ Buttons like "Continuer sans accepter" or "Continue without accepting" contain the
31
+ word "accept/accepter" and were being incorrectly classified as accept buttons because
32
+ accept patterns were tested first. Swapping the check order (reject → accept) ensures
33
+ these rejection-phrased labels are correctly identified, preventing false negatives on
34
+ a very common dark pattern used by French and other European sites.
35
+
36
+ - 00c926b: fix: deduct points for indirect reject button labels in easyRefusal score
37
+
38
+ Buttons like "Continuer sans accepter" or "Continue without accepting" are technically
39
+ reject buttons but use indirect wording that makes the refusal non-obvious to users.
40
+ This is a dark pattern covered by EDPB Guidelines 03/2022 (§ 3.3.3 — hiding choices).
41
+
42
+ The easyRefusal score now deducts 5 points when such indirect wording is detected,
43
+ and a warning issue is surfaced in the report alongside the existing detection logic.
44
+
45
+ - 9f69e31: feat: add IAB TCF detection and consent string decoding
46
+
47
+ The scanner now detects TCF (Transparency & Consent Framework) implementations on scanned pages.
48
+ It checks for the `__tcfapi` JavaScript API, the `__tcfapiLocator` iframe, and `euconsent-v2`/`euconsent` cookies.
49
+ When a consent string is found, it is decoded (TCF v1 and v2 core segments) to extract CMP identity,
50
+ declared purposes, legitimate interests, and special features opt-ins.
51
+
52
+ This data is purely informational and does not affect the compliance score.
53
+ It appears as a new section in both the HTML and Markdown reports.
54
+
3
55
  ## 3.6.0
4
56
 
5
57
  ### Minor Changes
package/CLAUDE.md CHANGED
@@ -19,7 +19,18 @@ node dist/cli.js scan <url> -o ./reports --locale fr-FR --verbose
19
19
  node dist/cli.js list-trackers
20
20
  ```
21
21
 
22
- There are no tests currently.
22
+ ## Tests
23
+
24
+ Use [Vitest](https://vitest.dev/) for unit tests. Test files live in `tests/` and mirror the source structure (`tests/analyzers/`, `tests/classifiers/`, `tests/scanner/`, `tests/unit/`).
25
+
26
+ ```bash
27
+ pnpm test # run all tests
28
+ pnpm test:watch # watch mode
29
+ ```
30
+
31
+ **When to write tests:** every new feature or bug fix must include tests. Pure functions (decoders, classifiers, analyzers) are the primary targets. Browser-dependent code (scanner phases) is not unit-tested.
32
+
33
+ **When to update the README:** every new user-facing feature must be documented in `README.md` — CLI flags, output formats, new report sections, etc.
23
34
 
24
35
  ## Commit checklist
25
36
 
package/CONTRIBUTING.md CHANGED
@@ -2,20 +2,32 @@
2
2
 
3
3
  ## Prerequisites
4
4
 
5
- - Node.js ≥ 20
5
+ - Node.js ≥ 24
6
6
  - pnpm
7
- - Playwright: `npx playwright install chromium`
7
+ - Playwright: `pnpm exec playwright install chromium`
8
+
9
+ ## Repository structure
10
+
11
+ This is a **pnpm workspace monorepo** with two packages:
12
+
13
+ | Package | Path | Description |
14
+ | -------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
15
+ | `@slashgear/gdpr-cookie-scanner` | `/` (root) | Published CLI tool |
16
+ | `@slashgear/gdpr-website` | `website/` | Hono web app — not published, deployed as a Docker image to [gdpr.slashgear.dev](https://gdpr.slashgear.dev) |
8
17
 
9
18
  ## Getting started
10
19
 
11
20
  ```bash
12
21
  git clone https://github.com/Slashgear/gdpr-report.git
13
22
  cd gdpr-report
14
- pnpm install
15
- pnpm build
23
+ pnpm install # installs all workspace packages
24
+ pnpm build # builds the CLI
16
25
 
17
26
  # Run the CLI locally
18
27
  node dist/cli.js scan https://example.com
28
+
29
+ # Run the website locally (http://localhost:8080)
30
+ pnpm website:dev
19
31
  ```
20
32
 
21
33
  ## Workflow
@@ -28,6 +40,7 @@ node dist/cli.js scan https://example.com
28
40
  pnpm lint
29
41
  pnpm typecheck
30
42
  pnpm build
43
+ pnpm website:typecheck
31
44
  ```
32
45
  4. Open a Pull Request targeting `main`
33
46
 
@@ -37,6 +50,21 @@ node dist/cli.js scan https://example.com
37
50
  - **Consent modal detection** — improve CMP detection in `src/scanner/consent-modal.ts`
38
51
  - **Compliance rules** — refine scoring rules in `src/analyzers/compliance.ts`
39
52
  - **Report** — improve report rendering in `src/report/generator.ts`
53
+ - **Website** — Hono server and landing page in `website/src/` and `website/public/`
54
+
55
+ ## Website — live reports showcase
56
+
57
+ The `website/public/reports/` directory contains pre-generated HTML reports (grades A–D only).
58
+ After adding new reports, run:
59
+
60
+ ```bash
61
+ pnpm build:showcase # regenerates the report cards in website/public/index.html
62
+ ```
63
+
64
+ The script reads `website/public/reports/` and injects sorted report cards between the
65
+ `<!-- ── REPORTS_START ── -->` / `<!-- ── REPORTS_END ── -->` markers.
66
+
67
+ Report screenshots (`.png`) are tracked via **Git LFS** — make sure `git lfs` is installed before cloning.
40
68
 
41
69
  ## Releasing
42
70
 
package/NEXT_STEPS.md CHANGED
@@ -20,13 +20,15 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
20
20
 
21
21
  - **Cookie wall** — detect when the page content is blurred, hidden, or inaccessible before consent is given. Requires comparing DOM structure / visible content area before and after interaction.
22
22
 
23
- - **Colour nudging** — accept button in green / reject button in grey or red is a documented dark pattern. Detect hue of each button's background colour and flag when accept is visually "positive" and reject is "negative".
23
+ - **Colour nudging** — accept button in green / reject button in grey or red is a documented dark pattern. Detect hue of each button's background colour and flag when accept is visually "positive" (green hue) and reject is "negative" (grey or red hue). Deduct from `easyRefusal`.
24
24
 
25
25
  - **Scroll- or navigation-as-consent** — some sites display a banner and treat scrolling as acceptance. Would require simulating a scroll event and checking whether the banner disappears without an explicit click.
26
26
 
27
27
  - **Bundled opt-outs** — some CMPs only provide "reject analytics + marketing" as a single checkbox rather than granular controls. Could be inferred from `hasGranularControls` combined with a single reject-all path.
28
28
 
29
- - **Consent fatigue / re-prompting** — detecting a banner reappearing on the next page load after rejection is hard without multi-page scanning, but worth exploring.
29
+ - **Legitimate interest abuse** — sites often declare legitimate interest for purposes 2–10 (advertising, profiling), bypassing consent entirely. When TCF is detected, flag when `purposesLegitimateInterest` includes ad-related IAB purposes (2, 3, 4, 7, 8, 9, 10).
30
+
31
+ - **Consent fatigue / re-prompting** — detect if the consent banner reappears on page reload after rejection. Requires a 5th scan phase: reload after reject and check for modal re-appearance.
30
32
 
31
33
  ---
32
34
 
@@ -40,6 +42,8 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
40
42
 
41
43
  - **Firefox / WebKit** — Playwright supports both. Firefox in particular is relevant because some CMPs behave differently across engines. A `--browser chromium|firefox|webkit` flag would be low-effort to wire up.
42
44
 
45
+ - **Screenshot capture** — capture a screenshot of the consent modal at detection time and embed it in the HTML report as visual evidence. Useful for audit trails and regulatory submissions.
46
+
43
47
  ---
44
48
 
45
49
  ## Tracker & cookie classification
@@ -50,12 +54,42 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
50
54
 
51
55
  ## Report improvements
52
56
 
53
- - **Single-file Markdown** — the current 3-file split (report + checklist + inventory) is logical but awkward to share or attach in a ticket. An optional `--merge-md` flag that concatenates the three files would help.
57
+ - **JSON output format** — export the full `ScanResult` as a `gdpr-report-*.json` file. Enables programmatic consumption in CI pipelines, dashboards, and historical comparisons without parsing Markdown or HTML.
58
+
59
+ - **CMP fingerprinting** — identify which CMP is in use (OneTrust, Didomi, Axeptio, Cookiebot, TrustArc, Usercentrics…) from script URLs, global objects (`window.Didomi`, `window.OneTrust`…), or CSS class names. Enrich the report and correlate compliance scores with specific vendors.
54
60
 
55
61
  - **Report localisation** — recommendations and section headings are hardcoded in French even when `--locale en-US` is used. The report language should follow `--locale`.
56
62
 
57
63
  - **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.
58
64
 
65
+ - **TCF consent string cross-check** — after rejection, re-read the TCF consent string and verify `purposesConsent` is empty. Currently we capture the string before interaction only; a mismatch between the declared rejection and a non-empty consent string would be a critical finding.
66
+
67
+ ---
68
+
69
+ ## Website (`docs/`)
70
+
71
+ The site is served as GitHub Pages from the `docs/` directory. Reports and cards are maintained manually.
72
+
73
+ - **HTML reports on the site** — generate `.html` reports into `docs/reports/<host>/` and point the "Live Reports" cards directly at the GitHub Pages URL instead of GitHub's Markdown renderer. Visitors stay on the site and get the full styled report experience.
74
+
75
+ - **Per-report `<title>` and `<meta description>`** — each HTML report should carry a specific page title (`"github.com — Grade F (15/100) | gdpr-cookie-scanner"`) and a meta description summarising the scan result. Currently the generator uses a generic title.
76
+
77
+ - **Open Graph / Twitter Card tags** — add `og:title`, `og:description`, `og:url` (and ideally `og:image` with a grade badge) to each report page so social shares display a meaningful preview card.
78
+
79
+ - **`sitemap.xml`** — auto-generated file listing the home page + every report page. Critical for search engine discovery of individual report pages. Can be a simple script that reads `docs/reports/` and writes the XML.
80
+
81
+ - **JSON-LD structured data** — `SoftwareApplication` schema on the home page; a `Dataset` or `Article` schema on each report page with `name`, `url`, `datePublished`, and a custom `score` property. Enables Google rich snippets.
82
+
83
+ - **`robots.txt`** — confirm (or add) a `robots.txt` that allows full crawling of `docs/` including report sub-directories.
84
+
85
+ - **Screenshots in the HTML report** — `after-reject.png` and `after-accept.png` are already captured alongside each report. Embedding them in the HTML report as visual evidence would make reports significantly more compelling.
86
+
87
+ - **Fix outdated copy** — the "What it checks" feature card still says "3 Markdown reports". Update to reflect the current single-file output and the HTML format.
88
+
89
+ - **"Submit a site" workflow** — a GitHub Issues template that lets users request a scan. A workflow picks it up, runs the scanner, commits the HTML report to `docs/reports/`, and posts a link back in the issue.
90
+
91
+ - **Dark mode** — `style.css` has no `@media (prefers-color-scheme: dark)` support. The design is simple enough that adding a dark palette would be straightforward.
92
+
59
93
  ---
60
94
 
61
95
  ## Testing
package/README.md CHANGED
@@ -317,9 +317,32 @@ All formats contain:
317
317
  - Detected dark patterns (missing reject button, visual asymmetry, pre-ticked boxes, misleading wording…)
318
318
  - Cookie table before interaction, after reject, after accept
319
319
  - Network tracker requests by phase
320
+ - **IAB TCF detection** — see below
320
321
  - Targeted recommendations
321
322
  - Legal references (RGPD, ePrivacy directive, CEPD guidelines, CNIL 2022)
322
323
 
324
+ ### IAB TCF detection
325
+
326
+ When a site uses the [IAB Transparency & Consent Framework](https://iabeurope.eu/tcf-2-0/), the scanner automatically detects and decodes it. This is **informational only** — it does not affect the compliance score.
327
+
328
+ Detected signals:
329
+
330
+ - `window.__tcfapi` (TCF v2) or `window.__cmp` (TCF v1) JavaScript API
331
+ - `__tcfapiLocator` iframe
332
+ - `euconsent-v2` / `euconsent` cookie
333
+
334
+ When a consent string is found (via API or cookie), it is decoded to expose:
335
+
336
+ | Field | Description |
337
+ | --------------------------------- | ----------------------------------------------- |
338
+ | CMP ID & version | Which Consent Management Platform is in use |
339
+ | Consent language | Language the consent was collected in |
340
+ | Vendor list version | IAB GVL version at time of consent |
341
+ | Purposes with consent | IAB purposes explicitly consented to (IDs 1–11) |
342
+ | Purposes with legitimate interest | IAB purposes claimed under legitimate interest |
343
+ | Special features opted in | Geolocation, device scanning (IDs 1–2) |
344
+ | Publisher country | Country code of the publisher |
345
+
323
346
  ## Scoring
324
347
 
325
348
  The score is made up of 4 criteria (25 points each):
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Colour nudging detection — EDPB Guidelines 03/2022 § 3.3.3.
3
+ *
4
+ * A "positive" colour (green = go, approve) on the accept button combined with
5
+ * a "negative" or neutral colour (grey, red) on the reject button steers users
6
+ * toward consent without technically hiding the refusal option.
7
+ */
8
+ /** Returns [hue 0–360, saturation 0–100, lightness 0–100]. */
9
+ export declare function rgbToHsl(r: number, g: number, b: number): [number, number, number];
10
+ export type ButtonHue = "green" | "red" | "grey" | "blue" | "neutral";
11
+ /**
12
+ * Classify the perceptual "valence" of a colour:
13
+ * - green → positive, approval (h 80–165, s ≥ 25)
14
+ * - red → negative, danger (h ≤ 20 or ≥ 340, s ≥ 25)
15
+ * - grey → neutral / muted (s < 20)
16
+ * - blue → informational (h 195–265, s ≥ 25)
17
+ * - neutral → anything else
18
+ *
19
+ * Very dark (<10 L) or very light (>93 L) colours are treated as neutral
20
+ * because their hue carries little visual weight in a button context.
21
+ */
22
+ export declare function classifyHue(r: number, g: number, b: number): ButtonHue;
23
+ export interface ColourNudgingResult {
24
+ acceptHue: ButtonHue | null;
25
+ rejectHue: ButtonHue | null;
26
+ /** True when accept is green and reject is grey or red. */
27
+ isNudging: boolean;
28
+ }
29
+ /**
30
+ * Detect colour nudging between the accept and reject buttons.
31
+ *
32
+ * Returns `isNudging: true` when the accept button has a "positive" hue (green)
33
+ * while the reject button has a "negative" or neutral hue (grey or red).
34
+ */
35
+ export declare function detectColourNudging(acceptBg: string | null | undefined, rejectBg: string | null | undefined): ColourNudgingResult;
36
+ //# sourceMappingURL=colour.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colour.d.ts","sourceRoot":"","sources":["../../src/analyzers/colour.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAsBlF;AAED,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAQtE;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,2DAA2D;IAC3D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAClC,mBAAmB,CAUrB"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Colour nudging detection — EDPB Guidelines 03/2022 § 3.3.3.
3
+ *
4
+ * A "positive" colour (green = go, approve) on the accept button combined with
5
+ * a "negative" or neutral colour (grey, red) on the reject button steers users
6
+ * toward consent without technically hiding the refusal option.
7
+ */
8
+ function parseRgb(css) {
9
+ const m = css.match(/rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)/);
10
+ if (!m)
11
+ return null;
12
+ return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];
13
+ }
14
+ /** Returns [hue 0–360, saturation 0–100, lightness 0–100]. */
15
+ export function rgbToHsl(r, g, b) {
16
+ const rr = r / 255, gg = g / 255, bb = b / 255;
17
+ const max = Math.max(rr, gg, bb), min = Math.min(rr, gg, bb);
18
+ const l = (max + min) / 2;
19
+ if (max === min)
20
+ return [0, 0, Math.round(l * 100)];
21
+ const d = max - min;
22
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
23
+ let h;
24
+ switch (max) {
25
+ case rr:
26
+ h = (gg - bb) / d + (gg < bb ? 6 : 0);
27
+ break;
28
+ case gg:
29
+ h = (bb - rr) / d + 2;
30
+ break;
31
+ default:
32
+ h = (rr - gg) / d + 4;
33
+ }
34
+ return [Math.round(h * 60), Math.round(s * 100), Math.round(l * 100)];
35
+ }
36
+ /**
37
+ * Classify the perceptual "valence" of a colour:
38
+ * - green → positive, approval (h 80–165, s ≥ 25)
39
+ * - red → negative, danger (h ≤ 20 or ≥ 340, s ≥ 25)
40
+ * - grey → neutral / muted (s < 20)
41
+ * - blue → informational (h 195–265, s ≥ 25)
42
+ * - neutral → anything else
43
+ *
44
+ * Very dark (<10 L) or very light (>93 L) colours are treated as neutral
45
+ * because their hue carries little visual weight in a button context.
46
+ */
47
+ export function classifyHue(r, g, b) {
48
+ const [h, s, l] = rgbToHsl(r, g, b);
49
+ if (l < 10 || l > 93)
50
+ return "neutral";
51
+ if (s < 20)
52
+ return "grey";
53
+ if (h >= 80 && h <= 165)
54
+ return "green";
55
+ if (h <= 20 || h >= 340)
56
+ return "red";
57
+ if (h >= 195 && h <= 265)
58
+ return "blue";
59
+ return "neutral";
60
+ }
61
+ /**
62
+ * Detect colour nudging between the accept and reject buttons.
63
+ *
64
+ * Returns `isNudging: true` when the accept button has a "positive" hue (green)
65
+ * while the reject button has a "negative" or neutral hue (grey or red).
66
+ */
67
+ export function detectColourNudging(acceptBg, rejectBg) {
68
+ const acceptRgb = acceptBg ? parseRgb(acceptBg) : null;
69
+ const rejectRgb = rejectBg ? parseRgb(rejectBg) : null;
70
+ const acceptHue = acceptRgb ? classifyHue(...acceptRgb) : null;
71
+ const rejectHue = rejectRgb ? classifyHue(...rejectRgb) : null;
72
+ const isNudging = acceptHue === "green" && (rejectHue === "grey" || rejectHue === "red");
73
+ return { acceptHue, rejectHue, isNudging };
74
+ }
75
+ //# sourceMappingURL=colour.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colour.js","sourceRoot":"","sources":["../../src/analyzers/colour.ts"],"names":[],"mappings":"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"}
@@ -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,CAgPzE"}
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;AAIrB,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,CAwQzE"}
@@ -1,4 +1,5 @@
1
1
  import { analyzeButtonWording, analyzeModalText } from "./wording.js";
2
+ import { detectColourNudging } from "./colour.js";
2
3
  export function analyzeCompliance(input) {
3
4
  const issues = [];
4
5
  // Determine whether a consent mechanism is actually required
@@ -11,6 +12,9 @@ export function analyzeCompliance(input) {
11
12
  ...input.networkAfterAccept,
12
13
  ].some((r) => r.requiresConsent);
13
14
  const consentRequired = hasNonEssentialCookies || hasNonEssentialTrackers;
15
+ // Run wording analysis once — modal may not be detected, so these can be null
16
+ const wordingResult = input.modal.detected ? analyzeButtonWording(input.modal.buttons) : null;
17
+ const textResult = input.modal.detected ? analyzeModalText(input.modal.text) : null;
14
18
  // ── A. Consent validity (0-25) ────────────────────────────────
15
19
  let consentValidity = 25;
16
20
  if (!input.modal.detected && consentRequired) {
@@ -23,9 +27,7 @@ export function analyzeCompliance(input) {
23
27
  consentValidity = 0;
24
28
  }
25
29
  else if (input.modal.detected) {
26
- // Wording analysis
27
- const wordingResult = analyzeButtonWording(input.modal.buttons);
28
- const textResult = analyzeModalText(input.modal.text);
30
+ // Wording analysis (wordingResult / textResult hoisted above)
29
31
  issues.push(...wordingResult.issues, ...textResult.issues);
30
32
  // Pre-ticked checkboxes
31
33
  const preTicked = input.modal.checkboxes.filter((c) => c.isCheckedByDefault);
@@ -86,6 +88,23 @@ export function analyzeCompliance(input) {
86
88
  easyRefusal -= 5;
87
89
  }
88
90
  }
91
+ // Indirect reject label ("continuer sans accepter", "continue without accepting"…)
92
+ if (wordingResult?.hasIndirectRejectLabel) {
93
+ easyRefusal -= 5;
94
+ }
95
+ // Colour nudging: green accept + grey/red reject
96
+ if (acceptButton && rejectButton) {
97
+ const { isNudging, acceptHue, rejectHue } = detectColourNudging(acceptButton.backgroundColor, rejectButton.backgroundColor);
98
+ if (isNudging) {
99
+ issues.push({
100
+ type: "nudging",
101
+ severity: "warning",
102
+ description: 'Accept button uses a "positive" colour (green) while reject is visually de-emphasised',
103
+ evidence: `Accept: ${acceptButton.backgroundColor} (${acceptHue}), Reject: ${rejectButton.backgroundColor} (${rejectHue}) — EDPB Guidelines 03/2022 § 3.3.3`,
104
+ });
105
+ easyRefusal -= 5;
106
+ }
107
+ }
89
108
  // Font size asymmetry
90
109
  if (acceptButton?.fontSize && rejectButton?.fontSize) {
91
110
  if (acceptButton.fontSize > rejectButton.fontSize * 1.3) {
@@ -142,9 +161,8 @@ export function analyzeCompliance(input) {
142
161
  transparency -= 10;
143
162
  }
144
163
  // Already deducted in consentValidity for missing info
145
- const wordingResult = analyzeModalText(input.modal.text);
146
- if (wordingResult.missingInfo.length > 0) {
147
- transparency -= wordingResult.missingInfo.length * 3;
164
+ if (textResult.missingInfo.length > 0) {
165
+ transparency -= textResult.missingInfo.length * 3;
148
166
  }
149
167
  // No privacy policy link in the modal
150
168
  if (!input.modal.privacyPolicyUrl) {
@@ -1 +1 @@
1
- {"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAatE,MAAM,UAAU,iBAAiB,CAAC,KAAsB;IACtD,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,6DAA6D;IAC7D,MAAM,sBAAsB,GAAG;QAC7B,GAAG,KAAK,CAAC,wBAAwB;QACjC,GAAG,KAAK,CAAC,kBAAkB;KAC5B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IACjC,MAAM,uBAAuB,GAAG;QAC9B,GAAG,KAAK,CAAC,wBAAwB;QACjC,GAAG,KAAK,CAAC,kBAAkB;KAC5B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IACjC,MAAM,eAAe,GAAG,sBAAsB,IAAI,uBAAuB,CAAC;IAE1E,iEAAiE;IACjE,IAAI,eAAe,GAAG,EAAE,CAAC;IAEzB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,kBAAkB;YACxB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,kCAAkC;YAC/C,QAAQ,EAAE,yEAAyE;SACpF,CAAC,CAAC;QACH,eAAe,GAAG,CAAC,CAAC;IACtB,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,mBAAmB;QACnB,MAAM,aAAa,GAAG,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAE3D,wBAAwB;QACxB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAC7E,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,YAAY;gBAClB,QAAQ,EAAE,UAAU;gBACpB,WAAW,EAAE,GAAG,SAAS,CAAC,MAAM,qCAAqC;gBACrE,QAAQ,EAAE,yEAAyE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aACxI,CAAC,CAAC;YACH,eAAe,IAAI,EAAE,CAAC;QACxB,CAAC;QAED,0BAA0B;QAC1B,IAAI,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,eAAe,IAAI,CAAC,CAAC;QACtE,IAAI,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,eAAe,CAAC;YAAE,eAAe,IAAI,CAAC,CAAC;QAC3E,IAAI,UAAU,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC;YAAE,eAAe,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED,iEAAiE;IACjE,IAAI,WAAW,GAAG,EAAE,CAAC;IAErB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;QAC7C,WAAW,GAAG,CAAC,CAAC;IAClB,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAC1E,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAE1E,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,eAAe;gBACrB,QAAQ,EAAE,UAAU;gBACpB,WAAW,EAAE,iCAAiC;gBAC9C,QAAQ,EAAE,mEAAmE;aAC9E,CAAC,CAAC;YACH,WAAW,IAAI,EAAE,CAAC;QACpB,CAAC;aAAM,IAAI,YAAY,CAAC,UAAU,GAAG,CAAC,YAAY,EAAE,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,UAAU;gBACpB,WAAW,EAAE,yCAAyC;gBACtD,QAAQ,EAAE,WAAW,YAAY,EAAE,UAAU,IAAI,CAAC,sBAAsB,YAAY,CAAC,UAAU,WAAW;aAC3G,CAAC,CAAC;YACH,WAAW,IAAI,EAAE,CAAC;QACpB,CAAC;QAED,4EAA4E;QAC5E,IAAI,YAAY,IAAI,YAAY,IAAI,YAAY,CAAC,WAAW,IAAI,YAAY,CAAC,WAAW,EAAE,CAAC;YACzF,MAAM,UAAU,GAAG,YAAY,CAAC,WAAW,CAAC,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC;YACpF,MAAM,UAAU,GAAG,YAAY,CAAC,WAAW,CAAC,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC;YACpF,IAAI,UAAU,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,QAAQ,EAAE,SAAS;oBACnB,WAAW,EAAE,0DAA0D;oBACvE,QAAQ,EAAE,gBAAgB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK;iBACjG,CAAC,CAAC;gBACH,WAAW,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,YAAY,EAAE,QAAQ,IAAI,YAAY,EAAE,QAAQ,EAAE,CAAC;YACrD,IAAI,YAAY,CAAC,QAAQ,GAAG,YAAY,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC;gBACxD,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS;oBACf,QAAQ,EAAE,SAAS;oBACnB,WAAW,EAAE,+DAA+D;oBAC5E,QAAQ,EAAE,WAAW,YAAY,CAAC,QAAQ,eAAe,YAAY,CAAC,QAAQ,IAAI;iBACnF,CAAC,CAAC;gBACH,WAAW,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,6DAA6D;QAC7D,IAAI,YAAY,IAAI,YAAY,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YACxD,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC;YACzC,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,QAAQ,EAAE,UAAU;oBACpB,WAAW,EAAE,iDAAiD;oBAC9D,QAAQ,EAAE,kBAAkB,KAAK,gDAAgD,YAAY,CAAC,eAAe,IAAI,GAAG,MAAM,YAAY,CAAC,SAAS,IAAI,GAAG,GAAG;iBAC3J,CAAC,CAAC;gBACH,WAAW,IAAI,EAAE,CAAC;YACpB,CAAC;iBAAM,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,QAAQ,EAAE,SAAS;oBACnB,WAAW,EAAE,yDAAyD;oBACtE,QAAQ,EAAE,kBAAkB,KAAK,gDAAgD,YAAY,CAAC,eAAe,IAAI,GAAG,MAAM,YAAY,CAAC,SAAS,IAAI,GAAG,GAAG;iBAC3J,CAAC,CAAC;gBACH,WAAW,IAAI,CAAC,CAAC;YACnB,CAAC;YAED,qEAAqE;YACrE,MAAM,cAAc,GAAG,YAAY,EAAE,aAAa,IAAI,IAAI,CAAC;YAC3D,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,IAAI,YAAY,CAAC,aAAa,GAAG,GAAG,EAAE,CAAC;gBAClF,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,QAAQ,EAAE,SAAS;oBACnB,WAAW,EAAE,oEAAoE;oBACjF,QAAQ,EAAE,WAAW,cAAc,eAAe,YAAY,CAAC,aAAa,IAAI;iBACjF,CAAC,CAAC;gBACH,WAAW,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;QAC7C,YAAY,GAAG,CAAC,CAAC;IACnB,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC;YACrC,YAAY,IAAI,EAAE,CAAC;QACrB,CAAC;QACD,uDAAuD;QACvD,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,aAAa,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzC,YAAY,IAAI,aAAa,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;QACvD,CAAC;QACD,sCAAsC;QACtC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,SAAS;gBACnB,WAAW,EAAE,mDAAmD;gBAChE,QAAQ,EACN,sFAAsF;aACzF,CAAC,CAAC;YACH,YAAY,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,uFAAuF;IACvF,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,eAAe,EAAE,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,SAAS;YACnB,WAAW,EAAE,0CAA0C;YACvD,QAAQ,EAAE,oEAAoE;SAC/E,CAAC,CAAC;QACH,YAAY,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,iEAAiE;IACjE,IAAI,cAAc,GAAG,EAAE,CAAC;IAExB,gEAAgE;IAChE,MAAM,wBAAwB,GAAG,KAAK,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IAEjG,IAAI,wBAAwB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,GAAG,wBAAwB,CAAC,MAAM,2DAA2D;YAC1G,QAAQ,EAAE,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SACtF,CAAC,CAAC;QACH,cAAc,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,wBAAwB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,gDAAgD;IAChD,MAAM,yBAAyB,GAAG,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAC/D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,UAAU,KAAK,cAAc,CAC5D,CAAC;IAEF,IAAI,yBAAyB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,GAAG,yBAAyB,CAAC,MAAM,kDAAkD;YAClG,QAAQ,EAAE,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SACvF,CAAC,CAAC;QACH,cAAc,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,yBAAyB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,6CAA6C;IAC7C,MAAM,sBAAsB,GAAG,KAAK,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IAE/F,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,GAAG,sBAAsB,CAAC,MAAM,8CAA8C;YAC3F,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;iBAC9E,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iBACX,IAAI,CAAC,IAAI,CAAC;SACd,CAAC,CAAC;QACH,cAAc,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,sBAAsB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,mBAAmB;IACnB,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG;QAChB,eAAe,EAAE,KAAK,CAAC,eAAe,CAAC;QACvC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC;QAC/B,YAAY,EAAE,KAAK,CAAC,YAAY,CAAC;QACjC,cAAc,EAAE,KAAK,CAAC,cAAc,CAAC;KACtC,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAElE,OAAO;QACL,KAAK;QACL,SAAS;QACT,MAAM;QACN,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { TcfConsentString } from "../types.js";
2
+ export declare const IAB_PURPOSES: Record<number, string>;
3
+ export declare const IAB_SPECIAL_FEATURES: Record<number, string>;
4
+ /**
5
+ * Decode a TCF v1 or v2 consent string (core segment only).
6
+ * Returns null if decoding fails or if the version is not 1 or 2.
7
+ */
8
+ export declare function decodeTcfConsentString(raw: string): TcfConsentString | null;
9
+ //# sourceMappingURL=tcf-decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tcf-decoder.d.ts","sourceRoot":"","sources":["../../src/analyzers/tcf-decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY/C,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGvD,CAAC;AAwCF;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkE3E"}