Files
harheimertc/scripts/set-admin-password.js

301 lines
8.6 KiB
JavaScript
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Script zum Setzen des Admin-Passworts
*
* Verwendung:
* node scripts/set-admin-password.js <neues-passwort>
*
* 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)
})
})
}
// 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)
const backupDir = path.join(__dirname, '..', 'backups', `users-${Date.now()}`)
await fs.mkdir(backupDir, { recursive: true })
const backupPath = path.join(backupDir, 'users.json')
await fs.copyFile(USERS_FILE, backupPath)
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!')
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) {
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)
console.error(error.stack)
process.exit(1)
}
}
// Script ausführen
main().catch(error => {
console.error('Unerwarteter Fehler:', error)
process.exit(1)
})