diff --git a/package-lock.json b/package-lock.json index 7bff8c6..8291e00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "devDependencies": { "@nuxtjs/tailwindcss": "^6.11.0", "autoprefixer": "^10.4.0", + "dotenv": "^17.2.3", "lucide-vue-next": "^0.344.0", "postcss": "^8.4.0", "supertest": "^7.1.0", diff --git a/package.json b/package.json index 6f6b022..37a1116 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "devDependencies": { "@nuxtjs/tailwindcss": "^6.11.0", "autoprefixer": "^10.4.0", + "dotenv": "^17.2.3", "lucide-vue-next": "^0.344.0", "postcss": "^8.4.0", "supertest": "^7.1.0", diff --git a/scripts/README-re-encrypt.md b/scripts/README-re-encrypt.md new file mode 100644 index 0000000..454e1ab --- /dev/null +++ b/scripts/README-re-encrypt.md @@ -0,0 +1,66 @@ +# Daten-Neuverschlüsselung + +Dieses Script verschlüsselt alle verschlüsselten Daten mit einem neuen Schlüssel neu. + +## Verwendung + +### Voraussetzungen + +1. Stelle sicher, dass `ENCRYPTION_KEY` in der `.env` Datei gesetzt ist: + ```bash + ENCRYPTION_KEY=dein-neuer-sicherer-schlüssel-hier + ``` + +2. Optional: Wenn du einen spezifischen alten Schlüssel verwendest (nicht den Standard), kannst du ihn angeben: + ```bash + node scripts/re-encrypt-data.js --old-key="dein-alter-schlüssel" + ``` + +### Ausführung + +```bash +node scripts/re-encrypt-data.js +``` + +## Was wird neu verschlüsselt? + +Das Script verarbeitet folgende Dateien: + +1. **`server/data/users.json`** - Benutzerdaten +2. **`server/data/members.json`** - Mitgliederdaten +3. **`server/data/membership-applications/*.json`** - Mitgliedschaftsanträge (wenn sie ein `encryptedData` Feld enthalten) +4. **`server/data/membership-applications/*.data`** - Verschlüsselte Antragsdaten + +## Sicherheit + +- **Automatische Backups**: Vor jeder Änderung werden Backups im Verzeichnis `backups/re-encrypt-/` erstellt +- **Mehrere Schlüssel**: Das Script versucht automatisch verschiedene alte Standard-Schlüssel: + - `default-key-change-in-production` + - `local_development_encryption_key_change_in_production` + - Ein optional angegebener `--old-key` Parameter + +## Beispiel + +```bash +# Standard-Ausführung (verwendet Standard-Entwicklungsschlüssel) +node scripts/re-encrypt-data.js + +# Mit spezifischem altem Schlüssel +node scripts/re-encrypt-data.js --old-key="mein-alter-produktions-schlüssel" +``` + +## Fehlerbehandlung + +Falls die Entschlüsselung mit allen verfügbaren Schlüsseln fehlschlägt: +- Das Script bricht ab +- Alle Backups bleiben erhalten +- Du kannst die Dateien manuell aus den Backups wiederherstellen + +## Wichtig + +⚠️ **WICHTIG**: Stelle sicher, dass: +- Die `.env` Datei den neuen `ENCRYPTION_KEY` enthält +- Du ein Backup der Daten hast (wird automatisch erstellt) +- Der Server während der Ausführung nicht läuft +- Du nach der Ausführung testest, ob alles funktioniert + diff --git a/scripts/re-encrypt-data.js b/scripts/re-encrypt-data.js new file mode 100755 index 0000000..3ef7242 --- /dev/null +++ b/scripts/re-encrypt-data.js @@ -0,0 +1,282 @@ +#!/usr/bin/env node +/** + * Script zum Neuverschlüsseln aller verschlüsselten Daten + * + * Verwendung: + * node scripts/re-encrypt-data.js [--old-key="alter-schlüssel"] + * + * Wenn --old-key nicht angegeben wird, wird der Standard-Entwicklungsschlüssel verwendet. + * Der neue Schlüssel wird aus der .env Datei gelesen (ENCRYPTION_KEY). + */ + +import fs from 'fs/promises' +import path from 'path' +import { fileURLToPath } from 'url' +import { decryptObject, encryptObject, decrypt, encrypt } from '../server/utils/encryption.js' +import dotenv from 'dotenv' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +// Lade .env Datei +dotenv.config({ path: path.join(__dirname, '..', '.env') }) + +// Alte Standard-Schlüssel (die möglicherweise verwendet wurden) +const OLD_DEFAULT_KEYS = [ + 'default-key-change-in-production', + 'local_development_encryption_key_change_in_production' +] + +// Neuer Schlüssel aus .env +const NEW_KEY = process.env.ENCRYPTION_KEY + +if (!NEW_KEY) { + console.error('❌ FEHLER: ENCRYPTION_KEY ist nicht in der .env Datei gesetzt!') + console.error('Bitte setzen Sie ENCRYPTION_KEY in der .env Datei.') + process.exit(1) +} + +// Alten Schlüssel aus Kommandozeilenargumenten oder Standard verwenden +const args = process.argv.slice(2) +let oldKeyArg = null +for (const arg of args) { + if (arg.startsWith('--old-key=')) { + oldKeyArg = arg.split('=')[1] + } +} + +// 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') +const MEMBERS_FILE = getDataPath('members.json') +const MEMBERSHIP_APPLICATIONS_DIR = getDataPath('membership-applications') + +// Backup-Verzeichnis erstellen +async function createBackup() { + const backupDir = path.join(__dirname, '..', 'backups', `re-encrypt-${Date.now()}`) + await fs.mkdir(backupDir, { recursive: true }) + console.log(`📦 Backup-Verzeichnis erstellt: ${backupDir}`) + return backupDir +} + +// 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 + } +} + +// Versucht mit verschiedenen Schlüsseln zu entschlüsseln +async function decryptWithFallback(encryptedData, keys) { + const errors = [] + + // encryptedData sollte bereits ein String sein (entweder direkt verschlüsselt oder aus einem JSON-Objekt extrahiert) + // Versuche mit jedem Schlüssel zu entschlüsseln + for (const key of keys) { + try { + // Direkt verschlüsselte Base64-Daten + return decryptObject(encryptedData, key) + } catch (error) { + errors.push({ key: key.length > 30 ? key.substring(0, 30) + '...' : key, error: error.message }) + continue + } + } + + throw new Error(`Entschlüsselung fehlgeschlagen mit allen Schlüsseln:\n${errors.map(e => ` - ${e.key}: ${e.error}`).join('\n')}`) +} + +// Neuverschlüsselt users.json +async function reencryptUsers(backupDir, oldKeys) { + try { + const data = await fs.readFile(USERS_FILE, 'utf-8') + + // Backup erstellen + await fs.copyFile(USERS_FILE, path.join(backupDir, 'users.json')) + console.log('✅ Backup von users.json erstellt') + + if (!isEncrypted(data)) { + console.log('ℹ️ users.json ist nicht verschlüsselt, überspringe...') + return + } + + console.log('🔄 Entschlüssele users.json...') + const decrypted = await decryptWithFallback(data, oldKeys) + + console.log('🔐 Verschlüssele users.json mit neuem Schlüssel...') + const reencrypted = encryptObject(decrypted, NEW_KEY) + + await fs.writeFile(USERS_FILE, reencrypted, 'utf-8') + console.log('✅ users.json erfolgreich neu verschlüsselt') + + } catch (error) { + if (error.code === 'ENOENT') { + console.log('ℹ️ users.json existiert nicht, überspringe...') + return + } + throw error + } +} + +// Neuverschlüsselt members.json +async function reencryptMembers(backupDir, oldKeys) { + try { + const data = await fs.readFile(MEMBERS_FILE, 'utf-8') + + // Backup erstellen + await fs.copyFile(MEMBERS_FILE, path.join(backupDir, 'members.json')) + console.log('✅ Backup von members.json erstellt') + + if (!isEncrypted(data)) { + console.log('ℹ️ members.json ist nicht verschlüsselt, überspringe...') + return + } + + console.log('🔄 Entschlüssele members.json...') + const decrypted = await decryptWithFallback(data, oldKeys) + + console.log('🔐 Verschlüssele members.json mit neuem Schlüssel...') + const reencrypted = encryptObject(decrypted, NEW_KEY) + + await fs.writeFile(MEMBERS_FILE, reencrypted, 'utf-8') + console.log('✅ members.json erfolgreich neu verschlüsselt') + + } catch (error) { + if (error.code === 'ENOENT') { + console.log('ℹ️ members.json existiert nicht, überspringe...') + return + } + throw error + } +} + +// Neuverschlüsselt Mitgliedschaftsanträge +async function reencryptMembershipApplications(backupDir, oldKeys) { + try { + await fs.access(MEMBERSHIP_APPLICATIONS_DIR) + } catch { + console.log('ℹ️ membership-applications Verzeichnis existiert nicht, überspringe...') + return + } + + const files = await fs.readdir(MEMBERSHIP_APPLICATIONS_DIR) + let processed = 0 + let skipped = 0 + + for (const file of files) { + const filePath = path.join(MEMBERSHIP_APPLICATIONS_DIR, file) + const stat = await fs.stat(filePath) + + if (stat.isDirectory()) { + continue + } + + try { + // Backup erstellen + const backupPath = path.join(backupDir, 'membership-applications', file) + await fs.mkdir(path.dirname(backupPath), { recursive: true }) + await fs.copyFile(filePath, backupPath) + + const content = await fs.readFile(filePath, 'utf-8') + const parsed = JSON.parse(content) + + // Prüfe ob encryptedData Feld vorhanden ist + if (parsed.encryptedData) { + console.log(`🔄 Entschlüssele ${file}...`) + // Nur das encryptedData Feld entschlüsseln + const decrypted = await decryptWithFallback(parsed.encryptedData, oldKeys) + + console.log(`🔐 Verschlüssele ${file} mit neuem Schlüssel...`) + const reencrypted = encryptObject(decrypted, NEW_KEY) + + parsed.encryptedData = reencrypted + await fs.writeFile(filePath, JSON.stringify(parsed, null, 2), 'utf-8') + console.log(`✅ ${file} erfolgreich neu verschlüsselt`) + processed++ + } else if (file.endsWith('.data')) { + // .data Dateien sind direkt verschlüsselt + console.log(`🔄 Entschlüssele ${file}...`) + const decrypted = await decryptWithFallback(content, oldKeys) + + console.log(`🔐 Verschlüssele ${file} mit neuem Schlüssel...`) + const reencrypted = encrypt(JSON.stringify(decrypted), NEW_KEY) + + await fs.writeFile(filePath, reencrypted, 'utf-8') + console.log(`✅ ${file} erfolgreich neu verschlüsselt`) + processed++ + } else { + console.log(`ℹ️ ${file} enthält keine verschlüsselten Daten, überspringe...`) + skipped++ + } + } catch (error) { + console.error(`❌ Fehler beim Verarbeiten von ${file}:`, error.message) + throw error + } + } + + console.log(`✅ Mitgliedschaftsanträge verarbeitet: ${processed} neu verschlüsselt, ${skipped} übersprungen`) +} + +// Hauptfunktion +async function main() { + console.log('🔐 Daten-Neuverschlüsselung gestartet\n') + + // Alte Schlüssel zusammenstellen + const oldKeys = oldKeyArg ? [oldKeyArg, ...OLD_DEFAULT_KEYS] : OLD_DEFAULT_KEYS + + console.log('Alte Schlüssel (werden nacheinander versucht):') + oldKeys.forEach((key, i) => { + const displayKey = key.length > 50 ? key.substring(0, 50) + '...' : key + console.log(` ${i + 1}. ${displayKey}`) + }) + console.log(`\nNeuer Schlüssel: ${NEW_KEY.length > 50 ? NEW_KEY.substring(0, 50) + '...' : NEW_KEY}\n`) + + // Bestätigung + console.log('⚠️ WICHTIG: Dieses Script wird alle verschlüsselten Daten neu verschlüsseln!') + console.log('📦 Backups werden automatisch erstellt.\n') + + // Backup-Verzeichnis erstellen + const backupDir = await createBackup() + + try { + // Dateien neu verschlüsseln + await reencryptUsers(backupDir, oldKeys) + console.log('') + + await reencryptMembers(backupDir, oldKeys) + console.log('') + + await reencryptMembershipApplications(backupDir, oldKeys) + console.log('') + + console.log('✅ Alle Daten erfolgreich neu verschlüsselt!') + console.log(`📦 Backups gespeichert in: ${backupDir}`) + + } catch (error) { + console.error('\n❌ FEHLER beim Neuverschlüsseln:', error.message) + console.error('\nDie Backups sind sicher gespeichert. Sie können die Dateien manuell wiederherstellen.') + process.exit(1) + } +} + +// Script ausführen +main().catch(error => { + console.error('Unerwarteter Fehler:', error) + process.exit(1) +}) + diff --git a/server/api/auth/register.post.js b/server/api/auth/register.post.js index a7251d7..cfb287f 100644 --- a/server/api/auth/register.post.js +++ b/server/api/auth/register.post.js @@ -53,47 +53,56 @@ export default defineEventHandler(async (event) => { // Send notification email to admin try { - const transporter = nodemailer.createTransport({ - host: process.env.SMTP_HOST || 'smtp.gmail.com', - port: process.env.SMTP_PORT || 587, - secure: false, - auth: { - user: process.env.SMTP_USER, - pass: process.env.SMTP_PASS - } - }) + const smtpUser = process.env.SMTP_USER + const smtpPass = process.env.SMTP_PASS + + if (!smtpUser || !smtpPass) { + console.warn('SMTP-Credentials fehlen! E-Mail-Versand wird übersprungen.') + console.warn(`SMTP_USER=${smtpUser ? 'gesetzt' : 'FEHLT'}, SMTP_PASS=${smtpPass ? 'gesetzt' : 'FEHLT'}`) + // Continue without sending email + } else { + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST || 'smtp.gmail.com', + port: process.env.SMTP_PORT || 587, + secure: false, + auth: { + user: smtpUser, + pass: smtpPass + } + }) - // Email to admin - await transporter.sendMail({ - from: process.env.SMTP_FROM || 'noreply@harheimertc.de', - to: process.env.SMTP_ADMIN || 'j.dichmann@gmx.de', - subject: 'Neue Registrierung - Harheimer TC', - html: ` -

Neue Registrierung

-

Ein neuer Benutzer hat sich registriert und wartet auf Freigabe:

- -

Bitte prüfen Sie die Registrierung im CMS.

- ` - }) + // Email to admin + await transporter.sendMail({ + from: process.env.SMTP_FROM || 'noreply@harheimertc.de', + to: process.env.SMTP_ADMIN || 'j.dichmann@gmx.de', + subject: 'Neue Registrierung - Harheimer TC', + html: ` +

Neue Registrierung

+

Ein neuer Benutzer hat sich registriert und wartet auf Freigabe:

+ +

Bitte prüfen Sie die Registrierung im CMS.

+ ` + }) - // Email to user - await transporter.sendMail({ - from: process.env.SMTP_FROM || 'noreply@harheimertc.de', - to: email, - subject: 'Registrierung erhalten - Harheimer TC', - html: ` -

Registrierung erhalten

-

Hallo ${name},

-

vielen Dank für Ihre Registrierung beim Harheimer TC!

-

Ihre Anfrage wird vom Vorstand geprüft. Sie erhalten eine E-Mail, sobald Ihr Zugang freigeschaltet wurde.

-
-

Mit sportlichen Grüßen,
Ihr Harheimer TC

- ` - }) + // Email to user + await transporter.sendMail({ + from: process.env.SMTP_FROM || 'noreply@harheimertc.de', + to: email, + subject: 'Registrierung erhalten - Harheimer TC', + html: ` +

Registrierung erhalten

+

Hallo ${name},

+

vielen Dank für Ihre Registrierung beim Harheimer TC!

+

Ihre Anfrage wird vom Vorstand geprüft. Sie erhalten eine E-Mail, sobald Ihr Zugang freigeschaltet wurde.

+
+

Mit sportlichen Grüßen,
Ihr Harheimer TC

+ ` + }) + } } catch (emailError) { console.error('E-Mail-Versand fehlgeschlagen:', emailError) // Continue anyway - user is registered diff --git a/server/api/auth/reset-password.post.js b/server/api/auth/reset-password.post.js index d15134a..997975e 100644 --- a/server/api/auth/reset-password.post.js +++ b/server/api/auth/reset-password.post.js @@ -37,35 +37,44 @@ export default defineEventHandler(async (event) => { await writeUsers(updatedUsers) // Send email with temporary password - const transporter = nodemailer.createTransport({ - host: process.env.SMTP_HOST || 'smtp.gmail.com', - port: process.env.SMTP_PORT || 587, - secure: false, - auth: { - user: process.env.SMTP_USER, - pass: process.env.SMTP_PASS + const smtpUser = process.env.SMTP_USER + const smtpPass = process.env.SMTP_PASS + + if (!smtpUser || !smtpPass) { + console.warn('SMTP-Credentials fehlen! E-Mail-Versand wird übersprungen.') + console.warn(`SMTP_USER=${smtpUser ? 'gesetzt' : 'FEHLT'}, SMTP_PASS=${smtpPass ? 'gesetzt' : 'FEHLT'}`) + // Continue without sending email - security: don't reveal if email exists + } else { + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST || 'smtp.gmail.com', + port: process.env.SMTP_PORT || 587, + secure: false, + auth: { + user: smtpUser, + pass: smtpPass + } + }) + + const mailOptions = { + from: process.env.SMTP_FROM || 'noreply@harheimertc.de', + to: user.email, + subject: 'Passwort zurücksetzen - Harheimer TC', + html: ` +

Passwort zurücksetzen

+

Hallo ${user.name},

+

Sie haben eine Anfrage zum Zurücksetzen Ihres Passworts gestellt.

+

Ihr temporäres Passwort lautet: ${tempPassword}

+

Bitte melden Sie sich damit an und ändern Sie Ihr Passwort im Mitgliederbereich.

+
+

Falls Sie diese Anfrage nicht gestellt haben, ignorieren Sie diese E-Mail.

+
+

Mit sportlichen Grüßen,
Ihr Harheimer TC

+ ` } - }) - const mailOptions = { - from: process.env.SMTP_FROM || 'noreply@harheimertc.de', - to: user.email, - subject: 'Passwort zurücksetzen - Harheimer TC', - html: ` -

Passwort zurücksetzen

-

Hallo ${user.name},

-

Sie haben eine Anfrage zum Zurücksetzen Ihres Passworts gestellt.

-

Ihr temporäres Passwort lautet: ${tempPassword}

-

Bitte melden Sie sich damit an und ändern Sie Ihr Passwort im Mitgliederbereich.

-
-

Falls Sie diese Anfrage nicht gestellt haben, ignorieren Sie diese E-Mail.

-
-

Mit sportlichen Grüßen,
Ihr Harheimer TC

- ` + await transporter.sendMail(mailOptions) } - await transporter.sendMail(mailOptions) - return { success: true, message: 'Falls ein Konto mit dieser E-Mail existiert, wurde eine E-Mail gesendet.' diff --git a/server/api/cms/users/approve.post.js b/server/api/cms/users/approve.post.js index a2037e5..830a133 100644 --- a/server/api/cms/users/approve.post.js +++ b/server/api/cms/users/approve.post.js @@ -35,30 +35,39 @@ export default defineEventHandler(async (event) => { // Send approval email try { - const transporter = nodemailer.createTransport({ - host: process.env.SMTP_HOST || 'smtp.gmail.com', - port: process.env.SMTP_PORT || 587, - secure: false, - auth: { - user: process.env.SMTP_USER, - pass: process.env.SMTP_PASS - } - }) + const smtpUser = process.env.SMTP_USER + const smtpPass = process.env.SMTP_PASS + + if (!smtpUser || !smtpPass) { + console.warn('SMTP-Credentials fehlen! E-Mail-Versand wird übersprungen.') + console.warn(`SMTP_USER=${smtpUser ? 'gesetzt' : 'FEHLT'}, SMTP_PASS=${smtpPass ? 'gesetzt' : 'FEHLT'}`) + // Continue without sending email + } else { + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST || 'smtp.gmail.com', + port: process.env.SMTP_PORT || 587, + secure: false, + auth: { + user: smtpUser, + pass: smtpPass + } + }) - await transporter.sendMail({ - from: process.env.SMTP_FROM || 'noreply@harheimertc.de', - to: user.email, - subject: 'Zugang freigeschaltet - Harheimer TC', - html: ` -

Zugang freigeschaltet

-

Hallo ${user.name},

-

Ihr Zugang zum Mitgliederbereich wurde freigeschaltet!

-

Sie können sich jetzt mit Ihrer E-Mail-Adresse und Ihrem Passwort anmelden.

-

Zum Login

-
-

Mit sportlichen Grüßen,
Ihr Harheimer TC

- ` - }) + await transporter.sendMail({ + from: process.env.SMTP_FROM || 'noreply@harheimertc.de', + to: user.email, + subject: 'Zugang freigeschaltet - Harheimer TC', + html: ` +

Zugang freigeschaltet

+

Hallo ${user.name},

+

Ihr Zugang zum Mitgliederbereich wurde freigeschaltet!

+

Sie können sich jetzt mit Ihrer E-Mail-Adresse und Ihrem Passwort anmelden.

+

Zum Login

+
+

Mit sportlichen Grüßen,
Ihr Harheimer TC

+ ` + }) + } } catch (emailError) { console.error('E-Mail-Versand fehlgeschlagen:', emailError) } diff --git a/server/api/contact.post.js b/server/api/contact.post.js index f404e57..a3bf226 100644 --- a/server/api/contact.post.js +++ b/server/api/contact.post.js @@ -22,13 +22,23 @@ export default defineEventHandler(async (event) => { } // SMTP-Konfiguration (hier können Sie Ihre SMTP-Daten eintragen) + const smtpUser = process.env.SMTP_USER || 'j.dichmann@gmx.de' + const smtpPass = process.env.SMTP_PASS || process.env.EMAIL_PASSWORD + + if (!smtpUser || !smtpPass) { + throw createError({ + statusCode: 500, + statusMessage: 'SMTP-Credentials fehlen! Bitte setzen Sie SMTP_USER und SMTP_PASS in der .env Datei.' + }) + } + const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST || 'smtp.gmail.com', port: process.env.SMTP_PORT || 587, secure: false, // true für 465, false für andere Ports auth: { - user: process.env.SMTP_USER || 'j.dichmann@gmx.de', - pass: process.env.SMTP_PASS || process.env.EMAIL_PASSWORD + user: smtpUser, + pass: smtpPass } }) diff --git a/server/api/membership/generate-pdf.post.js b/server/api/membership/generate-pdf.post.js index bc96edf..f245a4f 100644 --- a/server/api/membership/generate-pdf.post.js +++ b/server/api/membership/generate-pdf.post.js @@ -674,7 +674,7 @@ export default defineEventHandler(async (event) => { // E-Mail senden emailResult = await sendMembershipEmail(data, filename, event) // Antragsdaten verschlüsselt speichern - const encryptionKey = process.env.ENCRYPTION_KEY || 'default-key-change-in-production' + const encryptionKey = process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production' const encryptedData = encrypt(JSON.stringify(data), encryptionKey) const dataPath = path.join(uploadsDir, `${filename}.data`) await fs.writeFile(dataPath, encryptedData, 'utf8') @@ -730,7 +730,7 @@ export default defineEventHandler(async (event) => { emailResult = await sendMembershipEmail(data, filename, event) // Antragsdaten verschlüsselt speichern - const encryptionKey = process.env.ENCRYPTION_KEY || 'default-key-change-in-production' + const encryptionKey = process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production' const encryptedData = encrypt(JSON.stringify(data), encryptionKey) const dataPath = path.join(uploadsDir, `${filename}.data`) await fs.writeFile(dataPath, encryptedData, 'utf8') diff --git a/server/utils/auth.js b/server/utils/auth.js index 16cf23c..9f90e39 100644 --- a/server/utils/auth.js +++ b/server/utils/auth.js @@ -24,7 +24,7 @@ const SESSIONS_FILE = getDataPath('sessions.json') // Get encryption key from environment function getEncryptionKey() { - return process.env.ENCRYPTION_KEY || 'default-key-change-in-production' + return process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production' } // Check if data is encrypted by trying to parse as JSON first diff --git a/server/utils/email-service.js b/server/utils/email-service.js index 2bb22ad..d7d29f7 100644 --- a/server/utils/email-service.js +++ b/server/utils/email-service.js @@ -80,13 +80,23 @@ function getEmailRecipients(data, config) { * @returns {Object} Nodemailer transporter */ function createTransporter() { + const smtpUser = process.env.SMTP_USER + const smtpPass = process.env.SMTP_PASS + + if (!smtpUser || !smtpPass) { + throw new Error( + 'SMTP-Credentials fehlen! Bitte setzen Sie SMTP_USER und SMTP_PASS in der .env Datei.\n' + + `Aktuell: SMTP_USER=${smtpUser ? 'gesetzt' : 'FEHLT'}, SMTP_PASS=${smtpPass ? 'gesetzt' : 'FEHLT'}` + ) + } + return nodemailer.createTransporter({ host: process.env.SMTP_HOST || 'localhost', port: parseInt(process.env.SMTP_PORT) || 587, secure: process.env.SMTP_SECURE === 'true', auth: { - user: process.env.SMTP_USER, - pass: process.env.SMTP_PASS + user: smtpUser, + pass: smtpPass } }) } diff --git a/server/utils/members.js b/server/utils/members.js index 13a986c..e01a1ff 100644 --- a/server/utils/members.js +++ b/server/utils/members.js @@ -20,7 +20,7 @@ const MEMBERS_FILE = getDataPath('members.json') // Get encryption key from environment or config function getEncryptionKey() { - return process.env.ENCRYPTION_KEY || 'default-key-change-in-production' + return process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production' } // Check if data is encrypted by trying to parse as JSON first