@slashgear/gdpr-cookie-scanner 3.8.1 → 3.8.2
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/ci.yml +17 -11
- package/.github/workflows/release.yml +6 -7
- package/.github/workflows/update-cookie-db.yml +9 -10
- package/.github/workflows/update-trackers.yml +8 -9
- package/.github/workflows/website.yml +18 -60
- package/CHANGELOG.md +12 -0
- package/CONTRIBUTING.md +1 -1
- package/Dockerfile +14 -16
- package/README.md +3 -3
- package/bun.lock +322 -0
- package/dist/cli.js +0 -0
- package/package.json +22 -25
- package/tests/analyzers/colour.test.ts +1 -1
- package/tests/analyzers/compliance.test.ts +1 -1
- package/tests/analyzers/tcf-decoder.test.ts +1 -1
- package/tests/analyzers/wording.test.ts +1 -1
- package/tests/classifiers/cookie-classifier.test.ts +1 -1
- package/tests/classifiers/network-classifier.test.ts +1 -1
- package/tests/e2e/scanner.test.ts +35 -47
- package/tests/scanner/button-classification.test.ts +1 -1
- package/tests/scanner/contrast-ratio.test.ts +1 -1
- package/tests/unit/compliance.test.ts +1 -1
- package/tests/unit/cookie-classifier.test.ts +1 -1
- package/tests/unit/network-classifier.test.ts +1 -1
- package/tests/unit/wording.test.ts +1 -1
- package/pnpm-workspace.yaml +0 -3
- package/vitest.config.ts +0 -9
- package/website/Dockerfile +0 -55
- package/website/node_modules/.bin/oxfmt +0 -21
- package/website/node_modules/.bin/oxlint +0 -21
- package/website/node_modules/.bin/tsc +0 -21
- package/website/node_modules/.bin/tsserver +0 -21
- package/website/node_modules/.bin/tsx +0 -21
- package/website/package.json +0 -29
- package/website/src/index.ts +0 -15
- package/website/src/security.ts +0 -26
- package/website/tsconfig.json +0 -14
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from "
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from "bun:test";
|
|
2
2
|
import { mkdtemp, rm } from "fs/promises";
|
|
3
3
|
import { tmpdir } from "os";
|
|
4
4
|
import { join } from "path";
|
|
5
|
+
import type { ScanResult } from "../../src/types.js";
|
|
5
6
|
import { Scanner } from "../../src/scanner/index.js";
|
|
6
7
|
import { startTestServer, type TestServer } from "../helpers/test-server.js";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
const E2E_TIMEOUT = 60_000;
|
|
10
|
-
|
|
11
|
-
describe("Scanner E2E", { timeout: E2E_TIMEOUT }, () => {
|
|
9
|
+
describe("Scanner E2E", () => {
|
|
12
10
|
let server: TestServer;
|
|
13
11
|
let outputDir: string;
|
|
14
12
|
|
|
@@ -34,98 +32,88 @@ describe("Scanner E2E", { timeout: E2E_TIMEOUT }, () => {
|
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
describe("compliant-site.html", () => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
let result: ScanResult;
|
|
36
|
+
|
|
37
|
+
beforeAll(async () => {
|
|
38
|
+
result = await new Scanner(makeOptions("compliant-site.html")).run();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("detects the consent modal", () => {
|
|
40
42
|
expect(result.modal.detected).toBe(true);
|
|
41
43
|
});
|
|
42
44
|
|
|
43
|
-
it("finds both accept and reject buttons",
|
|
44
|
-
const scanner = new Scanner(makeOptions("compliant-site.html"));
|
|
45
|
-
const result = await scanner.run();
|
|
45
|
+
it("finds both accept and reject buttons", () => {
|
|
46
46
|
const types = result.modal.buttons.map((b) => b.type);
|
|
47
47
|
expect(types).toContain("accept");
|
|
48
48
|
expect(types).toContain("reject");
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
it("finds the privacy policy link in the modal",
|
|
52
|
-
const scanner = new Scanner(makeOptions("compliant-site.html"));
|
|
53
|
-
const result = await scanner.run();
|
|
51
|
+
it("finds the privacy policy link in the modal", () => {
|
|
54
52
|
expect(result.modal.privacyPolicyUrl).toBeTruthy();
|
|
55
53
|
});
|
|
56
54
|
|
|
57
|
-
it("finds a privacy policy link on the page",
|
|
58
|
-
const scanner = new Scanner(makeOptions("compliant-site.html"));
|
|
59
|
-
const result = await scanner.run();
|
|
55
|
+
it("finds a privacy policy link on the page", () => {
|
|
60
56
|
expect(result.privacyPolicyUrl).toBeTruthy();
|
|
61
57
|
});
|
|
62
58
|
|
|
63
|
-
it("assigns a passing compliance grade (A or B)",
|
|
64
|
-
const scanner = new Scanner(makeOptions("compliant-site.html"));
|
|
65
|
-
const result = await scanner.run();
|
|
59
|
+
it("assigns a passing compliance grade (A or B)", () => {
|
|
66
60
|
expect(["A", "B"]).toContain(result.compliance.grade);
|
|
67
61
|
});
|
|
68
62
|
|
|
69
|
-
it("does not flag pre-consent cookies",
|
|
70
|
-
const scanner = new Scanner(makeOptions("compliant-site.html"));
|
|
71
|
-
const result = await scanner.run();
|
|
63
|
+
it("does not flag pre-consent cookies", () => {
|
|
72
64
|
const illegalPreConsent = result.cookiesBeforeInteraction.filter((c) => c.requiresConsent);
|
|
73
65
|
expect(illegalPreConsent).toHaveLength(0);
|
|
74
66
|
});
|
|
75
67
|
});
|
|
76
68
|
|
|
77
69
|
describe("non-compliant-site.html", () => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
let result: ScanResult;
|
|
71
|
+
|
|
72
|
+
beforeAll(async () => {
|
|
73
|
+
result = await new Scanner(makeOptions("non-compliant-site.html")).run();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("detects the consent modal", () => {
|
|
81
77
|
expect(result.modal.detected).toBe(true);
|
|
82
78
|
});
|
|
83
79
|
|
|
84
|
-
it("detects _ga cookie set before any interaction",
|
|
85
|
-
const scanner = new Scanner(makeOptions("non-compliant-site.html"));
|
|
86
|
-
const result = await scanner.run();
|
|
80
|
+
it("detects _ga cookie set before any interaction", () => {
|
|
87
81
|
const gaBeforeInteraction = result.cookiesBeforeInteraction.some(
|
|
88
82
|
(c) => c.name === "_ga" && c.requiresConsent,
|
|
89
83
|
);
|
|
90
84
|
expect(gaBeforeInteraction).toBe(true);
|
|
91
85
|
});
|
|
92
86
|
|
|
93
|
-
it("raises an auto-consent issue for pre-interaction cookies",
|
|
94
|
-
const scanner = new Scanner(makeOptions("non-compliant-site.html"));
|
|
95
|
-
const result = await scanner.run();
|
|
87
|
+
it("raises an auto-consent issue for pre-interaction cookies", () => {
|
|
96
88
|
const issue = result.compliance.issues.find((i) => i.type === "auto-consent");
|
|
97
89
|
expect(issue).toBeDefined();
|
|
98
90
|
});
|
|
99
91
|
|
|
100
|
-
it("assigns a failing grade (C, D, or F)",
|
|
101
|
-
const scanner = new Scanner(makeOptions("non-compliant-site.html"));
|
|
102
|
-
const result = await scanner.run();
|
|
92
|
+
it("assigns a failing grade (C, D, or F)", () => {
|
|
103
93
|
expect(["C", "D", "F"]).toContain(result.compliance.grade);
|
|
104
94
|
});
|
|
105
95
|
});
|
|
106
96
|
|
|
107
97
|
describe("no-modal-site.html", () => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
let result: ScanResult;
|
|
99
|
+
|
|
100
|
+
beforeAll(async () => {
|
|
101
|
+
result = await new Scanner(makeOptions("no-modal-site.html")).run();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("reports modal as not detected", () => {
|
|
111
105
|
expect(result.modal.detected).toBe(false);
|
|
112
106
|
});
|
|
113
107
|
|
|
114
|
-
it("still finds the page-level privacy policy link",
|
|
115
|
-
const scanner = new Scanner(makeOptions("no-modal-site.html"));
|
|
116
|
-
const result = await scanner.run();
|
|
108
|
+
it("still finds the page-level privacy policy link", () => {
|
|
117
109
|
expect(result.privacyPolicyUrl).toBeTruthy();
|
|
118
110
|
});
|
|
119
111
|
|
|
120
|
-
it("assigns grade A — no consent mechanism needed for a tracking-free site",
|
|
121
|
-
const scanner = new Scanner(makeOptions("no-modal-site.html"));
|
|
122
|
-
const result = await scanner.run();
|
|
112
|
+
it("assigns grade A — no consent mechanism needed for a tracking-free site", () => {
|
|
123
113
|
expect(result.compliance.grade).toBe("A");
|
|
124
114
|
});
|
|
125
115
|
|
|
126
|
-
it("raises no compliance issues for a tracking-free site without a modal",
|
|
127
|
-
const scanner = new Scanner(makeOptions("no-modal-site.html"));
|
|
128
|
-
const result = await scanner.run();
|
|
116
|
+
it("raises no compliance issues for a tracking-free site without a modal", () => {
|
|
129
117
|
expect(result.compliance.issues).toHaveLength(0);
|
|
130
118
|
});
|
|
131
119
|
});
|
package/pnpm-workspace.yaml
DELETED
package/vitest.config.ts
DELETED
package/website/Dockerfile
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Build context: repo root (docker build -f website/Dockerfile .)
|
|
2
|
-
|
|
3
|
-
# ── Stage 1: build ────────────────────────────────────────────────────────────
|
|
4
|
-
FROM node:24-slim AS builder
|
|
5
|
-
WORKDIR /app
|
|
6
|
-
|
|
7
|
-
# Install compression tools (brotli, zstd, zopfli)
|
|
8
|
-
RUN apt-get update && apt-get install -y --no-install-recommends brotli zstd zopfli \
|
|
9
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
10
|
-
|
|
11
|
-
RUN npm install -g pnpm@latest
|
|
12
|
-
|
|
13
|
-
# Copy workspace manifests for layer caching
|
|
14
|
-
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
15
|
-
COPY website/package.json ./website/
|
|
16
|
-
|
|
17
|
-
# Install website deps only (no playwright, no CLI deps)
|
|
18
|
-
RUN pnpm install --frozen-lockfile --filter @slashgear/gdpr-website
|
|
19
|
-
|
|
20
|
-
# Copy source and compile
|
|
21
|
-
COPY website/tsconfig.json ./website/
|
|
22
|
-
COPY website/src ./website/src
|
|
23
|
-
RUN pnpm --filter @slashgear/gdpr-website build
|
|
24
|
-
|
|
25
|
-
# Copy static assets and precompress them
|
|
26
|
-
COPY website/public ./website/public
|
|
27
|
-
RUN find /app/website/public -type f \( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.json" -o -name "*.svg" \) | \
|
|
28
|
-
while read f; do \
|
|
29
|
-
brotli --best -k "$f"; \
|
|
30
|
-
zstd --ultra -22 -k "$f"; \
|
|
31
|
-
zopfli --gzip "$f"; \
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
# ── Stage 2: runtime ──────────────────────────────────────────────────────────
|
|
35
|
-
FROM node:24-slim
|
|
36
|
-
WORKDIR /app
|
|
37
|
-
ENV NODE_ENV=production
|
|
38
|
-
|
|
39
|
-
RUN npm install -g pnpm@latest
|
|
40
|
-
|
|
41
|
-
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
42
|
-
COPY website/package.json ./website/
|
|
43
|
-
RUN pnpm install --prod --frozen-lockfile --filter @slashgear/gdpr-website
|
|
44
|
-
|
|
45
|
-
# Static assets with precompressed variants (.br, .zst, .gz)
|
|
46
|
-
COPY --from=builder /app/website/public ./website/public
|
|
47
|
-
|
|
48
|
-
# Compiled server
|
|
49
|
-
COPY --from=builder /app/website/dist ./website/dist
|
|
50
|
-
|
|
51
|
-
WORKDIR /app/website
|
|
52
|
-
ENV PORT=8080
|
|
53
|
-
EXPOSE 8080
|
|
54
|
-
|
|
55
|
-
CMD ["node", "dist/index.js"]
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules/oxfmt/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules/oxfmt/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../oxfmt/bin/oxfmt" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../oxfmt/bin/oxfmt" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules/oxlint/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules/oxlint/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../oxlint/bin/oxlint" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../oxlint/bin/oxlint" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
21
|
-
fi
|
package/website/package.json
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@slashgear/gdpr-website",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "Web interface for gdpr-cookie-scanner",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"dev": "tsx src/index.ts",
|
|
10
|
-
"start": "node dist/index.js",
|
|
11
|
-
"typecheck": "tsc --noEmit",
|
|
12
|
-
"lint": "oxlint .",
|
|
13
|
-
"format": "oxfmt ."
|
|
14
|
-
},
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@hono/node-server": "^1.14.0",
|
|
17
|
-
"hono": "^4.7.0"
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@types/node": "^22.0.0",
|
|
21
|
-
"oxfmt": "^0.34.0",
|
|
22
|
-
"oxlint": "^1.48.0",
|
|
23
|
-
"tsx": "^4.19.0",
|
|
24
|
-
"typescript": "^5.5.0"
|
|
25
|
-
},
|
|
26
|
-
"engines": {
|
|
27
|
-
"node": ">=24.0.0"
|
|
28
|
-
}
|
|
29
|
-
}
|
package/website/src/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { serve } from "@hono/node-server";
|
|
2
|
-
import { serveStatic } from "@hono/node-server/serve-static";
|
|
3
|
-
import { Hono } from "hono";
|
|
4
|
-
import { securityHeaders } from "./security.js";
|
|
5
|
-
|
|
6
|
-
const app = new Hono();
|
|
7
|
-
|
|
8
|
-
app.use("/*", securityHeaders);
|
|
9
|
-
app.use("/*", serveStatic({ root: "./public", precompressed: true }));
|
|
10
|
-
|
|
11
|
-
const port = Number(process.env.PORT) || 8080;
|
|
12
|
-
|
|
13
|
-
serve({ fetch: app.fetch, port }, (info) => {
|
|
14
|
-
console.log(`Server running on http://localhost:${info.port}`);
|
|
15
|
-
});
|
package/website/src/security.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { MiddlewareHandler } from "hono";
|
|
2
|
-
|
|
3
|
-
const CSP = [
|
|
4
|
-
"default-src 'self'",
|
|
5
|
-
"script-src 'self'",
|
|
6
|
-
"style-src 'self' 'unsafe-inline'",
|
|
7
|
-
"img-src 'self' data: https:",
|
|
8
|
-
"font-src 'self'",
|
|
9
|
-
"connect-src 'self'",
|
|
10
|
-
"frame-ancestors 'none'",
|
|
11
|
-
"base-uri 'self'",
|
|
12
|
-
"form-action 'self'",
|
|
13
|
-
"upgrade-insecure-requests",
|
|
14
|
-
].join("; ");
|
|
15
|
-
|
|
16
|
-
export const securityHeaders: MiddlewareHandler = async (c, next) => {
|
|
17
|
-
await next();
|
|
18
|
-
c.header("X-Frame-Options", "DENY");
|
|
19
|
-
c.header("X-Content-Type-Options", "nosniff");
|
|
20
|
-
c.header("X-XSS-Protection", "1; mode=block");
|
|
21
|
-
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
22
|
-
c.header("Permissions-Policy", "geolocation=(), microphone=(), camera=()");
|
|
23
|
-
if (process.env.NODE_ENV === "production") {
|
|
24
|
-
c.header("Content-Security-Policy", CSP);
|
|
25
|
-
}
|
|
26
|
-
};
|
package/website/tsconfig.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": "src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true
|
|
11
|
-
},
|
|
12
|
-
"include": ["src/**/*"],
|
|
13
|
-
"exclude": ["node_modules", "dist"]
|
|
14
|
-
}
|