import fs from 'fs/promises' import path from 'path' import { getUserFromToken, hasAnyRole } from '../../../utils/auth.js' import { randomUUID } from 'crypto' // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal // filename is always a hardcoded constant (e.g., 'newsletter-groups.json'), never user input const 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 NEWSLETTER_GROUPS_FILE = getDataPath('newsletter-groups.json') async function readGroups() { try { const data = await fs.readFile(NEWSLETTER_GROUPS_FILE, 'utf-8') return JSON.parse(data) } catch (error) { if (error.code === 'ENOENT') { return [] } throw error } } async function writeGroups(groups) { await fs.writeFile(NEWSLETTER_GROUPS_FILE, JSON.stringify(groups, null, 2), 'utf-8') } export default defineEventHandler(async (event) => { try { // Authentifizierung prüfen const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace('Bearer ', '') if (!token) { throw createError({ statusCode: 401, statusMessage: 'Nicht authentifiziert' }) } const user = await getUserFromToken(token) if (!user || !hasAnyRole(user, 'admin', 'vorstand', 'newsletter')) { throw createError({ statusCode: 403, statusMessage: 'Keine Berechtigung' }) } const body = await readBody(event) const { name, type, targetGroup, sendToExternal, description } = body if (!name || !type) { throw createError({ statusCode: 400, statusMessage: 'Name und Typ sind erforderlich' }) } if (type === 'subscription' && sendToExternal === undefined) { throw createError({ statusCode: 400, statusMessage: 'sendToExternal ist für Abonnenten-Newsletter erforderlich' }) } if (type === 'group' && !targetGroup) { throw createError({ statusCode: 400, statusMessage: 'Zielgruppe ist für Gruppen-Newsletter erforderlich' }) } const groups = await readGroups() // Prüfe ob Name bereits existiert if (groups.find(g => g.name.toLowerCase() === name.toLowerCase())) { throw createError({ statusCode: 409, statusMessage: 'Eine Newsletter-Gruppe mit diesem Namen existiert bereits' }) } const newGroup = { id: randomUUID(), name, description: description || '', type, // 'subscription' oder 'group' targetGroup: type === 'group' ? targetGroup : null, sendToExternal: type === 'subscription' ? sendToExternal : false, createdAt: new Date().toISOString(), createdBy: user.id, postCount: 0 } groups.push(newGroup) await writeGroups(groups) return { success: true, message: 'Newsletter-Gruppe erfolgreich erstellt', group: newGroup } } catch (error) { console.error('Fehler beim Erstellen der Newsletter-Gruppe:', error) if (error.statusCode) { throw error } throw createError({ statusCode: 500, statusMessage: 'Fehler beim Erstellen der Newsletter-Gruppe' }) } })