cuonztech-privacy-chaos-gate 0.2.0 → 0.2.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/LICENSE +97 -0
- package/README.md +197 -30
- package/action.yml +187 -26
- package/dist/chunk-42D7PLVP.js +9146 -0
- package/dist/cli.js +96 -93
- package/dist/index.d.ts +710 -88
- package/dist/index.js +41 -12
- package/docs/BRAND-PILOT-EVIDENCE.md +41 -49
- package/package.json +6 -5
- package/dist/chunk-FN3QUFUZ.js +0 -36
- package/dist/chunk-FN3QUFUZ.js.map +0 -1
- package/dist/chunk-T5D6BUAC.js +0 -4514
- package/dist/chunk-T5D6BUAC.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/resolveGrant-6U6VG3DM.js +0 -230
- package/dist/resolveGrant-6U6VG3DM.js.map +0 -1
- package/docs/LIZENZ-KAUFFLUSS.md +0 -105
- package/docs/PREISMODELL.md +0 -63
package/dist/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
CORE_SCENARIOS,
|
|
3
3
|
ChaosScanner,
|
|
4
4
|
ChaosScenarioSchema,
|
|
5
|
+
ENV_FILE_KEYS_HELP,
|
|
6
|
+
EXIT,
|
|
5
7
|
EvidenceRecordSchema,
|
|
6
8
|
EvidenceStatusSchema,
|
|
7
9
|
FilePatchSchema,
|
|
8
10
|
GateConfigSchema,
|
|
11
|
+
JurisdictionCodeSchema,
|
|
12
|
+
LICENSE_CONTACT,
|
|
9
13
|
LeakReportSchema,
|
|
10
14
|
PrivacyChaosGate,
|
|
11
15
|
PullRequestResultSchema,
|
|
@@ -16,37 +20,52 @@ import {
|
|
|
16
20
|
StorageSnapshotSchema,
|
|
17
21
|
TrackerCategorySchema,
|
|
18
22
|
TrackerViolationSchema,
|
|
23
|
+
assessReport,
|
|
19
24
|
buildCoverHtml,
|
|
20
25
|
buildEvidenceHtml,
|
|
21
26
|
buildEvidenceMarkdown,
|
|
22
|
-
|
|
27
|
+
checkTargetReachable,
|
|
23
28
|
codeSolutionsFor,
|
|
24
29
|
deriveReportFacts,
|
|
30
|
+
evidenceLabelOf,
|
|
25
31
|
findingsCountText,
|
|
32
|
+
gateNotesOf,
|
|
26
33
|
groupFindings,
|
|
27
|
-
|
|
34
|
+
isEnvKeyAllowedFromFile,
|
|
35
|
+
isLoopbackTarget,
|
|
36
|
+
licenseSkipText,
|
|
37
|
+
loadProjectEnv,
|
|
38
|
+
parseGateConfig,
|
|
28
39
|
problemsTextOf,
|
|
29
40
|
renderDeluxeCombined,
|
|
30
41
|
renderDeluxePdf,
|
|
31
42
|
reproductionText,
|
|
43
|
+
requestedLicensedFeatures,
|
|
44
|
+
resolveEntitlement,
|
|
32
45
|
resolveGateConfig,
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
resolveReportGate,
|
|
47
|
+
statusLabelOf,
|
|
48
|
+
uncheckableReasons
|
|
49
|
+
} from "./chunk-42D7PLVP.js";
|
|
35
50
|
|
|
36
51
|
// src/index.ts
|
|
37
52
|
async function runGate(optionsOrConfig) {
|
|
38
|
-
const
|
|
53
|
+
const input = "targetUrl" in optionsOrConfig && typeof optionsOrConfig.targetUrl === "string" ? optionsOrConfig : resolveGateConfig(optionsOrConfig);
|
|
39
54
|
const gate = new PrivacyChaosGate();
|
|
40
|
-
return gate.run(
|
|
55
|
+
return gate.run(input);
|
|
41
56
|
}
|
|
42
57
|
export {
|
|
43
|
-
|
|
58
|
+
CORE_SCENARIOS,
|
|
44
59
|
ChaosScanner,
|
|
45
60
|
ChaosScenarioSchema,
|
|
61
|
+
ENV_FILE_KEYS_HELP,
|
|
62
|
+
EXIT,
|
|
46
63
|
EvidenceRecordSchema,
|
|
47
64
|
EvidenceStatusSchema,
|
|
48
65
|
FilePatchSchema,
|
|
49
66
|
GateConfigSchema,
|
|
67
|
+
JurisdictionCodeSchema,
|
|
68
|
+
LICENSE_CONTACT,
|
|
50
69
|
LeakReportSchema,
|
|
51
70
|
PrivacyChaosGate,
|
|
52
71
|
PullRequestResultSchema,
|
|
@@ -57,21 +76,31 @@ export {
|
|
|
57
76
|
StorageSnapshotSchema,
|
|
58
77
|
TrackerCategorySchema,
|
|
59
78
|
TrackerViolationSchema,
|
|
79
|
+
assessReport,
|
|
60
80
|
buildCoverHtml,
|
|
61
81
|
buildEvidenceHtml,
|
|
62
82
|
buildEvidenceMarkdown,
|
|
63
|
-
|
|
83
|
+
checkTargetReachable,
|
|
64
84
|
codeSolutionsFor,
|
|
65
85
|
deriveReportFacts,
|
|
86
|
+
evidenceLabelOf,
|
|
66
87
|
findingsCountText,
|
|
88
|
+
gateNotesOf,
|
|
67
89
|
groupFindings,
|
|
68
|
-
|
|
90
|
+
isEnvKeyAllowedFromFile,
|
|
91
|
+
isLoopbackTarget,
|
|
92
|
+
licenseSkipText,
|
|
93
|
+
loadProjectEnv,
|
|
94
|
+
parseGateConfig,
|
|
69
95
|
problemsTextOf,
|
|
70
96
|
renderDeluxeCombined,
|
|
71
97
|
renderDeluxePdf,
|
|
72
98
|
reproductionText,
|
|
99
|
+
requestedLicensedFeatures,
|
|
100
|
+
resolveEntitlement,
|
|
73
101
|
resolveGateConfig,
|
|
102
|
+
resolveReportGate,
|
|
74
103
|
runGate,
|
|
75
|
-
statusLabelOf
|
|
104
|
+
statusLabelOf,
|
|
105
|
+
uncheckableReasons
|
|
76
106
|
};
|
|
77
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# Cuonztech Privacy Chaos Gate
|
|
2
|
-
## Evidence Report
|
|
2
|
+
## Evidence Report — Consent-Pre-Consent-Leaks auf pilot-kunde.ch
|
|
3
|
+
|
|
4
|
+
> **BEISPIELBERICHT (Demo):** Dieses Dokument zeigt das Format eines Evidence-Reports an einem
|
|
5
|
+
> **erfundenen Beispiel**. `pilot-kunde.ch`, die Tag-ID `GTM-DEMO01`, das Datum und alle Zahlen sind
|
|
6
|
+
> Platzhalter aus Demo-Daten. Es beschreibt keinen realen Kunden und keine reale Website.
|
|
3
7
|
|
|
4
8
|
**Produkt:** Cuonztech Privacy Chaos Gate (CPCG)
|
|
5
9
|
**Kategorie:** CI-Gate · Chaos-Scanner · Auto-Fix-PR
|
|
6
|
-
**Auftraggeber/Pilot:** Read-only Audit, 20.10.2026
|
|
7
|
-
**Status:** Gate BLOCKED
|
|
10
|
+
**Auftraggeber/Pilot:** Beispiel (Platzhalter), Read-only Audit, 20.10.2026
|
|
11
|
+
**Status:** Gate BLOCKED — 10 Tracker-Leaks vor Einwilligung (Beispielwerte)
|
|
8
12
|
|
|
9
|
-
>
|
|
10
|
-
> Implementierung von Consent-Lösungen
|
|
13
|
+
> ⚠️ **Hinweis / Disclaimer:** CPCG ist ein technisches Hilfsmittel zur Unterstützung bei der
|
|
14
|
+
> Implementierung von Consent-Lösungen — **keine Rechtsberatung** und keine Garantie für
|
|
11
15
|
> DSGVO-/TTDSG-Konformität. Bitte lassen Sie die endgültige Umsetzung anwaltlich prüfen.
|
|
12
16
|
> / CPCG is a technical aid, **not legal advice** and no guarantee of GDPR/ePrivacy compliance.
|
|
13
17
|
|
|
@@ -16,8 +20,8 @@
|
|
|
16
20
|
## 1. Was ist passiert?
|
|
17
21
|
|
|
18
22
|
Die Produktionsseite **pilot-kunde.ch** setzt professionell auf **OneTrust** (`cdn.cookielaw.org`,
|
|
19
|
-
Domain-Script `151e70dd
|
|
20
|
-
(`GTM-DEMO01`) **ungedeckt im HTML-Head**
|
|
23
|
+
Domain-Script `151e70dd-…`). Trotzdem lädt der **Google-Tag-Manager-Bootstrap**
|
|
24
|
+
(`GTM-DEMO01`) **ungedeckt im HTML-Head** — **bevor** das OneTrust-Banner irgendeine
|
|
21
25
|
Entgegennahme von Einwilligung darstellt.
|
|
22
26
|
|
|
23
27
|
Ergebnis des CPCG-Chaos-Scans: **10 Unauthorized Tracker Requests**.
|
|
@@ -47,76 +51,64 @@ Ergebnis des CPCG-Chaos-Scans: **10 Unauthorized Tracker Requests**.
|
|
|
47
51
|
|
|
48
52
|
```html
|
|
49
53
|
<!-- OneTrust Cookies Consent Notice start for pilot-kunde.ch -->
|
|
50
|
-
<script src="https://cdn.cookielaw.org/consent/151e70dd
|
|
51
|
-
<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js"
|
|
54
|
+
<script src="https://cdn.cookielaw.org/consent/151e70dd-…/OtAutoBlock.js"></script>
|
|
55
|
+
<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" …></script>
|
|
52
56
|
|
|
53
|
-
<!-- Google Tag Manager
|
|
54
|
-
<script>(function(w,d,s,l,i){
|
|
57
|
+
<!-- Google Tag Manager — läuft ohne Consent -->
|
|
58
|
+
<script>(function(w,d,s,l,i){ … j.src='https://www.googletagmanager.com/gtm.js?id='+i;
|
|
55
59
|
})(window,document,'script','dataLayer','GTM-DEMO01');</script>
|
|
56
60
|
```
|
|
57
61
|
|
|
58
62
|
---
|
|
59
63
|
|
|
60
|
-
## 3.
|
|
64
|
+
## 3. Einordnung
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
| Cookiebot / Usercentrics / Ketch / Osano | CMP, Banner, Consent-Storage | **CI-Gate + Auto-Fix-PR** |
|
|
65
|
-
| CookieYes / Webxray | Cookie-Scan, Reporting | **Chaos-Szenarien (Fast-Click, Network-Drop) + Fix-PR** |
|
|
66
|
-
| **Cuonztech CPCG** | Pre-Consent-Detektion + Auto-Fix-PR im CI | ”” |
|
|
66
|
+
CMPs prüfen vorrangig die **Konfiguration** (Banner, Kategorien, Consent-Speicherung), CPCG prüft das **Verhalten**
|
|
67
|
+
der laufenden Seite im Browser. CPCG ersetzt kein CMP und keine Rechtsberatung, sondern ergänzt beides.
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
| | Schwerpunkt | Zeitpunkt |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| CMP (typisch) | Konfiguration: Banner, Kategorien, Consent-Speicherung | im Betrieb der Seite |
|
|
72
|
+
| **CuonzTech CPCG** | Verhalten: welche Requests laufen vor und nach der Einwilligung (Fast-Click, Network-Drop u. a.) | im CI vor dem Merge oder als Stichprobe; optional mit Fix-Vorschlag |
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
**Ansatz:** Shift-Left. Nicht erst nach dem Go-Live dokumentieren, sondern vor dem Merge prüfen.
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
---
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
```html
|
|
77
|
-
<script>(function(w,d,s,l,i){ ”¦ j.src='https://www.googletagmanager.com/gtm.js?id='+i; ”¦
|
|
78
|
-
})(window,document,'script','dataLayer','GTM-DEMO01');</script>
|
|
79
|
-
```
|
|
78
|
+
## 4. Fix-Prinzip (nicht ohne Kunden-Freigabe anwenden)
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
window.__cpcgInits = window.__cpcgInits || [];
|
|
90
|
-
window.__cpcgInits.push(function(){
|
|
91
|
-
if (localStorage.getItem('OptanonConsent') !== 'accepted') return;
|
|
92
|
-
gtag('consent','update',{ad_storage:'granted',analytics_storage:'granted'});
|
|
93
|
-
// GTM-Bootstrap erst hier laden ”¦
|
|
94
|
-
});
|
|
95
|
-
</script>
|
|
96
|
-
```
|
|
80
|
+
Das Tracker-Skript darf erst nach der Einwilligung der passenden Kategorie (Statistik/Marketing)
|
|
81
|
+
laden, nicht im Head ohne Consent-Prüfung. Den konkreten Patch erzeugt CPCG im Scan-Lauf mit
|
|
82
|
+
`--auto-fix` und `--source-dir <Quellverzeichnis>`; er steht als Diff im Report. Bei OneTrust und
|
|
83
|
+
Cookiebot liest der Patch die Kategorien automatisch, bei eigenen Bannern meldet die Seite die
|
|
84
|
+
Einwilligung an die eingefügte Runtime. Andere Consent-Plattformen und Tracker, die nicht im
|
|
85
|
+
Quelltext stehen (Tag Manager, Server, CMS), bleiben «manuell zu beheben» (siehe README, Abschnitt
|
|
86
|
+
«Auto-Fix: Grenzen»). Dieses Beispiel enthält bewusst keinen Beispiel-Patch: ein gekürzter Code
|
|
87
|
+
würde nicht dem echten Ausgabeformat entsprechen.
|
|
97
88
|
|
|
98
|
-
**Nach Umsetzung:**
|
|
89
|
+
**Nach Umsetzung:** Ein erneuter Scan muss ein grünes Gate liefern (Exit-Code 0).
|
|
99
90
|
|
|
100
91
|
---
|
|
101
92
|
|
|
102
93
|
## 5. Was der Kunde bekommt (Produkt-Fluss)
|
|
103
94
|
|
|
104
95
|
1. **Online-Kauf** auf cuonztech.ch → Lizenzcode per E-Mail
|
|
105
|
-
2. **Scan:** `npx
|
|
106
|
-
3. **Report** (JSON + Markdown
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
2. **Scan:** `npx cuonztech-privacy-chaos-gate --url <staging>`. Scan und Konsolen-Gate brauchen keine Lizenz.
|
|
97
|
+
3. **Report** (JSON + Markdown/HTML). Den **Kundenreport** (mit `--client`, PDF mit `--report-pdf`) schaltet die Lizenz frei:
|
|
98
|
+
Code per Umgebungsvariable `CPCG_LICENSE` übergeben.
|
|
99
|
+
4. **Auto-Fix-PR** (optional, mit Review-Agent; Commit/PR brauchen eine Lizenz, das lokale Anwenden nicht)
|
|
100
|
+
5. **CI-Gate** im GitHub-Action-Workflow — Merge-Blocker bei Pre-Consent-Leaks
|
|
109
101
|
|
|
110
102
|
---
|
|
111
103
|
|
|
112
104
|
## 6. Nächste Schritte
|
|
113
105
|
|
|
114
106
|
- [ ] Technische Umsetzung Fix (intern oder CPCG Auto-Fix-PR)
|
|
115
|
-
- [ ] Juristische Prüfung (Datenschutzbeauftragte/r)
|
|
107
|
+
- [ ] Juristische Prüfung (Datenschutzbeauftragte/r) — siehe Disclaimer
|
|
116
108
|
- [ ] Rescan + Freigabe
|
|
117
109
|
- [ ] CPCG als CI-Gate in die Pipeline
|
|
118
110
|
|
|
119
111
|
---
|
|
120
112
|
|
|
121
|
-
*© Cuonztech
|
|
113
|
+
*© Cuonztech — Cuonztech Privacy Chaos Gate (CPCG)*
|
|
122
114
|
*Technisches Hilfsmittel, keine Rechtsberatung.*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cuonztech-privacy-chaos-gate",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "CuonzTech Privacy Chaos Gate — CI/CD Consent-Scanner, Chaos-Szenarien und Auto-Fix-PR",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
+
"!dist/**/*.map",
|
|
13
14
|
"action.yml",
|
|
15
|
+
"LICENSE",
|
|
14
16
|
"README.md",
|
|
15
|
-
"docs/BRAND-PILOT-EVIDENCE.md"
|
|
16
|
-
"docs/LIZENZ-KAUFFLUSS.md",
|
|
17
|
-
"docs/PREISMODELL.md"
|
|
17
|
+
"docs/BRAND-PILOT-EVIDENCE.md"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
20
|
"node": ">=20"
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"test": "vitest run",
|
|
37
37
|
"test:watch": "vitest",
|
|
38
38
|
"typecheck": "tsc --noEmit",
|
|
39
|
+
"typecheck:all": "tsc -p tsconfig.test.json --noEmit",
|
|
39
40
|
"prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build",
|
|
40
41
|
"demo": "tsx scripts/scan-demo-portal.mts && tsx scripts/make-deluxe-report.mts && tsx scripts/package-delivery.mts",
|
|
41
42
|
"demo:report": "tsx scripts/make-deluxe-report.mts"
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
"cuonztech"
|
|
53
54
|
],
|
|
54
55
|
"author": "CuonzTech · Carlo Cuonz",
|
|
55
|
-
"license": "
|
|
56
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
56
57
|
"dependencies": {
|
|
57
58
|
"commander": "^12.1.0",
|
|
58
59
|
"dotenv": "^16.4.5",
|
package/dist/chunk-FN3QUFUZ.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// src/core/license/ed25519.ts
|
|
2
|
-
import crypto from "crypto";
|
|
3
|
-
|
|
4
|
-
// src/core/license/publicKey.ts
|
|
5
|
-
var LICENSE_PUBLIC_KEY = "q20XyLRZGURVvMLR6q0SCIc6poLhW73KE5Ds94Yq1FQ=";
|
|
6
|
-
|
|
7
|
-
// src/core/license/ed25519.ts
|
|
8
|
-
var PKCS8_PREFIX = Buffer.from("302e020100300506032b657004220420", "hex");
|
|
9
|
-
var SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
10
|
-
function rawKey(b64, what) {
|
|
11
|
-
const raw = Buffer.from(b64, "base64");
|
|
12
|
-
if (raw.length !== 32) throw new Error(`${what}: erwartet 32 Byte (base64), erhalten ${raw.length}`);
|
|
13
|
-
return raw;
|
|
14
|
-
}
|
|
15
|
-
function defaultPublicKey() {
|
|
16
|
-
return process.env.CPCG_LICENSE_PUBLIC_KEY || LICENSE_PUBLIC_KEY;
|
|
17
|
-
}
|
|
18
|
-
function verifyEd25519(domain, payload, sigB64url, publicKeyB64 = defaultPublicKey()) {
|
|
19
|
-
try {
|
|
20
|
-
const key = crypto.createPublicKey({
|
|
21
|
-
key: Buffer.concat([SPKI_PREFIX, rawKey(publicKeyB64, "Public Key")]),
|
|
22
|
-
format: "der",
|
|
23
|
-
type: "spki"
|
|
24
|
-
});
|
|
25
|
-
const sig = Buffer.from(sigB64url, "base64url");
|
|
26
|
-
return sig.length === 64 && crypto.verify(null, Buffer.from(`${domain}.${payload}`), key, sig);
|
|
27
|
-
} catch {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export {
|
|
33
|
-
defaultPublicKey,
|
|
34
|
-
verifyEd25519
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=chunk-FN3QUFUZ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/license/ed25519.ts","../src/core/license/publicKey.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport { LICENSE_PUBLIC_KEY } from \"./publicKey.js\";\n\n/**\n * Ed25519-Signaturen für Lizenzen und Grants.\n *\n * Der Server signiert mit dem privaten Seed (nur in config.php / KeePass),\n * der Client prüft ausschliesslich mit dem öffentlichen Schlüssel. Wer das CLI\n * besitzt, kann damit nichts ausstellen. Schlüssel sind rohe 32 Byte, base64.\n *\n * Jeder Token-Typ signiert mit eigenem Domain-Präfix, damit eine Lizenz-\n * Signatur nie als Grant (oder umgekehrt) durchgeht.\n */\nexport type SignDomain = \"cpcg-license-v1\" | \"cpcg-grant-v1\";\n\nconst PKCS8_PREFIX = Buffer.from(\"302e020100300506032b657004220420\", \"hex\");\nconst SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\nfunction rawKey(b64: string, what: string): Buffer {\n const raw = Buffer.from(b64, \"base64\");\n if (raw.length !== 32) throw new Error(`${what}: erwartet 32 Byte (base64), erhalten ${raw.length}`);\n return raw;\n}\n\nexport function generateLicenseKeyPair(): { seed: string; publicKey: string } {\n const { privateKey, publicKey } = crypto.generateKeyPairSync(\"ed25519\");\n return {\n seed: privateKey.export({ format: \"der\", type: \"pkcs8\" }).subarray(-32).toString(\"base64\"),\n publicKey: publicKey.export({ format: \"der\", type: \"spki\" }).subarray(-32).toString(\"base64\"),\n };\n}\n\nexport function signEd25519(domain: SignDomain, payload: string, seedB64: string): string {\n const key = crypto.createPrivateKey({\n key: Buffer.concat([PKCS8_PREFIX, rawKey(seedB64, \"CPCG_LICENSE_SIGNING_SEED\")]),\n format: \"der\",\n type: \"pkcs8\",\n });\n return crypto.sign(null, Buffer.from(`${domain}.${payload}`), key).toString(\"base64url\");\n}\n\n/** Öffentlicher Schlüssel: CPCG_LICENSE_PUBLIC_KEY (Tests, Self-Hosting) vor dem eingebetteten. */\nexport function defaultPublicKey(): string {\n return process.env.CPCG_LICENSE_PUBLIC_KEY || LICENSE_PUBLIC_KEY;\n}\n\nexport function verifyEd25519(\n domain: SignDomain,\n payload: string,\n sigB64url: string,\n publicKeyB64: string = defaultPublicKey()\n): boolean {\n try {\n const key = crypto.createPublicKey({\n key: Buffer.concat([SPKI_PREFIX, rawKey(publicKeyB64, \"Public Key\")]),\n format: \"der\",\n type: \"spki\",\n });\n const sig = Buffer.from(sigB64url, \"base64url\");\n return sig.length === 64 && crypto.verify(null, Buffer.from(`${domain}.${payload}`), key, sig);\n } catch {\n return false;\n }\n}\n","/**\n * Öffentlicher Ed25519-Schlüssel des Cuonztech-Lizenzdienstes (32 Byte, base64).\n * Der zugehörige private Seed liegt nur serverseitig (config.php) und im KeePass.\n */\nexport const LICENSE_PUBLIC_KEY = \"q20XyLRZGURVvMLR6q0SCIc6poLhW73KE5Ds94Yq1FQ=\";\n"],"mappings":";AAAA,OAAO,YAAY;;;ACIZ,IAAM,qBAAqB;;;ADWlC,IAAM,eAAe,OAAO,KAAK,oCAAoC,KAAK;AAC1E,IAAM,cAAc,OAAO,KAAK,4BAA4B,KAAK;AAEjE,SAAS,OAAO,KAAa,MAAsB;AACjD,QAAM,MAAM,OAAO,KAAK,KAAK,QAAQ;AACrC,MAAI,IAAI,WAAW,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,yCAAyC,IAAI,MAAM,EAAE;AACnG,SAAO;AACT;AAoBO,SAAS,mBAA2B;AACzC,SAAO,QAAQ,IAAI,2BAA2B;AAChD;AAEO,SAAS,cACd,QACA,SACA,WACA,eAAuB,iBAAiB,GAC/B;AACT,MAAI;AACF,UAAM,MAAM,OAAO,gBAAgB;AAAA,MACjC,KAAK,OAAO,OAAO,CAAC,aAAa,OAAO,cAAc,YAAY,CAAC,CAAC;AAAA,MACpE,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AACD,UAAM,MAAM,OAAO,KAAK,WAAW,WAAW;AAC9C,WAAO,IAAI,WAAW,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK,GAAG,MAAM,IAAI,OAAO,EAAE,GAAG,KAAK,GAAG;AAAA,EAC/F,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|