Add proper filename to the content-disposition header

By default we take the slug given in the request, if this is not set we try to give a filename from known types.
If we still have no filename we fallback to the previous method of setting no filename.

If the filename is non ascii we will only create the encoded "filename*" and not the ascii only "filename". This is to prevent other applications to save a file like "?????.png" if the filename contains non ascii chars.

For the browsers nothing will really change comapred to the behaviour before this change as good fallbacks if no content-disposition filename is set. But that is not the case for all application, thus it makes sense to include the proper way to set the filename.
This commit is contained in:
Nachtalb 2021-04-03 12:32:49 +02:00
parent 8dd9bc0e98
commit 14d76f8023
No known key found for this signature in database
GPG key ID: E48DF13C07055D92
2 changed files with 36 additions and 23 deletions

View file

@ -45,6 +45,7 @@
"chalk": "4.1.0",
"cheerio": "1.0.0-rc.5",
"commander": "7.2.0",
"content-disposition": "0.5.3",
"express": "4.17.1",
"file-type": "16.2.0",
"filenamify": "4.2.0",

View file

@ -10,26 +10,27 @@ const readChunk = require("read-chunk");
const crypto = require("crypto");
const isUtf8 = require("is-utf8");
const log = require("../log");
const contentDisposition = require("content-disposition");
// List of allowed mime types that can be rendered in browser
// without forcing it to be downloaded
const inlineContentDispositionTypes = [
"application/ogg",
"audio/midi",
"audio/mpeg",
"audio/ogg",
"audio/vnd.wave",
"image/bmp",
"image/gif",
"image/jpeg",
"image/png",
"image/webp",
"image/avif",
"text/plain",
"video/mp4",
"video/ogg",
"video/webm",
];
// Map of allowed mime types to their respecive default filenames
// that will be rendered in browser without forcing them to be downloaded
const inlineContentDispositionTypes = {
"application/ogg": "media.ogx",
"audio/midi": "audio.midi",
"audio/mpeg": "audio.mp3",
"audio/ogg": "audio.ogg",
"audio/vnd.wave": "audio.wav",
"image/bmp": "image.bmp",
"image/gif": "image.gif",
"image/jpeg": "image.jpg",
"image/png": "image.png",
"image/webp": "image.webp",
"image/avif": "image.avif",
"text/plain": "text.txt",
"video/mp4": "video.mp4",
"video/ogg": "video.ogv",
"video/webm": "video.webm",
};
const uploadTokens = new Map();
@ -92,9 +93,20 @@ class Uploader {
}
// Force a download in the browser if it's not an allowed type (binary or otherwise unknown)
const contentDisposition = inlineContentDispositionTypes.includes(detectedMimeType)
? "inline"
: "attachment";
let slug = req.params.slug;
const isInline = detectedMimeType in inlineContentDispositionTypes;
let disposition = isInline ? "inline" : "attachment";
if (!slug && isInline) {
slug = inlineContentDispositionTypes[detectedMimeType];
}
if (slug) {
disposition = contentDisposition(slug.trim(), {
fallback: false,
type: disposition,
});
}
if (detectedMimeType === "audio/vnd.wave") {
// Send a more common mime type for wave audio files
@ -102,7 +114,7 @@ class Uploader {
detectedMimeType = "audio/wav";
}
res.setHeader("Content-Disposition", contentDisposition);
res.setHeader("Content-Disposition", disposition);
res.setHeader("Cache-Control", "max-age=86400");
res.contentType(detectedMimeType);