#!/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')) { // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal return path.join(cwd, '../server/data', filename) } // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal 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) }) }) } // Fragt nach Bestätigung function askConfirmation(question) { return new Promise((resolve) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) rl.question(`${question} (j/n): `, (answer) => { rl.close() resolve(answer.toLowerCase() === 'j' || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'ja' || answer.toLowerCase() === 'yes') }) }) } // Erstellt ein Backup der users.json async function createBackup() { try { await fs.access(USERS_FILE) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal const backupDir = path.join(__dirname, '..', 'backups', `users-${Date.now()}`) await fs.mkdir(backupDir, { recursive: true }) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal const backupPath = path.join(backupDir, 'users.json') await fs.copyFile(USERS_FILE, backupPath) // nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring console.log(`📦 Backup erstellt: ${backupPath}`) return backupPath } catch (error) { if (error.code === 'ENOENT') { console.log('ℹ️ users.json existiert nicht, kein Backup nötig') return null } throw error } } // Erstellt eine neue users.json mit Admin-User async function createNewUsersFile(password) { const hashedPassword = await hashPassword(password) const adminUser = { id: Date.now().toString(), email: ADMIN_EMAIL, password: hashedPassword, name: 'Administrator', role: 'admin', active: true, created: new Date().toISOString(), lastLogin: null } return [adminUser] } // Hauptfunktion async function main() { console.log('🔐 Admin-Passwort setzen\n') // Prüfe ob --recreate Flag gesetzt ist const recreateFlag = process.argv.includes('--recreate') || process.argv.includes('-r') // Passwort aus Kommandozeilenargumenten oder interaktiv abfragen // Filtere Flags heraus und nimm das erste verbleibende Argument als Passwort const args = process.argv.slice(2).filter(arg => !arg.startsWith('--') && !arg.startsWith('-')) let newPassword = args.length > 0 ? args[0] : null 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...') let users let shouldRecreate = recreateFlag try { users = await readUsers() } catch (error) { if (error.message.includes('entschlüsseln') || error.message.includes('Entschlüsselung')) { console.error('\n⚠️ WARNUNG: Konnte Benutzerdaten nicht entschlüsseln!') console.error(' Dies bedeutet, dass der ENCRYPTION_KEY nicht mit dem verwendeten Schlüssel übereinstimmt.\n') if (!shouldRecreate) { const confirmed = await askConfirmation('Möchten Sie die users.json Datei neu erstellen? (Alte Datei wird als Backup gespeichert)') if (!confirmed) { console.log('\n❌ Abgebrochen. Bitte setzen Sie ENCRYPTION_KEY in der .env Datei auf den korrekten Wert.') process.exit(1) } shouldRecreate = true } // Backup erstellen await createBackup() // Neue Datei erstellen console.log('\n🆕 Erstelle neue users.json Datei...') users = await createNewUsersFile(newPassword) // Direkt speichern console.log('💾 Speichere neue Benutzerdaten...') const success = await writeUsers(users) if (success) { console.log('\n✅ Neue users.json Datei erfolgreich erstellt!') // nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring console.log(`📧 E-Mail: ${ADMIN_EMAIL}`) console.log(`👤 Rolle: admin`) console.log(`✅ Status: Aktiv`) console.log(`🔐 Passwort: Gesetzt`) } else { console.error('\n❌ FEHLER: Konnte Benutzerdaten nicht speichern!') process.exit(1) } return } else { throw error } } // Admin-User finden oder erstellen let adminUser = users.find(u => u.email.toLowerCase() === ADMIN_EMAIL.toLowerCase()) if (!adminUser) { // nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring 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 { // nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring 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!') // nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring 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) console.error(error.stack) process.exit(1) } } // Script ausführen main().catch(error => { console.error('Unerwarteter Fehler:', error) process.exit(1) })