mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
Block uploads for demo user, restore PDF preview modal (v2.2.3)
- Demo user gets 403 on all upload endpoints (files, photos, cover, avatar) - Admin uploads still work normally - PDF export back in modal popup using srcdoc iframe - Zero behavior change when DEMO_MODE is not set
This commit is contained in:
@@ -356,10 +356,37 @@ ${daysHtml}
|
|||||||
|
|
||||||
</body></html>`
|
</body></html>`
|
||||||
|
|
||||||
// Open in new window
|
// Open in modal with srcdoc iframe (no URL loading = no X-Frame-Options issue)
|
||||||
const win = window.open('', '_blank')
|
const overlay = document.createElement('div')
|
||||||
if (win) {
|
overlay.id = 'pdf-preview-overlay'
|
||||||
win.document.write(html)
|
overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:9999;display:flex;align-items:center;justify-content:center;padding:8px;'
|
||||||
win.document.close()
|
overlay.onclick = (e) => { if (e.target === overlay) overlay.remove() }
|
||||||
}
|
|
||||||
|
const card = document.createElement('div')
|
||||||
|
card.style.cssText = 'width:100%;max-width:1000px;height:95vh;background:var(--bg-card);border-radius:12px;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 20px 60px rgba(0,0,0,0.3);'
|
||||||
|
|
||||||
|
const header = document.createElement('div')
|
||||||
|
header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--border-primary);flex-shrink:0;'
|
||||||
|
header.innerHTML = `
|
||||||
|
<span style="font-size:13px;font-weight:600;color:var(--text-primary)">${escHtml(trip?.name || tr('pdf.travelPlan'))}</span>
|
||||||
|
<div style="display:flex;align-items:center;gap:8px">
|
||||||
|
<button id="pdf-print-btn" style="display:flex;align-items:center;gap:5px;font-size:12px;font-weight:500;color:var(--text-muted);background:none;border:none;cursor:pointer;padding:4px 8px;border-radius:6px;font-family:inherit">${tr('pdf.saveAsPdf')}</button>
|
||||||
|
<button id="pdf-close-btn" style="background:none;border:none;cursor:pointer;color:var(--text-faint);display:flex;padding:4px;border-radius:6px">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const iframe = document.createElement('iframe')
|
||||||
|
iframe.style.cssText = 'flex:1;width:100%;border:none;'
|
||||||
|
iframe.sandbox = 'allow-same-origin allow-modals'
|
||||||
|
iframe.srcdoc = html
|
||||||
|
|
||||||
|
card.appendChild(header)
|
||||||
|
card.appendChild(iframe)
|
||||||
|
overlay.appendChild(card)
|
||||||
|
document.body.appendChild(overlay)
|
||||||
|
|
||||||
|
header.querySelector('#pdf-close-btn').onclick = () => overlay.remove()
|
||||||
|
header.querySelector('#pdf-print-btn').onclick = () => { iframe.contentWindow?.print() }
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nomad-server",
|
"name": "nomad-server",
|
||||||
"version": "2.2.2",
|
"version": "2.2.3",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --experimental-sqlite src/index.js",
|
"start": "node --experimental-sqlite src/index.js",
|
||||||
|
|||||||
@@ -53,4 +53,11 @@ const adminOnly = (req, res, next) => {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { authenticate, optionalAuth, adminOnly };
|
const demoUploadBlock = (req, res, next) => {
|
||||||
|
if (process.env.DEMO_MODE === 'true' && req.user?.email === 'demo@nomad.app') {
|
||||||
|
return res.status(403).json({ error: 'Uploads are disabled in demo mode. Self-host NOMAD for full functionality.' });
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = { authenticate, optionalAuth, adminOnly, demoUploadBlock };
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const fs = require('fs');
|
|||||||
const { v4: uuid } = require('uuid');
|
const { v4: uuid } = require('uuid');
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const { db } = require('../db/database');
|
const { db } = require('../db/database');
|
||||||
const { authenticate } = require('../middleware/auth');
|
const { authenticate, demoUploadBlock } = require('../middleware/auth');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { JWT_SECRET } = require('../config');
|
const { JWT_SECRET } = require('../config');
|
||||||
@@ -243,7 +243,7 @@ router.get('/me/settings', authenticate, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/auth/avatar — upload avatar
|
// POST /api/auth/avatar — upload avatar
|
||||||
router.post('/avatar', authenticate, avatarUpload.single('avatar'), (req, res) => {
|
router.post('/avatar', authenticate, demoUploadBlock, avatarUpload.single('avatar'), (req, res) => {
|
||||||
if (!req.file) return res.status(400).json({ error: 'No image uploaded' });
|
if (!req.file) return res.status(400).json({ error: 'No image uploaded' });
|
||||||
|
|
||||||
const current = db.prepare('SELECT avatar FROM users WHERE id = ?').get(req.user.id);
|
const current = db.prepare('SELECT avatar FROM users WHERE id = ?').get(req.user.id);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const { db, canAccessTrip } = require('../db/database');
|
const { db, canAccessTrip } = require('../db/database');
|
||||||
const { authenticate } = require('../middleware/auth');
|
const { authenticate, demoUploadBlock } = require('../middleware/auth');
|
||||||
const { broadcast } = require('../websocket');
|
const { broadcast } = require('../websocket');
|
||||||
|
|
||||||
const router = express.Router({ mergeParams: true });
|
const router = express.Router({ mergeParams: true });
|
||||||
@@ -72,7 +72,7 @@ router.get('/', authenticate, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/trips/:tripId/files
|
// POST /api/trips/:tripId/files
|
||||||
router.post('/', authenticate, upload.single('file'), (req, res) => {
|
router.post('/', authenticate, demoUploadBlock, upload.single('file'), (req, res) => {
|
||||||
const { tripId } = req.params;
|
const { tripId } = req.params;
|
||||||
const { place_id, description, reservation_id } = req.body;
|
const { place_id, description, reservation_id } = req.body;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const { db, canAccessTrip } = require('../db/database');
|
const { db, canAccessTrip } = require('../db/database');
|
||||||
const { authenticate } = require('../middleware/auth');
|
const { authenticate, demoUploadBlock } = require('../middleware/auth');
|
||||||
|
|
||||||
const router = express.Router({ mergeParams: true });
|
const router = express.Router({ mergeParams: true });
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ router.get('/', authenticate, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/trips/:tripId/photos
|
// POST /api/trips/:tripId/photos
|
||||||
router.post('/', authenticate, upload.array('photos', 20), (req, res) => {
|
router.post('/', authenticate, demoUploadBlock, upload.array('photos', 20), (req, res) => {
|
||||||
const { tripId } = req.params;
|
const { tripId } = req.params;
|
||||||
const { day_id, place_id, caption } = req.body;
|
const { day_id, place_id, caption } = req.body;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const { db, canAccessTrip, isOwner } = require('../db/database');
|
const { db, canAccessTrip, isOwner } = require('../db/database');
|
||||||
const { authenticate } = require('../middleware/auth');
|
const { authenticate, demoUploadBlock } = require('../middleware/auth');
|
||||||
const { broadcast } = require('../websocket');
|
const { broadcast } = require('../websocket');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@@ -139,7 +139,7 @@ router.put('/:id', authenticate, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/trips/:id/cover
|
// POST /api/trips/:id/cover
|
||||||
router.post('/:id/cover', authenticate, uploadCover.single('cover'), (req, res) => {
|
router.post('/:id/cover', authenticate, demoUploadBlock, uploadCover.single('cover'), (req, res) => {
|
||||||
if (!isOwner(req.params.id, req.user.id))
|
if (!isOwner(req.params.id, req.user.id))
|
||||||
return res.status(403).json({ error: 'Nur der Eigentümer kann das Titelbild ändern' });
|
return res.status(403).json({ error: 'Nur der Eigentümer kann das Titelbild ändern' });
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user