diff --git a/backend/src/tools/dateien/routes.js b/backend/src/tools/dateien/routes.js index 779bb7c..883032b 100644 --- a/backend/src/tools/dateien/routes.js +++ b/backend/src/tools/dateien/routes.js @@ -149,7 +149,8 @@ router.get('/', authenticate, (req, res) => { const sharedByMe = folderId ? [] : db.prepare(` SELECT DISTINCT f.*, u.username as owner, GROUP_CONCAT(su.username) as shared_with_names, - MIN(s.created_at) as shared_at + MIN(s.created_at) as shared_at, + MAX(s.accessed_at) as accessed_at FROM files f JOIN users u ON u.id=f.user_id JOIN file_shares s ON s.file_id=f.id JOIN users su ON su.id=s.shared_with @@ -193,16 +194,34 @@ router.post('/', authenticate, (req, res) => { }); }); -router.get('/:id/download', authenticate, (req, res) => { +router.get('/:id/download', authenticate, async (req, res) => { const uid = req.user.id; const file = db.prepare('SELECT * FROM files WHERE id=?').get(req.params.id); if (!file) return res.status(404).json({ error: 'Nicht gefunden' }); - const ok = file.user_id===uid - || db.prepare('SELECT id FROM file_shares WHERE file_id=? AND shared_with=?').get(file.id, uid) - || (file.folder_id && isInSharedFolder(file.folder_id, uid)); - if (!ok) return res.status(403).json({ error: 'Kein Zugriff' }); + + const isOwner = file.user_id === uid; + const share = db.prepare('SELECT * FROM file_shares WHERE file_id=? AND shared_with=?').get(file.id, uid); + const inSharedDir = file.folder_id && isInSharedFolder(file.folder_id, uid); + + if (!isOwner && !share && !inSharedDir) return res.status(403).json({ error: 'Kein Zugriff' }); + + // Passwortprüfung für Shares (Owner braucht kein Passwort) + if (!isOwner && share?.password_hash) { + const bcrypt = require('bcryptjs'); + const pw = req.query.password || req.headers['x-share-password'] || ''; + const ok = pw && await bcrypt.compare(pw, share.password_hash); + if (!ok) return res.status(403).json({ error: 'Falsches Passwort', passwordRequired: true }); + } + const fp = path.join(UPLOAD_DIR, file.filename); if (!fs.existsSync(fp)) return res.status(404).json({ error: 'Datei fehlt' }); + + // Zugriff tracken + if (share && !share.accessed_at) { + db.prepare("UPDATE file_shares SET accessed_at = datetime('now','localtime') WHERE file_id=? AND shared_with=?") + .run(file.id, uid); + } + res.download(fp, file.originalname); }); @@ -217,16 +236,34 @@ router.delete('/:id', authenticate, (req, res) => { router.get('/:id/shares', authenticate, (req, res) => { const file = db.prepare('SELECT * FROM files WHERE id=? AND user_id=?').get(req.params.id, req.user.id); if (!file) return res.status(404).json({ error: 'Nicht gefunden' }); - res.json(db.prepare('SELECT u.id,u.username,s.created_at as shared_at FROM file_shares s JOIN users u ON u.id=s.shared_with WHERE s.file_id=?').all(file.id)); + res.json(db.prepare(` + SELECT u.id, u.username, s.created_at as shared_at, + s.accessed_at, + CASE WHEN s.password_hash IS NOT NULL THEN 1 ELSE 0 END as has_password + FROM file_shares s JOIN users u ON u.id=s.shared_with + WHERE s.file_id=? + `).all(file.id)); }); -router.post('/:id/share', authenticate, (req, res) => { +router.post('/:id/share', authenticate, async (req, res) => { const file = db.prepare('SELECT * FROM files WHERE id=? AND user_id=?').get(req.params.id, req.user.id); if (!file) return res.status(404).json({ error: 'Nicht gefunden' }); const target = db.prepare('SELECT * FROM users WHERE username=?').get(req.body.username); if (!target) return res.status(404).json({ error: 'Benutzer nicht gefunden' }); if (target.id === req.user.id) return res.status(400).json({ error: 'Kann nicht mit dir selbst teilen' }); - db.prepare('INSERT OR IGNORE INTO file_shares (file_id,shared_by,shared_with) VALUES (?,?,?)').run(file.id, req.user.id, target.id); + let passwordHash = null; + if (req.body.password) { + const bcrypt = require('bcryptjs'); + passwordHash = await bcrypt.hash(req.body.password, 10); + } + const existing = db.prepare('SELECT id FROM file_shares WHERE file_id=? AND shared_with=?').get(file.id, target.id); + if (existing) { + db.prepare('UPDATE file_shares SET password_hash=?, accessed_at=NULL WHERE file_id=? AND shared_with=?') + .run(passwordHash, file.id, target.id); + } else { + db.prepare('INSERT INTO file_shares (file_id,shared_by,shared_with,password_hash) VALUES (?,?,?,?)') + .run(file.id, req.user.id, target.id, passwordHash); + } res.json({ success: true }); });