@slashgear/gdpr-cookie-scanner 2.0.2 → 2.0.4
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/.github/workflows/release.yml +3 -2
- package/CHANGELOG.md +19 -0
- package/dist/cli.js +25 -25
- package/dist/cli.js.map +1 -1
- package/package.json +3 -4
- package/src/cli.ts +34 -25
|
@@ -49,6 +49,7 @@ jobs:
|
|
|
49
49
|
run: |
|
|
50
50
|
VERSION=$(echo '${{ steps.changesets.outputs.publishedPackages }}' | jq -r '.[0].version')
|
|
51
51
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
52
|
+
echo "image=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
|
|
52
53
|
|
|
53
54
|
- name: Log in to GitHub Container Registry
|
|
54
55
|
if: steps.changesets.outputs.published == 'true'
|
|
@@ -65,5 +66,5 @@ jobs:
|
|
|
65
66
|
context: .
|
|
66
67
|
push: true
|
|
67
68
|
tags: |
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
${{ steps.version.outputs.image }}:latest
|
|
70
|
+
${{ steps.version.outputs.image }}:${{ steps.version.outputs.version }}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @slashgear/gdpr-cookie-scanner
|
|
2
2
|
|
|
3
|
+
## 2.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 81d9b79: Replace `chalk` and `ora` with lighter, zero/minimal-dependency alternatives.
|
|
8
|
+
|
|
9
|
+
- `chalk` → `node:util styleText` (Node.js built-in, no dependency at all)
|
|
10
|
+
- `ora` → `nanospinner` (single dependency, same spinner UX)
|
|
11
|
+
|
|
12
|
+
This reduces the install footprint and removes two runtime dependencies in favour of the e18e ecosystem recommendations. The only visual difference is that the orange score color (formerly `chalk.hex("#FFA500")`) is now rendered as `yellowBright`, since `styleText` does not support hex colors.
|
|
13
|
+
|
|
14
|
+
## 2.0.3
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- cc8b0dc: Fix Docker image tags using lowercase repository name.
|
|
19
|
+
|
|
20
|
+
`github.repository` can contain uppercase letters (e.g. `Slashgear/gdpr-cookie-scanner`), which is rejected by the OCI registry spec. The image name is now lowercased via `tr '[:upper:]' '[:lower:]'` before being passed to `docker/build-push-action`.
|
|
21
|
+
|
|
3
22
|
## 2.0.2
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import { styleText } from "node:util";
|
|
4
|
+
import { createSpinner } from "nanospinner";
|
|
5
5
|
import { join, resolve } from "path";
|
|
6
6
|
import { Scanner } from "./scanner/index.js";
|
|
7
7
|
import { ReportGenerator } from "./report/generator.js";
|
|
@@ -22,13 +22,13 @@ program
|
|
|
22
22
|
.option("-f, --format <formats>", "Output formats: md, html, json, pdf (comma-separated)", "md,pdf")
|
|
23
23
|
.action(async (url, opts) => {
|
|
24
24
|
console.log();
|
|
25
|
-
console.log(
|
|
26
|
-
console.log(
|
|
25
|
+
console.log(styleText(["bold", "blue"], " GDPR Cookie Scanner"));
|
|
26
|
+
console.log(styleText("gray", " ─────────────────────────────────────"));
|
|
27
27
|
const normalizedUrl = normalizeUrl(url);
|
|
28
28
|
const hostname = new URL(normalizedUrl).hostname;
|
|
29
29
|
const outputDir = join(resolve(opts.output), hostname);
|
|
30
|
-
console.log(
|
|
31
|
-
console.log(
|
|
30
|
+
console.log(styleText("gray", ` Target : ${url}`));
|
|
31
|
+
console.log(styleText("gray", ` Output : ${outputDir}`));
|
|
32
32
|
console.log();
|
|
33
33
|
const validFormats = new Set(["md", "html", "json", "pdf"]);
|
|
34
34
|
const formats = opts.format
|
|
@@ -36,7 +36,7 @@ program
|
|
|
36
36
|
.map((f) => f.trim().toLowerCase())
|
|
37
37
|
.filter((f) => validFormats.has(f));
|
|
38
38
|
if (formats.length === 0) {
|
|
39
|
-
console.error(
|
|
39
|
+
console.error(styleText("red", " Invalid --format value. Valid options: md, html, json, pdf"));
|
|
40
40
|
process.exit(2);
|
|
41
41
|
}
|
|
42
42
|
const options = {
|
|
@@ -48,27 +48,27 @@ program
|
|
|
48
48
|
verbose: opts.verbose,
|
|
49
49
|
formats,
|
|
50
50
|
};
|
|
51
|
-
const spinner =
|
|
51
|
+
const spinner = createSpinner("Launching browser...").start();
|
|
52
52
|
try {
|
|
53
53
|
const scanner = new Scanner(options);
|
|
54
|
-
spinner.text
|
|
54
|
+
spinner.update({ text: "Loading page (before interaction)..." });
|
|
55
55
|
const result = await scanner.run((phase) => {
|
|
56
|
-
spinner.text
|
|
56
|
+
spinner.update({ text: phase });
|
|
57
57
|
});
|
|
58
|
-
spinner.
|
|
58
|
+
spinner.success({ text: "Scan complete" });
|
|
59
59
|
console.log();
|
|
60
60
|
const generator = new ReportGenerator(options);
|
|
61
61
|
const paths = await generator.generate(result);
|
|
62
|
-
console.log(
|
|
62
|
+
console.log(styleText("bold", ` Compliance score: ${formatScore(result.compliance.total)} ${result.compliance.grade}`));
|
|
63
63
|
console.log();
|
|
64
64
|
if (result.compliance.issues.length > 0) {
|
|
65
|
-
console.log(
|
|
65
|
+
console.log(styleText("yellow", ` ${result.compliance.issues.length} issue(s) detected:`));
|
|
66
66
|
for (const issue of result.compliance.issues.slice(0, 5)) {
|
|
67
|
-
const icon = issue.severity === "critical" ?
|
|
67
|
+
const icon = issue.severity === "critical" ? styleText("red", "✗") : styleText("yellow", "⚠");
|
|
68
68
|
console.log(` ${icon} ${issue.description}`);
|
|
69
69
|
}
|
|
70
70
|
if (result.compliance.issues.length > 5) {
|
|
71
|
-
console.log(
|
|
71
|
+
console.log(styleText("gray", ` ... and ${result.compliance.issues.length - 5} more (see report)`));
|
|
72
72
|
}
|
|
73
73
|
console.log();
|
|
74
74
|
}
|
|
@@ -79,16 +79,16 @@ program
|
|
|
79
79
|
pdf: "PDF",
|
|
80
80
|
};
|
|
81
81
|
for (const [fmt, path] of Object.entries(paths)) {
|
|
82
|
-
console.log(
|
|
82
|
+
console.log(styleText("green", ` ${(labels[fmt] ?? fmt).padEnd(8)} ${path}`));
|
|
83
83
|
}
|
|
84
84
|
console.log();
|
|
85
85
|
process.exit(result.compliance.grade === "F" ? 1 : 0);
|
|
86
86
|
}
|
|
87
87
|
catch (err) {
|
|
88
|
-
spinner.
|
|
89
|
-
console.error(
|
|
88
|
+
spinner.error({ text: "Scan failed" });
|
|
89
|
+
console.error(styleText("red", `\n Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
90
90
|
if (opts.verbose && err instanceof Error && err.stack) {
|
|
91
|
-
console.error(
|
|
91
|
+
console.error(styleText("gray", err.stack));
|
|
92
92
|
}
|
|
93
93
|
process.exit(2);
|
|
94
94
|
}
|
|
@@ -103,9 +103,9 @@ program
|
|
|
103
103
|
const cat = entry.category;
|
|
104
104
|
categories.set(cat, (categories.get(cat) ?? 0) + 1);
|
|
105
105
|
}
|
|
106
|
-
console.log(
|
|
106
|
+
console.log(styleText("bold", "\n Built-in tracker database:"));
|
|
107
107
|
for (const [cat, count] of categories.entries()) {
|
|
108
|
-
console.log(` ${
|
|
108
|
+
console.log(` ${styleText("cyan", cat.padEnd(20))} ${count} domains`);
|
|
109
109
|
}
|
|
110
110
|
console.log(`\n Total: ${Object.keys(TRACKER_DB).length} tracked domains\n`);
|
|
111
111
|
});
|
|
@@ -118,12 +118,12 @@ function normalizeUrl(url) {
|
|
|
118
118
|
}
|
|
119
119
|
function formatScore(score) {
|
|
120
120
|
const colored = score >= 80
|
|
121
|
-
?
|
|
121
|
+
? styleText("green", String(score))
|
|
122
122
|
: score >= 60
|
|
123
|
-
?
|
|
123
|
+
? styleText("yellow", String(score))
|
|
124
124
|
: score >= 40
|
|
125
|
-
?
|
|
126
|
-
:
|
|
125
|
+
? styleText("yellowBright", String(score))
|
|
126
|
+
: styleText("red", String(score));
|
|
127
127
|
return `${colored}/100`;
|
|
128
128
|
}
|
|
129
129
|
//# sourceMappingURL=cli.js.map
|
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,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,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,CACL,wBAAwB,EACxB,uDAAuD,EACvD,QAAQ,CACT;KACA,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,IAAI,EAAE,EAAE;IAClC,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,yCAAyC,CAAC,CAAC,CAAC;IAC1E,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,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,cAAc,SAAS,EAAE,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,YAAY,GAAG,IAAI,GAAG,CAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAI,IAAI,CAAC,MAAiB;SACpC,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAiB,CAAC,CAAC,CAAC;IAEzE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CACX,SAAS,CAAC,KAAK,EAAE,8DAA8D,CAAC,CACjF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,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;QACrB,OAAO;KACR,CAAC;IAEF,MAAM,OAAO,GAAG,aAAa,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,CAAC;IAE9D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;QAErC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,sCAAsC,EAAE,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACzC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE/C,OAAO,CAAC,GAAG,CACT,SAAS,CACP,MAAM,EACN,uBAAuB,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,CACzF,CACF,CAAC;QACF,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,qBAAqB,CAAC,CAAC,CAAC;YAC5F,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACzD,MAAM,IAAI,GACR,KAAK,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBACnF,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxC,OAAO,CAAC,GAAG,CACT,SAAS,CACP,MAAM,EACN,eAAe,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,oBAAoB,CACvE,CACF,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAA2B;YACrC,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,GAAG,EAAE,KAAK;SACX,CAAC;QACF,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;QACjF,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,KAAK,CACX,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CACnF,CAAC;QACF,IAAI,IAAI,CAAC,OAAO,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACtD,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC3B,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,gCAAgC,CAAC,CAAC,CAAC;IACjE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,OAAO,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,oBAAoB,CAAC,CAAC;AAChF,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9D,OAAO,WAAW,GAAG,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,OAAO,GACX,KAAK,IAAI,EAAE;QACT,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC,CAAC,KAAK,IAAI,EAAE;YACX,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC,CAAC,KAAK,IAAI,EAAE;gBACX,CAAC,CAAC,SAAS,CAAC,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC1C,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,OAAO,GAAG,OAAO,MAAM,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slashgear/gdpr-cookie-scanner",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "CLI tool to scan websites for GDPR cookie consent compliance",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compliance",
|
|
@@ -32,10 +32,9 @@
|
|
|
32
32
|
"registry": "https://registry.npmjs.org"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"
|
|
36
|
-
"commander": "^12.1.0",
|
|
35
|
+
"commander": "^14.0.3",
|
|
37
36
|
"marked": "^17.0.3",
|
|
38
|
-
"
|
|
37
|
+
"nanospinner": "^1.2.2",
|
|
39
38
|
"playwright": "^1.49.0"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
package/src/cli.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import { styleText } from "node:util";
|
|
4
|
+
import { createSpinner } from "nanospinner";
|
|
5
5
|
import { join, resolve } from "path";
|
|
6
6
|
import { Scanner } from "./scanner/index.js";
|
|
7
7
|
import { ReportGenerator } from "./report/generator.js";
|
|
@@ -30,14 +30,14 @@ program
|
|
|
30
30
|
)
|
|
31
31
|
.action(async (url: string, opts) => {
|
|
32
32
|
console.log();
|
|
33
|
-
console.log(
|
|
34
|
-
console.log(
|
|
33
|
+
console.log(styleText(["bold", "blue"], " GDPR Cookie Scanner"));
|
|
34
|
+
console.log(styleText("gray", " ─────────────────────────────────────"));
|
|
35
35
|
const normalizedUrl = normalizeUrl(url);
|
|
36
36
|
const hostname = new URL(normalizedUrl).hostname;
|
|
37
37
|
const outputDir = join(resolve(opts.output), hostname);
|
|
38
38
|
|
|
39
|
-
console.log(
|
|
40
|
-
console.log(
|
|
39
|
+
console.log(styleText("gray", ` Target : ${url}`));
|
|
40
|
+
console.log(styleText("gray", ` Output : ${outputDir}`));
|
|
41
41
|
console.log();
|
|
42
42
|
|
|
43
43
|
const validFormats = new Set<ReportFormat>(["md", "html", "json", "pdf"]);
|
|
@@ -47,7 +47,9 @@ program
|
|
|
47
47
|
.filter((f): f is ReportFormat => validFormats.has(f as ReportFormat));
|
|
48
48
|
|
|
49
49
|
if (formats.length === 0) {
|
|
50
|
-
console.error(
|
|
50
|
+
console.error(
|
|
51
|
+
styleText("red", " Invalid --format value. Valid options: md, html, json, pdf"),
|
|
52
|
+
);
|
|
51
53
|
process.exit(2);
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -61,38 +63,43 @@ program
|
|
|
61
63
|
formats,
|
|
62
64
|
};
|
|
63
65
|
|
|
64
|
-
const spinner =
|
|
66
|
+
const spinner = createSpinner("Launching browser...").start();
|
|
65
67
|
|
|
66
68
|
try {
|
|
67
69
|
const scanner = new Scanner(options);
|
|
68
70
|
|
|
69
|
-
spinner.text
|
|
71
|
+
spinner.update({ text: "Loading page (before interaction)..." });
|
|
70
72
|
const result = await scanner.run((phase) => {
|
|
71
|
-
spinner.text
|
|
73
|
+
spinner.update({ text: phase });
|
|
72
74
|
});
|
|
73
75
|
|
|
74
|
-
spinner.
|
|
76
|
+
spinner.success({ text: "Scan complete" });
|
|
75
77
|
console.log();
|
|
76
78
|
|
|
77
79
|
const generator = new ReportGenerator(options);
|
|
78
80
|
const paths = await generator.generate(result);
|
|
79
81
|
|
|
80
82
|
console.log(
|
|
81
|
-
|
|
83
|
+
styleText(
|
|
84
|
+
"bold",
|
|
82
85
|
` Compliance score: ${formatScore(result.compliance.total)} ${result.compliance.grade}`,
|
|
83
86
|
),
|
|
84
87
|
);
|
|
85
88
|
console.log();
|
|
86
89
|
|
|
87
90
|
if (result.compliance.issues.length > 0) {
|
|
88
|
-
console.log(
|
|
91
|
+
console.log(styleText("yellow", ` ${result.compliance.issues.length} issue(s) detected:`));
|
|
89
92
|
for (const issue of result.compliance.issues.slice(0, 5)) {
|
|
90
|
-
const icon =
|
|
93
|
+
const icon =
|
|
94
|
+
issue.severity === "critical" ? styleText("red", "✗") : styleText("yellow", "⚠");
|
|
91
95
|
console.log(` ${icon} ${issue.description}`);
|
|
92
96
|
}
|
|
93
97
|
if (result.compliance.issues.length > 5) {
|
|
94
98
|
console.log(
|
|
95
|
-
|
|
99
|
+
styleText(
|
|
100
|
+
"gray",
|
|
101
|
+
` ... and ${result.compliance.issues.length - 5} more (see report)`,
|
|
102
|
+
),
|
|
96
103
|
);
|
|
97
104
|
}
|
|
98
105
|
console.log();
|
|
@@ -105,16 +112,18 @@ program
|
|
|
105
112
|
pdf: "PDF",
|
|
106
113
|
};
|
|
107
114
|
for (const [fmt, path] of Object.entries(paths)) {
|
|
108
|
-
console.log(
|
|
115
|
+
console.log(styleText("green", ` ${(labels[fmt] ?? fmt).padEnd(8)} ${path}`));
|
|
109
116
|
}
|
|
110
117
|
console.log();
|
|
111
118
|
|
|
112
119
|
process.exit(result.compliance.grade === "F" ? 1 : 0);
|
|
113
120
|
} catch (err) {
|
|
114
|
-
spinner.
|
|
115
|
-
console.error(
|
|
121
|
+
spinner.error({ text: "Scan failed" });
|
|
122
|
+
console.error(
|
|
123
|
+
styleText("red", `\n Error: ${err instanceof Error ? err.message : String(err)}`),
|
|
124
|
+
);
|
|
116
125
|
if (opts.verbose && err instanceof Error && err.stack) {
|
|
117
|
-
console.error(
|
|
126
|
+
console.error(styleText("gray", err.stack));
|
|
118
127
|
}
|
|
119
128
|
process.exit(2);
|
|
120
129
|
}
|
|
@@ -130,9 +139,9 @@ program
|
|
|
130
139
|
const cat = entry.category;
|
|
131
140
|
categories.set(cat, (categories.get(cat) ?? 0) + 1);
|
|
132
141
|
}
|
|
133
|
-
console.log(
|
|
142
|
+
console.log(styleText("bold", "\n Built-in tracker database:"));
|
|
134
143
|
for (const [cat, count] of categories.entries()) {
|
|
135
|
-
console.log(` ${
|
|
144
|
+
console.log(` ${styleText("cyan", cat.padEnd(20))} ${count} domains`);
|
|
136
145
|
}
|
|
137
146
|
console.log(`\n Total: ${Object.keys(TRACKER_DB).length} tracked domains\n`);
|
|
138
147
|
});
|
|
@@ -149,11 +158,11 @@ function normalizeUrl(url: string): string {
|
|
|
149
158
|
function formatScore(score: number): string {
|
|
150
159
|
const colored =
|
|
151
160
|
score >= 80
|
|
152
|
-
?
|
|
161
|
+
? styleText("green", String(score))
|
|
153
162
|
: score >= 60
|
|
154
|
-
?
|
|
163
|
+
? styleText("yellow", String(score))
|
|
155
164
|
: score >= 40
|
|
156
|
-
?
|
|
157
|
-
:
|
|
165
|
+
? styleText("yellowBright", String(score))
|
|
166
|
+
: styleText("red", String(score));
|
|
158
167
|
return `${colored}/100`;
|
|
159
168
|
}
|