2022-04-05 16:31:53 +02:00
|
|
|
export const httpStreamOutput = function(readStream, name, http, downloadFlag, cacheControl) {
|
|
|
|
|
readStream.on('data', data => {
|
|
|
|
|
http.response.write(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
readStream.on('end', () => {
|
|
|
|
|
// don't pass parameters to end() or it will be attached to the file's binary stream
|
|
|
|
|
http.response.end();
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-23 13:40:14 +03:00
|
|
|
readStream.on('error', (err) => {
|
|
|
|
|
console.error(`Download stream error for file '${name}':`, err);
|
2022-04-05 16:31:53 +02:00
|
|
|
http.response.statusCode = 404;
|
|
|
|
|
http.response.end('not found');
|
|
|
|
|
});
|
|
|
|
|
|
2022-04-07 23:06:16 +02:00
|
|
|
if (cacheControl) {
|
|
|
|
|
http.response.setHeader('Cache-Control', cacheControl);
|
|
|
|
|
}
|
2025-10-10 23:06:06 +03:00
|
|
|
|
|
|
|
|
// Set Content-Disposition header
|
2022-04-05 16:31:53 +02:00
|
|
|
http.response.setHeader('Content-Disposition', getContentDisposition(name, http?.params?.query?.download));
|
2025-10-10 23:06:06 +03:00
|
|
|
|
|
|
|
|
// Add security headers to prevent XSS attacks
|
|
|
|
|
const isSvgFile = name && name.toLowerCase().endsWith('.svg');
|
|
|
|
|
if (isSvgFile) {
|
|
|
|
|
// For SVG files, add strict CSP to prevent script execution
|
|
|
|
|
http.response.setHeader('Content-Security-Policy', "default-src 'none'; script-src 'none'; object-src 'none';");
|
|
|
|
|
http.response.setHeader('X-Content-Type-Options', 'nosniff');
|
|
|
|
|
http.response.setHeader('X-Frame-Options', 'DENY');
|
|
|
|
|
}
|
2022-04-05 16:31:53 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** will initiate download, if links are called with ?download="true" queryparam */
|
|
|
|
|
const getContentDisposition = (name, downloadFlag) => {
|
2025-10-10 23:06:06 +03:00
|
|
|
// Force attachment disposition for SVG files to prevent XSS attacks
|
|
|
|
|
const isSvgFile = name && name.toLowerCase().endsWith('.svg');
|
|
|
|
|
const forceAttachment = isSvgFile || downloadFlag === 'true';
|
|
|
|
|
const dispositionType = forceAttachment ? 'attachment;' : 'inline;';
|
2022-04-05 16:31:53 +02:00
|
|
|
|
|
|
|
|
const encodedName = encodeURIComponent(name);
|
|
|
|
|
const dispositionName = `filename="${encodedName}"; filename=*UTF-8"${encodedName}";`;
|
|
|
|
|
const dispositionEncoding = 'charset=utf-8';
|
|
|
|
|
|
|
|
|
|
return `${dispositionType} ${dispositionName} ${dispositionEncoding}`;
|
|
|
|
|
};
|