fix(slideshow): deny display-only token on download/upload/feedback (PR #646 review)
The slideshow JWT reuses type:'gallery', so verifyGalleryAccess accepts it on every gallery route — a leaked projector link could download (single/all/ selected), upload (when allow_user_uploads), or post feedback for up to ~12h, beyond its display-only contract. Add a `denySlideshowToken` middleware (403 when req.accessLevel==='slideshow') after verifyGalleryAccess on those 5 routes. The photo-display routes (/photos, photo/thumbnail/preview/hero) stay open — the kiosk needs them. +4 tests mint a real slideshow JWT and assert 403. Docs note that Regenerate/Disable isn't instant revocation (~12h) and the feature flag is the hard cut-off.
This commit is contained in:
@@ -171,7 +171,25 @@ async function verifyGalleryAccess(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny a slideshow-scoped JWT. The Live Slideshow token (accessLevel
|
||||
* 'slideshow') is reused as a `type:'gallery'` token so it can read photos for
|
||||
* the kiosk, which means every verifyGalleryAccess-protected route would
|
||||
* otherwise accept it. A projector URL is meant to be display-only and is
|
||||
* comparatively easy to leak (browser history, venue laptop, USB), so this
|
||||
* gate is placed AFTER verifyGalleryAccess on the write/bulk-download routes to
|
||||
* keep a leaked slideshow link from downloading, uploading, or posting
|
||||
* feedback. (#646 review)
|
||||
*/
|
||||
function denySlideshowToken(req, res, next) {
|
||||
if (req.accessLevel === 'slideshow') {
|
||||
return res.status(403).json({ error: 'Slideshow tokens are display-only' });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
verifyGalleryAccess,
|
||||
denySlideshowToken,
|
||||
isAdminPreview
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user