Added setContentDisposition option

Resolves #192

This added 2 new dependencies:
content-disposition
BobbyWibowo/serve-static

content-disposition:
This has fallback generation for file names that are outside ISO-8859-1.
Plus it was already a sub-dependency due to express to begin with.

BobbyWibowo/serve-static:
A fork of express/serve-static to allow specifying an async setHeaders
function by the name preSetHeaders, that will be awaited before
creating send stream to clients.
This commit is contained in:
Bobby Wibowo 2020-09-27 04:33:42 +07:00
parent a79117f893
commit c8a5f7be16
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
4 changed files with 50 additions and 5 deletions

View File

@ -30,6 +30,12 @@ module.exports = {
serveFilesWithNode: false, serveFilesWithNode: false,
domain: 'https://lolisafe.moe', domain: 'https://lolisafe.moe',
/*
If you serve files with node, you can optionally choose to set Content-Disposition header
into their original file names. This allows users to save files into their original file names.
*/
setContentDisposition: false,
/* /*
If you are serving your files with a different domain than your lolisafe homepage, If you are serving your files with a different domain than your lolisafe homepage,
then fill this option with your lolisafe homepage, otherwise any falsy value. then fill this option with your lolisafe homepage, otherwise any falsy value.

View File

@ -1,11 +1,13 @@
const bodyParser = require('body-parser') const bodyParser = require('body-parser')
const clamd = require('clamdjs') const clamd = require('clamdjs')
const contentDisposition = require('content-disposition')
const express = require('express') const express = require('express')
const helmet = require('helmet') const helmet = require('helmet')
const nunjucks = require('nunjucks') const nunjucks = require('nunjucks')
const path = require('path') const path = require('path')
const RateLimit = require('express-rate-limit') const RateLimit = require('express-rate-limit')
const readline = require('readline') const readline = require('readline')
const serveStatic = require('serve-static')
const config = require('./config') const config = require('./config')
const logger = require('./logger') const logger = require('./logger')
const versions = require('./src/versions') const versions = require('./src/versions')
@ -65,6 +67,33 @@ let setHeaders = res => {
res.set('Access-Control-Allow-Origin', '*') res.set('Access-Control-Allow-Origin', '*')
} }
const initServeStaticUploads = (opts = {}) => {
if (config.setContentDisposition) {
opts.preSetHeaders = async (res, path) => {
// Do only if accessing files from uploads' root directory (i.e. not thumbs, etc.)
// and only if they're GET requests
if (path.indexOf('/', 1) === -1 && res.req.method === 'GET') {
const name = path.substring(1)
try {
const file = await db.table('files')
.where('name', name)
.select('original')
.first()
res.set('Content-Disposition', contentDisposition(file.original, { type: 'inline' }))
} catch (error) {
logger.error(error)
}
}
}
// serveStatic is just a modified express/serve-static module that allows specifying
// an async setHeaders function by the name preSetHeaders.
// The module will wait for the said function before creating send stream to client.
safe.use('/', serveStatic(paths.uploads, opts))
} else {
safe.use('/', express.static(paths.uploads, opts))
}
}
// Cache control (safe.fiery.me) // Cache control (safe.fiery.me)
if (config.cacheControl) { if (config.cacheControl) {
const cacheControls = { const cacheControls = {
@ -96,7 +125,7 @@ if (config.cacheControl) {
// If serving uploads with node // If serving uploads with node
if (config.serveFilesWithNode) if (config.serveFilesWithNode)
safe.use('/', express.static(paths.uploads, { initServeStaticUploads({
setHeaders: res => { setHeaders: res => {
res.set('Access-Control-Allow-Origin', '*') res.set('Access-Control-Allow-Origin', '*')
// If using CDN, cache uploads in CDN as well // If using CDN, cache uploads in CDN as well
@ -104,7 +133,7 @@ if (config.cacheControl) {
if (config.cacheControl !== 2) if (config.cacheControl !== 2)
res.set('Cache-Control', cacheControls.cdn) res.set('Cache-Control', cacheControls.cdn)
} }
})) })
// Function for static assets. // Function for static assets.
// This requires the assets to use version in their query string, // This requires the assets to use version in their query string,
@ -125,8 +154,7 @@ if (config.cacheControl) {
next() next()
}) })
} else if (config.serveFilesWithNode) { } else if (config.serveFilesWithNode) {
// If serving uploads with node initServeStaticUploads()
safe.use('/', express.static(paths.uploads))
} }
// Static assets // Static assets

View File

@ -36,6 +36,7 @@
"blake3": "~2.1.4", "blake3": "~2.1.4",
"body-parser": "~1.19.0", "body-parser": "~1.19.0",
"clamdjs": "~1.0.2", "clamdjs": "~1.0.2",
"content-disposition": "~0.5.3",
"express": "~4.17.1", "express": "~4.17.1",
"express-rate-limit": "~5.1.3", "express-rate-limit": "~5.1.3",
"fluent-ffmpeg": "~2.1.2", "fluent-ffmpeg": "~2.1.2",
@ -48,6 +49,7 @@
"randomstring": "~1.1.5", "randomstring": "~1.1.5",
"readline": "~1.3.0", "readline": "~1.3.0",
"search-query-parser": "~1.5.5", "search-query-parser": "~1.5.5",
"serve-static": "git+https://git@github.com/BobbyWibowo/serve-static#60049dec396615ab738d29576a65432e4f9d7d4a",
"sharp": "~0.26.0", "sharp": "~0.26.0",
"sqlite3": "~5.0.0", "sqlite3": "~5.0.0",
"systeminformation": "~4.27.3" "systeminformation": "~4.27.3"

View File

@ -1440,7 +1440,7 @@ contains-path@^0.1.0:
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
content-disposition@0.5.3: content-disposition@0.5.3, content-disposition@~0.5.3:
version "0.5.3" version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
@ -6788,6 +6788,15 @@ serve-static@1.14.1:
parseurl "~1.3.3" parseurl "~1.3.3"
send "0.17.1" send "0.17.1"
"serve-static@git+https://git@github.com/BobbyWibowo/serve-static#60049dec396615ab738d29576a65432e4f9d7d4a":
version "1.14.2"
resolved "git+https://git@github.com/BobbyWibowo/serve-static#60049dec396615ab738d29576a65432e4f9d7d4a"
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.1"
set-blocking@^2.0.0, set-blocking@~2.0.0: set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"