import crypto from 'crypto'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; const CHAT_USERS_FILE_NAME = 'chat-users.json'; function ensureLogsDir(baseDir) { const logsDir = join(baseDir, '../logs'); if (!existsSync(logsDir)) { mkdirSync(logsDir, { recursive: true }); } return logsDir; } function getChatUsersPath(baseDir) { return join(ensureLogsDir(baseDir), CHAT_USERS_FILE_NAME); } function sha256(value) { return crypto.createHash('sha256').update(value).digest('hex'); } export function ensureChatUsersFile(baseDir) { const usersPath = getChatUsersPath(baseDir); if (existsSync(usersPath)) return; writeFileSync(usersPath, '[]\n', 'utf-8'); console.warn( `[Auth] ${CHAT_USERS_FILE_NAME} wurde neu erstellt. Bitte mindestens einen Admin-User mit Passwort-Hash konfigurieren.` ); } export function loadChatUsers(baseDir) { ensureChatUsersFile(baseDir); const usersPath = getChatUsersPath(baseDir); const raw = readFileSync(usersPath, 'utf-8').trim(); if (!raw) return []; let users = []; try { users = JSON.parse(raw); } catch (error) { throw new Error(`Ungültige ${CHAT_USERS_FILE_NAME}: ${error.message}`); } if (!Array.isArray(users)) { throw new Error(`${CHAT_USERS_FILE_NAME} muss ein Array sein`); } return users .filter((entry) => entry && typeof entry.username === 'string') .map((entry) => ({ username: entry.username.trim(), passwordHash: typeof entry.passwordHash === 'string' ? entry.passwordHash.trim() : '', rights: Array.isArray(entry.rights) ? entry.rights.map((r) => String(r).toLowerCase()) : [] })) .filter((entry) => entry.username && entry.passwordHash); } export function verifyChatUser(baseDir, username, password) { if (!username || !password) return null; const normalizedUser = String(username).trim(); const passwordHash = sha256(password); const user = loadChatUsers(baseDir).find( (entry) => entry.username.toLowerCase() === normalizedUser.toLowerCase() && entry.passwordHash === passwordHash ); if (!user) return null; return { username: user.username, rights: new Set(user.rights) }; }