const { URL } = require('url'); /** * Anti-hotlinking middleware. Ensures that requests for assets originate * from the official app domain (SYSTEM_HOST). Blocks direct URL access. */ const verifyReferer = (req, res, next) => { const referer = req.headers.referer; const origin = req.headers.origin; const systemHost = process.env.SYSTEM_HOST || 'http://localhost:5000'; let allowedOrigin; try { allowedOrigin = new URL(systemHost).origin; } catch (e) { allowedOrigin = systemHost; } const isMatch = (headerValue) => { if (!headerValue) return false; try { return new URL(headerValue).origin === allowedOrigin; } catch (e) { return headerValue.startsWith(allowedOrigin); } }; const hasValidReferer = isMatch(referer); const hasValidOrigin = isMatch(origin); // Block request if both referer and origin are missing or do not match SYSTEM_HOST if (!hasValidReferer && !hasValidOrigin) { return res.status(403).json({ message: 'Access denied: Hotlinking detected or direct file access is prohibited.' }); } next(); }; /** * Cache prevention middleware. Ensures that sensitive image assets are never * cached by client browsers or intermediate proxies. */ const setNoCacheHeaders = (req, res, next) => { res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); next(); }; module.exports = { verifyReferer, setNoCacheHeaders };