From 4b017453b27024c38ad3079ddec1b684e2d12679 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Thu, 18 Dec 2025 12:39:22 +0100 Subject: [PATCH] Update AUTH_README.md to clarify admin password setup process and provide usage instructions for the set-admin-password script. Change file permissions for deploy.sh, production-setup.sh, and fetch-template.sh to make them executable. --- AUTH_README.md | 18 ++- deploy.sh | 0 production-setup.sh | 0 scripts/README-set-admin-password.md | 56 ++++++++ scripts/fetch-template.sh | 0 scripts/set-admin-password.js | 200 +++++++++++++++++++++++++++ 6 files changed, 272 insertions(+), 2 deletions(-) mode change 100644 => 100755 deploy.sh mode change 100644 => 100755 production-setup.sh create mode 100644 scripts/README-set-admin-password.md mode change 100644 => 100755 scripts/fetch-template.sh create mode 100755 scripts/set-admin-password.js diff --git a/AUTH_README.md b/AUTH_README.md index dc9cc45..bf01fcc 100644 --- a/AUTH_README.md +++ b/AUTH_README.md @@ -7,9 +7,23 @@ ⚠️ **WICHTIG:** Ändern Sie dieses Passwort sofort nach der ersten Anmeldung! -## Passwort-Hash generieren +## Admin-Passwort setzen -Um einen neuen Benutzer oder ein neues Passwort zu erstellen, können Sie folgenden Node.js-Code verwenden: +Das einfachste Verfahren ist das Script `scripts/set-admin-password.js`: + +```bash +# Mit Passwort als Argument +node scripts/set-admin-password.js "mein-neues-passwort" + +# Oder interaktiv (Passwort wird abgefragt) +node scripts/set-admin-password.js +``` + +Siehe auch: `scripts/README-set-admin-password.md` + +## Passwort-Hash generieren (manuell) + +Falls Sie einen Passwort-Hash manuell generieren möchten, können Sie folgenden Node.js-Code verwenden: ```javascript import bcrypt from 'bcryptjs' diff --git a/deploy.sh b/deploy.sh old mode 100644 new mode 100755 diff --git a/production-setup.sh b/production-setup.sh old mode 100644 new mode 100755 diff --git a/scripts/README-set-admin-password.md b/scripts/README-set-admin-password.md new file mode 100644 index 0000000..192d5df --- /dev/null +++ b/scripts/README-set-admin-password.md @@ -0,0 +1,56 @@ +# Admin-Passwort setzen + +Dieses Script ermöglicht es, das Passwort für den Admin-User (`admin@harheimertc.de`) zu setzen oder zu ändern. + +## Verwendung + +### Mit Passwort als Argument + +```bash +node scripts/set-admin-password.js "mein-neues-passwort" +``` + +### Interaktiv (Passwort wird abgefragt) + +```bash +node scripts/set-admin-password.js +``` + +Das Script fragt dann nach dem neuen Passwort. + +## Funktionen + +- **Findet oder erstellt den Admin-User**: Falls der Admin-User nicht existiert, wird er automatisch erstellt +- **Passwort-Hashing**: Das Passwort wird mit bcrypt gehasht (10 Runden) +- **Verschlüsselte Speicherung**: Die Benutzerdaten werden verschlüsselt gespeichert +- **Validierung**: Prüft, dass das Passwort mindestens 8 Zeichen lang ist + +## Voraussetzungen + +- `ENCRYPTION_KEY` muss in der `.env` Datei gesetzt sein (für verschlüsselte Speicherung) +- Die Datei `server/data/users.json` muss existieren oder wird automatisch erstellt + +## Beispiel + +```bash +# Passwort direkt setzen +node scripts/set-admin-password.js "MeinSicheresPasswort123!" + +# Interaktiv +node scripts/set-admin-password.js +# Eingabeaufforderung: Neues Passwort für admin@harheimertc.de: +``` + +## Sicherheit + +- Das Passwort wird niemals im Klartext gespeichert +- Es wird mit bcrypt gehasht (10 Runden) +- Die Benutzerdaten werden verschlüsselt gespeichert +- Das Passwort wird nicht in der Kommandozeilen-Historie gespeichert (bei interaktiver Eingabe) + +## Fehlerbehandlung + +Falls die Entschlüsselung der Benutzerdaten fehlschlägt: +- Prüfe, ob `ENCRYPTION_KEY` in der `.env` Datei korrekt gesetzt ist +- Stelle sicher, dass der Schlüssel mit dem übereinstimmt, der zum Verschlüsseln verwendet wurde + diff --git a/scripts/fetch-template.sh b/scripts/fetch-template.sh old mode 100644 new mode 100755 diff --git a/scripts/set-admin-password.js b/scripts/set-admin-password.js new file mode 100755 index 0000000..64746a2 --- /dev/null +++ b/scripts/set-admin-password.js @@ -0,0 +1,200 @@ +#!/usr/bin/env node +/** + * Script zum Setzen des Admin-Passworts + * + * Verwendung: + * node scripts/set-admin-password.js + * + * Oder interaktiv: + * node scripts/set-admin-password.js + */ + +import fs from 'fs/promises' +import path from 'path' +import { fileURLToPath } from 'url' +import bcrypt from 'bcryptjs' +import { decryptObject, encryptObject } from '../server/utils/encryption.js' +import dotenv from 'dotenv' +import readline from 'readline' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +// Lade .env Datei +dotenv.config({ path: path.join(__dirname, '..', '.env') }) + +const ADMIN_EMAIL = 'admin@harheimertc.de' + +// Pfade bestimmen +function getDataPath(filename) { + const cwd = process.cwd() + if (cwd.endsWith('.output')) { + return path.join(cwd, '../server/data', filename) + } + return path.join(cwd, 'server/data', filename) +} + +const USERS_FILE = getDataPath('users.json') + +// Get encryption key from environment +function getEncryptionKey() { + return process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production' +} + +// Prüft ob Daten verschlüsselt sind +function isEncrypted(data) { + try { + const parsed = JSON.parse(data.trim()) + if (Array.isArray(parsed)) { + return false + } + if (typeof parsed === 'object' && parsed !== null && !parsed.encryptedData) { + return false + } + return false + } catch (e) { + return true + } +} + +// Liest Benutzer aus Datei +async function readUsers() { + try { + const data = await fs.readFile(USERS_FILE, 'utf-8') + const encrypted = isEncrypted(data) + + if (encrypted) { + const encryptionKey = getEncryptionKey() + try { + return decryptObject(data, encryptionKey) + } catch (decryptError) { + console.error('Fehler beim Entschlüsseln der Benutzerdaten:', decryptError.message) + throw new Error('Konnte Benutzerdaten nicht entschlüsseln. Bitte prüfe ENCRYPTION_KEY in .env') + } + } else { + return JSON.parse(data) + } + } catch (error) { + if (error.code === 'ENOENT') { + return [] + } + throw error + } +} + +// Schreibt Benutzer in Datei (immer verschlüsselt) +async function writeUsers(users) { + try { + const encryptionKey = getEncryptionKey() + const encryptedData = encryptObject(users, encryptionKey) + await fs.writeFile(USERS_FILE, encryptedData, 'utf-8') + return true + } catch (error) { + console.error('Fehler beim Schreiben der Benutzerdaten:', error) + return false + } +} + +// Hash-Passwort generieren +async function hashPassword(password) { + const salt = await bcrypt.genSalt(10) + return await bcrypt.hash(password, salt) +} + +// Fragt nach Passwort (wenn nicht als Argument übergeben) +function askPassword() { + return new Promise((resolve) => { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }) + + rl.question('Neues Passwort für admin@harheimertc.de: ', (password) => { + rl.close() + resolve(password) + }) + }) +} + +// Hauptfunktion +async function main() { + console.log('🔐 Admin-Passwort setzen\n') + + // Passwort aus Kommandozeilenargumenten oder interaktiv abfragen + let newPassword = process.argv[2] + + if (!newPassword) { + newPassword = await askPassword() + } + + if (!newPassword || newPassword.trim().length === 0) { + console.error('❌ FEHLER: Passwort darf nicht leer sein!') + process.exit(1) + } + + if (newPassword.length < 8) { + console.error('❌ FEHLER: Passwort muss mindestens 8 Zeichen lang sein!') + process.exit(1) + } + + try { + // Benutzer laden + console.log('📖 Lade Benutzerdaten...') + const users = await readUsers() + + // Admin-User finden oder erstellen + let adminUser = users.find(u => u.email.toLowerCase() === ADMIN_EMAIL.toLowerCase()) + + if (!adminUser) { + console.log(`ℹ️ Admin-User (${ADMIN_EMAIL}) nicht gefunden, erstelle neuen Benutzer...`) + adminUser = { + id: Date.now().toString(), + email: ADMIN_EMAIL, + name: 'Administrator', + role: 'admin', + active: true, + created: new Date().toISOString(), + lastLogin: null + } + users.push(adminUser) + } else { + console.log(`✅ Admin-User gefunden: ${adminUser.name || ADMIN_EMAIL}`) + } + + // Passwort hashen + console.log('🔐 Hashe Passwort...') + const hashedPassword = await hashPassword(newPassword) + + // Passwort setzen + adminUser.password = hashedPassword + adminUser.updated = new Date().toISOString() + + // Benutzer speichern + console.log('💾 Speichere Benutzerdaten...') + const success = await writeUsers(users) + + if (success) { + console.log('\n✅ Passwort erfolgreich gesetzt!') + console.log(`📧 E-Mail: ${ADMIN_EMAIL}`) + console.log(`👤 Rolle: ${adminUser.role}`) + console.log(`✅ Status: ${adminUser.active ? 'Aktiv' : 'Inaktiv'}`) + } else { + console.error('\n❌ FEHLER: Konnte Benutzerdaten nicht speichern!') + process.exit(1) + } + + } catch (error) { + console.error('\n❌ FEHLER:', error.message) + if (error.message.includes('entschlüsseln')) { + console.error('\n💡 Tipp: Stelle sicher, dass ENCRYPTION_KEY in der .env Datei korrekt gesetzt ist.') + } + process.exit(1) + } +} + +// Script ausführen +main().catch(error => { + console.error('Unerwarteter Fehler:', error) + process.exit(1) +}) +