cms: headless CMS vor Hugo (Supabase + Node-API + React-Admin)
All-in-One docker-compose-Stack (Muster von RAPPORT-SERVER gespiegelt): db/auth/rest/kong + cms-Service (Node-API + Hugo-Binary 0.161.1 + Admin-SPA). - DB-backed: posts-Tabelle kanonisch, MD ist generiertes Artefakt - echte Hugo-Vorschau via draft:true + --buildDrafts → /_preview - Publish: DB → content/library/<section>/<slug>.md → hugo build → live - Bild-Upload nach static/images/, Supabase-Auth schützt /api/* - Proxmox-LXC-Script: legt Container an, generiert Secrets, startet Stack Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env node
|
||||
// Generiert ANON_KEY und SERVICE_ROLE_KEY (JWTs, HS256) aus dem JWT_SECRET
|
||||
// in der .env. Ohne diese Keys können GoTrue und PostgREST nicht reden.
|
||||
// (Gespiegelt von RAPPORT-SERVER — generisch, nicht app-spezifisch.)
|
||||
//
|
||||
// Aufruf:
|
||||
// node scripts/generate-keys.mjs # liest JWT_SECRET aus .env
|
||||
// node scripts/generate-keys.mjs <secret> # explizit übergeben
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
|
||||
function base64url(input) {
|
||||
return Buffer.from(input).toString("base64")
|
||||
.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function signJwt(payload, secret) {
|
||||
const header = base64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
||||
const body = base64url(JSON.stringify(payload));
|
||||
const sig = base64url(crypto.createHmac("sha256", secret).update(`${header}.${body}`).digest());
|
||||
return `${header}.${body}.${sig}`;
|
||||
}
|
||||
|
||||
let secret = process.argv[2];
|
||||
if (!secret) {
|
||||
try {
|
||||
const env = fs.readFileSync(".env", "utf8");
|
||||
const m = env.match(/^JWT_SECRET=(.+)$/m);
|
||||
if (m) secret = m[1].trim().replace(/^["']|["']$/g, "");
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!secret || secret.length < 32 || secret.includes("CHANGE-ME")) {
|
||||
console.error("✗ Kein gültiges JWT_SECRET gefunden (mind. 32 Zeichen, nicht der Placeholder).");
|
||||
console.error(" Setze JWT_SECRET in .env oder gib es als Argument:");
|
||||
console.error(" node scripts/generate-keys.mjs $(openssl rand -hex 32)");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const tenYears = now + 10 * 365 * 24 * 3600;
|
||||
|
||||
const anonKey = signJwt({ role: "anon", iss: "supabase", iat: now, exp: tenYears }, secret);
|
||||
const serviceKey = signJwt({ role: "service_role", iss: "supabase", iat: now, exp: tenYears }, secret);
|
||||
|
||||
console.log("ANON_KEY=" + anonKey);
|
||||
console.log("SERVICE_ROLE_KEY=" + serviceKey);
|
||||
console.error("");
|
||||
console.error("→ Werte in .env eintragen (überschreibt CHANGE-ME-Placeholder).");
|
||||
Reference in New Issue
Block a user