Files
singlechat/server/chat-auth.js
Torsten Schulz (local) 47373a27af Enhance SEO and feedback features across the application
- Updated index.html with improved meta tags for SEO, including author and theme color.
- Added a feedback dialog in ImprintContainer.vue for user feedback submission.
- Refactored LoginForm.vue to utilize a utility for cookie management, simplifying profile persistence.
- Introduced new routes and schemas for feedback in the router and server, enhancing SEO and user experience.
- Improved ChatView.vue with better error handling and command table display.
- Implemented feedback API endpoints in server routes for managing user feedback submissions and admin access.

These changes collectively improve the application's SEO, user interaction, and feedback management capabilities.
2026-03-19 15:21:54 +01:00

74 lines
2.2 KiB
JavaScript

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)
};
}