From 67c8d01533d8820fe93e11a6fe37447f732690c2 Mon Sep 17 00:00:00 2001 From: Dicken Date: Thu, 28 May 2026 00:23:38 +0200 Subject: [PATCH] Dateien nach "backend/src" hochladen --- backend/src/db.js | 44 +++++++++++++++++++++++++++++++++----------- backend/src/index.js | 23 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/backend/src/db.js b/backend/src/db.js index 849c87c..3098b88 100644 --- a/backend/src/db.js +++ b/backend/src/db.js @@ -182,15 +182,13 @@ db.exec("UPDATE order_items SET qty_warteliste=stueckzahl WHERE qty_warteliste=0 if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages'").get()) { db.exec(` CREATE TABLE messages ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - recipient_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - encrypted_content TEXT NOT NULL, - iv TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - deleted_by_sender INTEGER NOT NULL DEFAULT 0, - deleted_by_recipient INTEGER NOT NULL DEFAULT 0, - read_by_recipient INTEGER NOT NULL DEFAULT 0 + id INTEGER PRIMARY KEY AUTOINCREMENT, + sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + recipient_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + encrypted_content TEXT NOT NULL, + iv TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + read_by_recipient INTEGER NOT NULL DEFAULT 0 ) `); } @@ -212,9 +210,33 @@ if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='pus ) `); } -// Falls messages-Tabelle alt ist und read_by_recipient fehlt +// Migration: Soft-Delete-Spalten entfernen (nur Nachrichten übernehmen die noch sichtbar waren) const msgCols = db.prepare("PRAGMA table_info(messages)").all().map(r => r.name); -if (msgCols.length && !msgCols.includes('read_by_recipient')) +if (msgCols.includes('deleted_by_sender')) { + db.exec(` + CREATE TABLE messages_v2 ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + recipient_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + encrypted_content TEXT NOT NULL, + iv TEXT NOT NULL, + created_at DATETIME DEFAULT NULL, + read_by_recipient INTEGER NOT NULL DEFAULT 0 + ); + INSERT INTO messages_v2 (id, sender_id, recipient_id, encrypted_content, iv, created_at, read_by_recipient) + SELECT id, sender_id, recipient_id, encrypted_content, iv, created_at, + COALESCE(read_by_recipient, 0) + FROM messages + WHERE deleted_by_sender = 0 AND deleted_by_recipient = 0; + DROP TABLE messages; + ALTER TABLE messages_v2 RENAME TO messages; + `); + console.log('✅ Migration: messages → Hard-Delete (Soft-Delete-Spalten entfernt)'); +} +// Falls read_by_recipient noch fehlt (sehr alte Installation) +const msgCols2 = db.prepare("PRAGMA table_info(messages)").all().map(r => r.name); +if (msgCols2.length && !msgCols2.includes('read_by_recipient')) { db.exec("ALTER TABLE messages ADD COLUMN read_by_recipient INTEGER NOT NULL DEFAULT 0"); +} module.exports = db; diff --git a/backend/src/index.js b/backend/src/index.js index 1b1beb0..24f8ded 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -7,6 +7,29 @@ require('./db'); const app = express(); app.use(express.json()); +// ── Security Headers ────────────────────────────────────────────────────────── +app.use((_req, res, next) => { + res.setHeader('Content-Security-Policy', [ + "default-src 'self'", + "script-src 'self'", + // unsafe-inline nötig für React inline-styles + @import Google Fonts + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com", + "font-src 'self' https://fonts.gstatic.com", + // iCal-Feeds werden serverseitig geprosxt → nur 'self' nötig + "connect-src 'self'", + // data: für Avatare (base64), google.com für Favicons im QuickLinks-Widget + "img-src 'self' data: https://www.google.com", + "worker-src 'self'", + "object-src 'none'", + "base-uri 'self'", + "form-action 'self'", + ].join('; ')); + res.setHeader('X-Content-Type-Options', 'nosniff'); + res.setHeader('X-Frame-Options', 'DENY'); + res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); + next(); +}); + // ── API ─────────────────────────────────────────────────────────────────────── app.use('/api/auth', require('./routes/auth')); app.use('/api/admin', require('./routes/admin'));