Reworked extension parsing

Removed "path-complete-extname" module in favor of an in-house solution, utilsController.extname().

For now the function will attempt to preserve multi-archive extensions (.001, .002, and so on), as well as some known tarballs (.tar.gz and the likes).

The function will always return lower case extension. It should be fine, but do keep it in mind.
This commit is contained in:
Bobby Wibowo 2018-09-18 02:32:27 +07:00
parent b47bbb90d6
commit 65442c18c5
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
5 changed files with 39 additions and 18 deletions

View File

@ -3,7 +3,6 @@ const db = require('knex')(config.database)
const EventEmitter = require('events')
const fs = require('fs')
const path = require('path')
const pce = require('path-complete-extname')
const randomstring = require('randomstring')
const utils = require('./utilsController')
const Zip = require('jszip')
@ -299,7 +298,7 @@ albumsController.get = async (req, res, next) => {
for (const file of files) {
file.file = `${config.domain}/${file.name}`
const extname = pce(file.name).toLowerCase()
const extname = utils.extname(file.name)
if (utils.mayGenerateThumb(extname)) {
file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -extname.length)}.png`
}

View File

@ -4,7 +4,6 @@ const db = require('knex')(config.database)
const fs = require('fs')
const multer = require('multer')
const path = require('path')
const pce = require('path-complete-extname')
const randomstring = require('randomstring')
const snekfetch = require('snekfetch')
const utils = require('./utilsController')
@ -40,7 +39,7 @@ const storage = multer.diskStorage({
filename (req, file, cb) {
// If chunked uploads is disabled or the uploaded file is not a chunk
if (!chunkedUploads || (req.body.uuid === undefined && req.body.chunkindex === undefined)) {
const extension = pce(file.originalname).toLowerCase()
const extension = utils.extname(file.originalname)
const length = uploadsController.getFileNameLength(req)
return uploadsController.getUniqueRandomName(length, extension)
.then(name => cb(null, name))
@ -61,7 +60,7 @@ const upload = multer({
fileSize: maxSizeBytes
},
fileFilter (req, file, cb) {
const extname = pce(file.originalname).toLowerCase()
const extname = utils.extname(file.originalname)
if (uploadsController.isExtensionFiltered(extname)) {
// eslint-disable-next-line standard/no-callback-literal
return cb(`${extname.substr(1).toUpperCase()} files are not permitted due to security reasons.`)
@ -216,7 +215,7 @@ uploadsController.actuallyUploadByUrl = async (req, res, user, albumid) => {
const infoMap = []
for (const url of urls) {
const original = path.basename(url).split(/[?#]/)[0]
const extension = pce(original).toLowerCase()
const extension = utils.extname(original)
if (uploadsController.isExtensionFiltered(extension)) {
return erred(`${extension.substr(1).toUpperCase()} files are not permitted due to security reasons.`)
}
@ -331,7 +330,7 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
if (error) { return erred(error) }
if (file.count < chunkNames.length) { return erred('Chunks count mismatch.') }
const extension = typeof file.original === 'string' ? pce(file.original).toLowerCase() : ''
const extension = typeof file.original === 'string' ? utils.extname(file.original) : ''
if (uploadsController.isExtensionFiltered(extension)) {
return erred(`${extension.substr(1).toUpperCase()} files are not permitted due to security reasons.`)
}
@ -593,7 +592,7 @@ uploadsController.processFilesForDisplay = async (req, res, files, existingFiles
if (file.albumid && !albumids.includes(file.albumid)) {
albumids.push(file.albumid)
}
if (utils.mayGenerateThumb(pce(file.name).toLowerCase())) {
if (utils.mayGenerateThumb(utils.extname(file.name))) {
utils.generateThumbs(file.name)
}
}
@ -688,7 +687,7 @@ uploadsController.list = async (req, res) => {
}
}
file.extname = pce(file.name).toLowerCase()
file.extname = utils.extname(file.name)
if (utils.mayGenerateThumb(file.extname)) {
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -file.extname.length)}.png`
}

View File

@ -4,7 +4,6 @@ const ffmpeg = require('fluent-ffmpeg')
const fs = require('fs')
const gm = require('gm')
const path = require('path')
const pce = require('path-complete-extname')
const snekfetch = require('snekfetch')
const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
@ -23,6 +22,35 @@ utilsController.mayGenerateThumb = extname => {
(config.uploads.generateThumbs.video && utilsController.videoExtensions.includes(extname))
}
// expand if necessary (must be lower case); for now only preserves some known tarballs
utilsController.preserves = ['.tar.gz', '.tar.z', '.tar.bz2', '.tar.lzma', '.tar.lzo', '.tar.xz']
utilsController.extname = filename => {
let lower = filename.toLowerCase() // due to this, the returned extname will always be lower case
let multi = ''
let extname = ''
// check for multi-archive extensions (.001, .002, and so on)
if (/\.\d{3}$/.test(lower)) {
multi = lower.slice(lower.lastIndexOf('.') - lower.length)
lower = lower.slice(0, lower.lastIndexOf('.'))
}
// check against extensions that must be preserved
for (let i = 0; i < utilsController.preserves.length; i++) {
if (lower.endsWith(utilsController.preserves[i])) {
extname = utilsController.preserves[i]
break
}
}
if (!extname) {
extname = lower.slice(lower.lastIndexOf('.') - lower.length) // path.extname(lower)
}
return extname + multi
}
utilsController.getPrettyDate = date => {
return date.getFullYear() + '-' +
(date.getMonth() + 1) + '-' +
@ -66,7 +94,7 @@ utilsController.authorize = async (req, res) => {
utilsController.generateThumbs = (name, force) => {
return new Promise(resolve => {
const extname = pce(name).toLowerCase()
const extname = utilsController.extname(name)
const thumbname = path.join(thumbsDir, name.slice(0, -extname.length) + '.png')
fs.lstat(thumbname, async (error, stats) => {
if (error && error.code !== 'ENOENT') {
@ -130,7 +158,7 @@ utilsController.generateThumbs = (name, force) => {
utilsController.deleteFile = file => {
return new Promise((resolve, reject) => {
const extname = pce(file).toLowerCase()
const extname = utilsController.extname(file)
return fs.unlink(path.join(uploadsDir, file), error => {
if (error && error.code !== 'ENOENT') { return reject(error) }
@ -224,7 +252,7 @@ utilsController.purgeCloudflareCache = async names => {
const thumbs = []
names = names.map(name => {
const url = `${config.domain}/${name}`
const extname = pce(name).toLowerCase()
const extname = utilsController.extname(name)
if (utilsController.mayGenerateThumb(extname)) {
thumbs.push(`${config.domain}/thumbs/${name.slice(0, -extname.length)}.png`)
}

View File

@ -33,7 +33,6 @@
"knex": "^0.14.6",
"multer": "^1.3.0",
"nunjucks": "^3.1.2",
"path-complete-extname": "^1.0.0",
"randomstring": "^1.1.5",
"snekfetch": "^3.6.4",
"sqlite3": "^4.0.0"

View File

@ -2015,10 +2015,6 @@ pascalcase@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
path-complete-extname@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/path-complete-extname/-/path-complete-extname-1.0.0.tgz#f889985dc91000c815515c0bfed06c5acda0752b"
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"