@slashgear/gdpr-cookie-scanner 1.4.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +13 -0
- package/.github/workflows/ci.yml +2 -2
- package/.github/workflows/pages.yml +40 -0
- package/.github/workflows/release.yml +1 -1
- package/.nvmrc +1 -0
- package/CHANGELOG.md +73 -0
- package/Dockerfile +36 -0
- package/README.md +42 -15
- package/dist/cli.js +21 -3
- package/dist/cli.js.map +1 -1
- package/dist/report/generator.d.ts +1 -4
- package/dist/report/generator.d.ts.map +1 -1
- package/dist/report/generator.js +45 -23
- package/dist/report/generator.js.map +1 -1
- package/dist/report/html.d.ts +3 -0
- package/dist/report/html.d.ts.map +1 -0
- package/dist/report/html.js +766 -0
- package/dist/report/html.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/index.html +314 -0
- package/docs/reports/github.com/after-accept.png +0 -0
- package/docs/reports/github.com/after-reject.png +0 -0
- package/docs/reports/github.com/gdpr-checklist-github.com-2026-02-22.md +44 -0
- package/docs/reports/github.com/gdpr-cookies-github.com-2026-02-22.md +29 -0
- package/docs/reports/github.com/gdpr-report-github.com-2026-02-22.md +102 -0
- package/docs/reports/github.com/gdpr-report-github.com-2026-02-22.pdf +0 -0
- package/docs/reports/gitlab.com/after-accept.png +0 -0
- package/docs/reports/gitlab.com/after-reject.png +0 -0
- package/docs/reports/gitlab.com/gdpr-checklist-gitlab.com-2026-02-22.md +44 -0
- package/docs/reports/gitlab.com/gdpr-cookies-gitlab.com-2026-02-22.md +55 -0
- package/docs/reports/gitlab.com/gdpr-report-gitlab.com-2026-02-22.md +200 -0
- package/docs/reports/gitlab.com/gdpr-report-gitlab.com-2026-02-22.pdf +0 -0
- package/docs/reports/gitlab.com/modal-initial.png +0 -0
- package/docs/reports/npmjs.com/after-accept.png +0 -0
- package/docs/reports/npmjs.com/after-reject.png +0 -0
- package/docs/reports/npmjs.com/gdpr-checklist-npmjs.com-2026-02-22.md +44 -0
- package/docs/reports/npmjs.com/gdpr-cookies-npmjs.com-2026-02-22.md +25 -0
- package/docs/reports/npmjs.com/gdpr-report-npmjs.com-2026-02-22.md +88 -0
- package/docs/reports/npmjs.com/gdpr-report-npmjs.com-2026-02-22.pdf +0 -0
- package/docs/reports/reddit.com/after-accept.png +0 -0
- package/docs/reports/reddit.com/after-reject.png +0 -0
- package/docs/reports/reddit.com/gdpr-checklist-reddit.com-2026-02-22.md +44 -0
- package/docs/reports/reddit.com/gdpr-cookies-reddit.com-2026-02-22.md +33 -0
- package/docs/reports/reddit.com/gdpr-report-reddit.com-2026-02-22.md +148 -0
- package/docs/reports/reddit.com/gdpr-report-reddit.com-2026-02-22.pdf +0 -0
- package/docs/reports/reddit.com/modal-initial.png +0 -0
- package/docs/reports/stackoverflow.com/after-accept.png +0 -0
- package/docs/reports/stackoverflow.com/after-reject.png +0 -0
- package/docs/reports/stackoverflow.com/gdpr-checklist-stackoverflow.com-2026-02-22.md +44 -0
- package/docs/reports/stackoverflow.com/gdpr-cookies-stackoverflow.com-2026-02-22.md +67 -0
- package/docs/reports/stackoverflow.com/gdpr-report-stackoverflow.com-2026-02-22.md +206 -0
- package/docs/reports/stackoverflow.com/gdpr-report-stackoverflow.com-2026-02-22.pdf +0 -0
- package/docs/reports/stackoverflow.com/modal-initial.png +0 -0
- package/docs/reports/www.afp.com/after-accept.png +0 -0
- package/docs/reports/www.afp.com/after-reject.png +0 -0
- package/docs/reports/www.afp.com/gdpr-checklist-afp.com-2026-02-22.md +44 -0
- package/docs/reports/www.afp.com/gdpr-cookies-afp.com-2026-02-22.md +42 -0
- package/docs/reports/www.afp.com/gdpr-report-afp.com-2026-02-22.md +202 -0
- package/docs/reports/www.afp.com/gdpr-report-afp.com-2026-02-22.pdf +0 -0
- package/docs/reports/www.afp.com/modal-initial.png +0 -0
- package/docs/style.css +439 -0
- package/package.json +6 -6
- package/src/cli.ts +28 -4
- package/src/report/generator.ts +54 -29
- package/src/report/html.ts +940 -0
- package/src/types.ts +3 -0
package/.dockerignore
ADDED
package/.github/workflows/ci.yml
CHANGED
|
@@ -11,7 +11,7 @@ jobs:
|
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
15
|
|
|
16
16
|
- uses: pnpm/action-setup@v4
|
|
17
17
|
with:
|
|
@@ -19,7 +19,7 @@ jobs:
|
|
|
19
19
|
|
|
20
20
|
- uses: actions/setup-node@v4
|
|
21
21
|
with:
|
|
22
|
-
node-version:
|
|
22
|
+
node-version: 24
|
|
23
23
|
cache: pnpm
|
|
24
24
|
|
|
25
25
|
- name: Install dependencies
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Deploy GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- "docs/**"
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
pages: write
|
|
14
|
+
id-token: write
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: pages
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
deploy:
|
|
22
|
+
environment:
|
|
23
|
+
name: github-pages
|
|
24
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Configure Pages
|
|
31
|
+
uses: actions/configure-pages@v4
|
|
32
|
+
|
|
33
|
+
- name: Upload artifact
|
|
34
|
+
uses: actions/upload-pages-artifact@v3
|
|
35
|
+
with:
|
|
36
|
+
path: docs/
|
|
37
|
+
|
|
38
|
+
- name: Deploy to GitHub Pages
|
|
39
|
+
id: deployment
|
|
40
|
+
uses: actions/deploy-pages@v4
|
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
24
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# @slashgear/gdpr-cookie-scanner
|
|
2
2
|
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 469c8e8: Fix Docker image not being published on release.
|
|
8
|
+
|
|
9
|
+
The `docker.yml` workflow was triggered on `release: published`, but GitHub Actions blocks workflows using `GITHUB_TOKEN` from cascading into other workflows, so the Docker build never ran. Merged the Docker build steps directly into `release.yml`, gated on `changesets/action` reporting `published == 'true'`.
|
|
10
|
+
|
|
11
|
+
## 2.0.0
|
|
12
|
+
|
|
13
|
+
### Major Changes
|
|
14
|
+
|
|
15
|
+
- 98880ac: feat!: require Node.js 24 LTS (breaking change for Node 20/22 users)
|
|
16
|
+
|
|
17
|
+
Node.js 24 became Active LTS in October 2025. This is a breaking change for
|
|
18
|
+
users running Node 20 or 22. A `.nvmrc` file is provided so `nvm use`
|
|
19
|
+
automatically selects the correct version when entering the project directory.
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- bd769d6: Add GitHub Pages landing page with live GDPR reports
|
|
24
|
+
|
|
25
|
+
Adds a static landing page (`docs/`) hosted on GitHub Pages that showcases the tool
|
|
26
|
+
with real scan results for 6 tech sites (reddit.com, dev.to, github.com, gitlab.com,
|
|
27
|
+
stackoverflow.com, npmjs.com). The page is vanilla HTML/CSS with dark mode support
|
|
28
|
+
and links directly to the rendered Markdown reports on GitHub.
|
|
29
|
+
|
|
30
|
+
Also adds `.github/workflows/pages.yml` to automatically deploy `docs/` on every
|
|
31
|
+
push to `main` that touches that directory.
|
|
32
|
+
|
|
33
|
+
- cf9c42a: feat: add Docker image for containerised usage
|
|
34
|
+
|
|
35
|
+
A `Dockerfile` is now included at the root of the repository, enabling
|
|
36
|
+
`gdpr-scan` to be run in any environment that supports Docker without
|
|
37
|
+
needing a local Node.js or Playwright installation.
|
|
38
|
+
|
|
39
|
+
The image uses a two-stage build:
|
|
40
|
+
|
|
41
|
+
- **Builder** (`node:24-slim`) — compiles TypeScript to `dist/`
|
|
42
|
+
- **Runtime** (`node:24-slim` + `playwright install chromium --with-deps`) —
|
|
43
|
+
installs only Chromium and its system dependencies instead of the full
|
|
44
|
+
official Playwright image (which bundles Chromium, Firefox and WebKit).
|
|
45
|
+
This keeps the final image around **400–600 MB** vs ~1.5–1.8 GB for the
|
|
46
|
+
unoptimised approach.
|
|
47
|
+
|
|
48
|
+
A `.dockerignore` is also included to exclude source files, Git history,
|
|
49
|
+
and dev artefacts from the build context.
|
|
50
|
+
|
|
51
|
+
Usage:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Build
|
|
55
|
+
docker build -t gdpr-scan .
|
|
56
|
+
|
|
57
|
+
# Run a scan (mount a local directory to retrieve the reports)
|
|
58
|
+
docker run --rm -v $(pwd)/reports:/reports gdpr-scan scan https://example.com -o /reports
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- 5cba8a8: feat: add multi-format report output and a standalone HTML report
|
|
62
|
+
|
|
63
|
+
The CLI now accepts a `-f, --format <formats>` option (comma-separated, defaults
|
|
64
|
+
to `md,pdf`) that controls which report files are produced. Supported values:
|
|
65
|
+
`md`, `html`, `json`, `pdf`.
|
|
66
|
+
|
|
67
|
+
The new `html` format generates a self-contained, styled HTML report directly from
|
|
68
|
+
the scan result — no external dependencies, no network requests. It includes a
|
|
69
|
+
colour-coded grade badge, per-dimension score cards with progress bars,
|
|
70
|
+
dark-pattern issue cards, modal details, cookies by phase, network tracker tables,
|
|
71
|
+
recommendations, and a compliance checklist.
|
|
72
|
+
|
|
73
|
+
This makes the report easier to share (single file, opens in any browser) and
|
|
74
|
+
provides a better reading experience than the Markdown version.
|
|
75
|
+
|
|
3
76
|
## 1.4.0
|
|
4
77
|
|
|
5
78
|
### Minor Changes
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# ── Stage 1: build ────────────────────────────────────────────────────────────
|
|
2
|
+
FROM node:24-slim AS builder
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
RUN npm install -g pnpm@latest
|
|
6
|
+
|
|
7
|
+
COPY package.json pnpm-lock.yaml ./
|
|
8
|
+
RUN pnpm install --frozen-lockfile
|
|
9
|
+
|
|
10
|
+
COPY tsconfig.json ./
|
|
11
|
+
COPY src ./src
|
|
12
|
+
RUN pnpm build
|
|
13
|
+
|
|
14
|
+
# ── Stage 2: runtime ──────────────────────────────────────────────────────────
|
|
15
|
+
# node:24-slim + Chromium only (~400-600 MB) vs the full Playwright image
|
|
16
|
+
# (~1.5-1.8 GB with all 3 browser stacks).
|
|
17
|
+
FROM node:24-slim
|
|
18
|
+
WORKDIR /app
|
|
19
|
+
ENV NODE_ENV=production
|
|
20
|
+
|
|
21
|
+
RUN npm install -g pnpm@latest
|
|
22
|
+
|
|
23
|
+
# Install production dependencies first — playwright CLI is needed for browser install
|
|
24
|
+
COPY package.json pnpm-lock.yaml ./
|
|
25
|
+
RUN pnpm install --prod --frozen-lockfile
|
|
26
|
+
|
|
27
|
+
# Install Chromium + its system dependencies, then clean up apt caches
|
|
28
|
+
RUN pnpm exec playwright install chromium --with-deps \
|
|
29
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
30
|
+
|
|
31
|
+
COPY --from=builder /app/dist ./dist
|
|
32
|
+
|
|
33
|
+
VOLUME ["/reports"]
|
|
34
|
+
|
|
35
|
+
ENTRYPOINT ["node", "dist/cli.js"]
|
|
36
|
+
CMD ["--help"]
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# gdpr-cookie-scanner
|
|
2
2
|
|
|
3
|
-
[](https://github.com/Slashgear/gdpr-cookie-scanner/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/@slashgear/gdpr-cookie-scanner)
|
|
5
5
|
[](https://www.npmjs.com/package/@slashgear/gdpr-cookie-scanner)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](https://nodejs.org)
|
|
8
8
|
[](https://www.typescriptlang.org)
|
|
9
9
|
[](https://playwright.dev)
|
|
10
10
|
[](CODE_OF_CONDUCT.md)
|
|
@@ -35,6 +35,20 @@ npx @slashgear/gdpr-cookie-scanner gdpr-scan scan https://example.com
|
|
|
35
35
|
npx playwright install chromium
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## Docker
|
|
39
|
+
|
|
40
|
+
No Node.js required — pull and run directly:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
docker run --rm \
|
|
44
|
+
-v $(pwd)/reports:/reports \
|
|
45
|
+
ghcr.io/slashgear/gdpr-cookie-scanner \
|
|
46
|
+
scan https://example.com -o /reports
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The image is published to [GitHub Container Registry](https://ghcr.io/slashgear/gdpr-cookie-scanner)
|
|
50
|
+
on every release and supports `linux/amd64` and `linux/arm64`.
|
|
51
|
+
|
|
38
52
|
## Usage
|
|
39
53
|
|
|
40
54
|
```bash
|
|
@@ -43,13 +57,14 @@ gdpr-scan scan <url> [options]
|
|
|
43
57
|
|
|
44
58
|
### Options
|
|
45
59
|
|
|
46
|
-
| Option
|
|
47
|
-
|
|
|
48
|
-
| `-o, --output <dir>`
|
|
49
|
-
| `-t, --timeout <ms>`
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
| `-
|
|
60
|
+
| Option | Default | Description |
|
|
61
|
+
| ------------------------ | ---------------- | ------------------------------------------------------------- |
|
|
62
|
+
| `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
|
|
63
|
+
| `-t, --timeout <ms>` | `30000` | Navigation timeout |
|
|
64
|
+
| `-f, --format <formats>` | `md,pdf` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
|
|
65
|
+
| `--no-screenshots` | — | Disable screenshot capture |
|
|
66
|
+
| `-l, --locale <locale>` | `fr-FR` | Browser locale |
|
|
67
|
+
| `-v, --verbose` | — | Show full stack trace on error |
|
|
53
68
|
|
|
54
69
|
### Examples
|
|
55
70
|
|
|
@@ -63,6 +78,12 @@ gdpr-scan scan https://example.com -o ./reports
|
|
|
63
78
|
# Scan in English, without screenshots
|
|
64
79
|
gdpr-scan scan https://example.com --locale en-US --no-screenshots
|
|
65
80
|
|
|
81
|
+
# Generate only an HTML report
|
|
82
|
+
gdpr-scan scan https://example.com -f html
|
|
83
|
+
|
|
84
|
+
# Generate all formats at once
|
|
85
|
+
gdpr-scan scan https://example.com -f md,html,json,pdf
|
|
86
|
+
|
|
66
87
|
# Show the built-in tracker database
|
|
67
88
|
gdpr-scan list-trackers
|
|
68
89
|
```
|
|
@@ -74,14 +95,22 @@ flowchart LR
|
|
|
74
95
|
URL([URL]) --> Chromium[Chromium] --> Classify[Classify] --> Score[Score] --> Report[Report]
|
|
75
96
|
```
|
|
76
97
|
|
|
77
|
-
A real Chromium browser loads the page, interacts with the consent modal (reject then accept in a fresh session), and captures cookies and network requests at each step. Results are classified, scored across 4 compliance dimensions, and rendered into
|
|
98
|
+
A real Chromium browser loads the page, interacts with the consent modal (reject then accept in a fresh session), and captures cookies and network requests at each step. Results are classified, scored across 4 compliance dimensions, and rendered into one or more report files depending on `--format`.
|
|
99
|
+
|
|
100
|
+
## Generated reports
|
|
78
101
|
|
|
79
|
-
|
|
102
|
+
Each scan produces up to 4 file types in `<output-dir>/<hostname>/`:
|
|
80
103
|
|
|
81
|
-
|
|
104
|
+
| Format | Files | Description |
|
|
105
|
+
| ------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
106
|
+
| `md` | `gdpr-report-*.md`, `gdpr-checklist-*.md`, `gdpr-cookies-*.md` | Main compliance report, per-rule checklist with legal references, and deduplicated cookie inventory |
|
|
107
|
+
| `html` | `gdpr-report-*.html` | Self-contained styled report — grade badge, score cards, dark-pattern issues, cookie and tracker tables. Opens in any browser, no dependencies |
|
|
108
|
+
| `json` | `gdpr-report-*.json` | Full raw scan result for programmatic processing or CI integration |
|
|
109
|
+
| `pdf` | `gdpr-report-*.pdf` | PDF built from the Markdown reports via Playwright |
|
|
110
|
+
|
|
111
|
+
All formats contain:
|
|
82
112
|
|
|
83
113
|
- **Global score** (0–100) and **grade** A/B/C/D/F
|
|
84
|
-
- Executive summary
|
|
85
114
|
- Modal analysis: buttons, checkboxes, font size, screenshots
|
|
86
115
|
- Detected dark patterns (missing reject button, visual asymmetry, pre-ticked boxes, misleading wording…)
|
|
87
116
|
- Cookie table before interaction, after reject, after accept
|
|
@@ -89,8 +118,6 @@ The Markdown report contains:
|
|
|
89
118
|
- Targeted recommendations
|
|
90
119
|
- Legal references (RGPD, ePrivacy directive, CEPD guidelines, CNIL 2022)
|
|
91
120
|
|
|
92
|
-
The file is created at: `<output-dir>/gdpr-report-<domain>-<date>.md`
|
|
93
|
-
|
|
94
121
|
## Scoring
|
|
95
122
|
|
|
96
123
|
The score is made up of 4 criteria (25 points each):
|
package/dist/cli.js
CHANGED
|
@@ -19,6 +19,7 @@ program
|
|
|
19
19
|
.option("--no-screenshots", "Disable screenshot capture")
|
|
20
20
|
.option("-l, --locale <locale>", "Browser locale for language detection", "fr-FR")
|
|
21
21
|
.option("-v, --verbose", "Show detailed output", false)
|
|
22
|
+
.option("-f, --format <formats>", "Output formats: md, html, json, pdf (comma-separated)", "md,pdf")
|
|
22
23
|
.action(async (url, opts) => {
|
|
23
24
|
console.log();
|
|
24
25
|
console.log(chalk.bold.blue(" GDPR Cookie Scanner"));
|
|
@@ -29,6 +30,15 @@ program
|
|
|
29
30
|
console.log(chalk.gray(` Target : ${url}`));
|
|
30
31
|
console.log(chalk.gray(` Output : ${outputDir}`));
|
|
31
32
|
console.log();
|
|
33
|
+
const validFormats = new Set(["md", "html", "json", "pdf"]);
|
|
34
|
+
const formats = opts.format
|
|
35
|
+
.split(",")
|
|
36
|
+
.map((f) => f.trim().toLowerCase())
|
|
37
|
+
.filter((f) => validFormats.has(f));
|
|
38
|
+
if (formats.length === 0) {
|
|
39
|
+
console.error(chalk.red(" Invalid --format value. Valid options: md, html, json, pdf"));
|
|
40
|
+
process.exit(2);
|
|
41
|
+
}
|
|
32
42
|
const options = {
|
|
33
43
|
url: normalizedUrl,
|
|
34
44
|
outputDir,
|
|
@@ -36,6 +46,7 @@ program
|
|
|
36
46
|
screenshots: opts.screenshots !== false,
|
|
37
47
|
locale: opts.locale,
|
|
38
48
|
verbose: opts.verbose,
|
|
49
|
+
formats,
|
|
39
50
|
};
|
|
40
51
|
const spinner = ora("Launching browser...").start();
|
|
41
52
|
try {
|
|
@@ -47,7 +58,7 @@ program
|
|
|
47
58
|
spinner.succeed("Scan complete");
|
|
48
59
|
console.log();
|
|
49
60
|
const generator = new ReportGenerator(options);
|
|
50
|
-
const
|
|
61
|
+
const paths = await generator.generate(result);
|
|
51
62
|
console.log(chalk.bold(` Compliance score: ${formatScore(result.compliance.total)} ${result.compliance.grade}`));
|
|
52
63
|
console.log();
|
|
53
64
|
if (result.compliance.issues.length > 0) {
|
|
@@ -61,8 +72,15 @@ program
|
|
|
61
72
|
}
|
|
62
73
|
console.log();
|
|
63
74
|
}
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
const labels = {
|
|
76
|
+
md: "Markdown",
|
|
77
|
+
html: "HTML",
|
|
78
|
+
json: "JSON",
|
|
79
|
+
pdf: "PDF",
|
|
80
|
+
};
|
|
81
|
+
for (const [fmt, path] of Object.entries(paths)) {
|
|
82
|
+
console.log(chalk.green(` ${(labels[fmt] ?? fmt).padEnd(8)} ${path}`));
|
|
83
|
+
}
|
|
66
84
|
console.log();
|
|
67
85
|
process.exit(result.compliance.grade === "F" ? 1 : 0);
|
|
68
86
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,mDAAmD,CAAC;KAChE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,sDAAsD,CAAC;KACnE,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC;KAC/C,MAAM,CAAC,oBAAoB,EAAE,iCAAiC,EAAE,gBAAgB,CAAC;KACjF,MAAM,CAAC,oBAAoB,EAAE,oCAAoC,EAAE,OAAO,CAAC;KAC3E,MAAM,CAAC,kBAAkB,EAAE,4BAA4B,CAAC;KACxD,MAAM,CAAC,uBAAuB,EAAE,uCAAuC,EAAE,OAAO,CAAC;KACjF,MAAM,CAAC,eAAe,EAAE,sBAAsB,EAAE,KAAK,CAAC;KACtD,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,IAAI,EAAE,EAAE;IAClC,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC,CAAC;IACnE,MAAM,aAAa,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,SAAS,EAAE,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,OAAO,GAAgB;QAC3B,GAAG,EAAE,aAAa;QAClB,SAAS;QACT,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QACnC,WAAW,EAAE,IAAI,CAAC,WAAW,KAAK,KAAK;QACvC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,10 +3,7 @@ import type { ScanOptions } from "../types.js";
|
|
|
3
3
|
export declare class ReportGenerator {
|
|
4
4
|
private readonly options;
|
|
5
5
|
constructor(options: ScanOptions);
|
|
6
|
-
generate(result: ScanResult): Promise<
|
|
7
|
-
reportPath: string;
|
|
8
|
-
pdfPath: string;
|
|
9
|
-
}>;
|
|
6
|
+
generate(result: ScanResult): Promise<Record<string, string>>;
|
|
10
7
|
private buildHtmlBody;
|
|
11
8
|
private inlineImages;
|
|
12
9
|
private wrapHtml;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,UAAU,EAKX,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW;IAE3C,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YA2DrD,aAAa;YAkDb,YAAY;IAmC1B,OAAO,CAAC,QAAQ;IAgDhB,OAAO,CAAC,aAAa;IA6ErB,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,qBAAqB;IAkD7B,OAAO,CAAC,iBAAiB;IA2EzB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,kBAAkB;IAqC1B,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,8BAA8B;IAiBtC,OAAO,CAAC,mBAAmB;IAgD3B,OAAO,CAAC,oBAAoB;IA2D5B,OAAO,CAAC,qBAAqB;IA6H7B,OAAO,CAAC,cAAc;CAmRvB"}
|
package/dist/report/generator.js
CHANGED
|
@@ -5,6 +5,7 @@ import { promisify } from "util";
|
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { Marked } from "marked";
|
|
7
7
|
import { generatePdf } from "./pdf.js";
|
|
8
|
+
import { generateHtmlReport } from "./html.js";
|
|
8
9
|
const execFileAsync = promisify(execFile);
|
|
9
10
|
const oxfmtBin = join(dirname(fileURLToPath(import.meta.url)), "../../node_modules/.bin/oxfmt");
|
|
10
11
|
export class ReportGenerator {
|
|
@@ -16,29 +17,50 @@ export class ReportGenerator {
|
|
|
16
17
|
await mkdir(this.options.outputDir, { recursive: true });
|
|
17
18
|
const hostname = new URL(result.url).hostname.replace(/^www\./, "");
|
|
18
19
|
const date = new Date(result.scanDate).toISOString().split("T")[0];
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
20
|
+
const base = `gdpr-report-${hostname}-${date}`;
|
|
21
|
+
const formats = this.options.formats;
|
|
22
|
+
const paths = {};
|
|
23
|
+
// ── Markdown ──────────────────────────────────────────────────
|
|
24
|
+
if (formats.includes("md")) {
|
|
25
|
+
const mdPath = join(this.options.outputDir, `${base}.md`);
|
|
26
|
+
await writeFile(mdPath, this.buildMarkdown(result), "utf-8");
|
|
27
|
+
await execFileAsync(oxfmtBin, [mdPath]).catch(() => { });
|
|
28
|
+
paths.md = mdPath;
|
|
29
|
+
const checklistPath = join(this.options.outputDir, `gdpr-checklist-${hostname}-${date}.md`);
|
|
30
|
+
await writeFile(checklistPath, this.buildChecklist(result), "utf-8");
|
|
31
|
+
await execFileAsync(oxfmtBin, [checklistPath]).catch(() => { });
|
|
32
|
+
const cookiesPath = join(this.options.outputDir, `gdpr-cookies-${hostname}-${date}.md`);
|
|
33
|
+
await writeFile(cookiesPath, this.buildCookiesInventory(result), "utf-8");
|
|
34
|
+
await execFileAsync(oxfmtBin, [cookiesPath]).catch(() => { });
|
|
35
|
+
}
|
|
36
|
+
// ── HTML ──────────────────────────────────────────────────────
|
|
37
|
+
if (formats.includes("html")) {
|
|
38
|
+
const htmlPath = join(this.options.outputDir, `${base}.html`);
|
|
39
|
+
await writeFile(htmlPath, generateHtmlReport(result), "utf-8");
|
|
40
|
+
paths.html = htmlPath;
|
|
41
|
+
}
|
|
42
|
+
// ── JSON ──────────────────────────────────────────────────────
|
|
43
|
+
if (formats.includes("json")) {
|
|
44
|
+
const jsonPath = join(this.options.outputDir, `${base}.json`);
|
|
45
|
+
await writeFile(jsonPath, JSON.stringify(result, null, 2), "utf-8");
|
|
46
|
+
paths.json = jsonPath;
|
|
47
|
+
}
|
|
48
|
+
// ── PDF (via Markdown → HTML → Playwright) ────────────────────
|
|
49
|
+
if (formats.includes("pdf")) {
|
|
50
|
+
const markdown = paths.md
|
|
51
|
+
? await import("fs/promises").then((m) => m.readFile(paths.md, "utf-8"))
|
|
52
|
+
: this.buildMarkdown(result);
|
|
53
|
+
const checklist = this.buildChecklist(result);
|
|
54
|
+
const cookiesInventory = this.buildCookiesInventory(result);
|
|
55
|
+
const combined = [markdown, checklist, cookiesInventory].join("\n\n---\n\n");
|
|
56
|
+
const rawBody = await this.buildHtmlBody(combined);
|
|
57
|
+
const body = await this.inlineImages(rawBody, this.options.outputDir);
|
|
58
|
+
const html = this.wrapHtml(body, hostname);
|
|
59
|
+
const pdfPath = join(this.options.outputDir, `${base}.pdf`);
|
|
60
|
+
await generatePdf(html, pdfPath);
|
|
61
|
+
paths.pdf = pdfPath;
|
|
62
|
+
}
|
|
63
|
+
return paths;
|
|
42
64
|
}
|
|
43
65
|
async buildHtmlBody(markdown) {
|
|
44
66
|
const entries = [];
|