From ae6d7936c71a28f201bf4ff8d33bba2b50601108 Mon Sep 17 00:00:00 2001 From: Bobby Wibowo Date: Mon, 1 Feb 2021 06:13:37 +0700 Subject: [PATCH] feat: blacklist extensions for strip tags GIFs are known to not work without custom globally-installed libvips with ImageMagick or GraphicsMagick support. https://sharp.pixelplumbing.com/api-output#gif https://sharp.pixelplumbing.com/install#custom-libvips It's highly recommended to update your config following the changes to the sample config file. This also addressed a bug where images would still get recorded to DB despite them not existing physically due to strip tags errors. --- config.sample.js | 11 +++++++++-- controllers/utilsController.js | 22 ++++++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/config.sample.js b/config.sample.js index 456de83..6deae62 100644 --- a/config.sample.js +++ b/config.sample.js @@ -474,11 +474,11 @@ module.exports = { /* Thumbnails are only used in the dashboard and album's public pages. You need to install a separate binary called ffmpeg (https://ffmpeg.org/) for video thumbnails. - NOTE: Placeholder defaults to 'public/images/unavailable.png'. */ generateThumbs: { image: true, video: false, + // Placeholder defaults to 'public/images/unavailable.png'. placeholder: null, size: 200 }, @@ -503,7 +503,14 @@ module.exports = { stripTags: { default: false, video: false, - force: false + force: false, + // Supporting the extensions below requires using custom globally-installed libvips. + // https://sharp.pixelplumbing.com/install#custom-libvips + blacklistExtensions: [ + // GIFs require libvips compiled with ImageMagick/GraphicsMagick support. + // https://sharp.pixelplumbing.com/api-output#gif + '.gif' + ] }, /* diff --git a/controllers/utilsController.js b/controllers/utilsController.js index 6a1221f..4ccd550 100644 --- a/controllers/utilsController.js +++ b/controllers/utilsController.js @@ -8,6 +8,7 @@ const paths = require('./pathsController') const perms = require('./permissionController') const apiErrorsHandler = require('./handlers/apiErrorsHandler') const ClientError = require('./utils/ClientError') +const ServerError = require('./utils/ServerError') const config = require('./../config') const logger = require('./../logger') const db = require('knex')(config.database) @@ -32,6 +33,10 @@ const self = { videoExts: ['.3g2', '.3gp', '.asf', '.avchd', '.avi', '.divx', '.evo', '.flv', '.h264', '.h265', '.hevc', '.m2p', '.m2ts', '.m4v', '.mk3d', '.mkv', '.mov', '.mp4', '.mpeg', '.mpg', '.mxf', '.ogg', '.ogv', '.ps', '.qt', '.rmvb', '.ts', '.vob', '.webm', '.wmv'], audioExts: ['.flac', '.mp3', '.wav', '.wma'], + stripTagsBlacklistedExts: Array.isArray(config.uploads.stripTags.blacklistExtensions) + ? config.uploads.stripTags.blacklistExtensions + : [], + thumbsSize: config.uploads.generateThumbs.size || 200, ffprobe: promisify(ffmpeg.ffprobe), @@ -309,7 +314,7 @@ self.generateThumbs = async (name, extname, force) => { return false } } catch (error) { - logger.error(`[${name}]: ${error.toString().trim()}`) + logger.error(`[${name}]: generateThumbs(): ${error.toString().trim()}`) try { await paths.unlink(thumbname).catch(() => {}) // try to unlink incomplete thumbs first await paths.symlink(paths.thumbPlaceholder, thumbname) @@ -325,8 +330,10 @@ self.generateThumbs = async (name, extname, force) => { self.stripTags = async (name, extname) => { extname = extname.toLowerCase() + if (self.stripTagsBlacklistedExts.includes(extname)) return false + const fullpath = path.join(paths.uploads, name) - let tmpfile + let tmpfile, isError try { if (self.imageExts.includes(extname)) { @@ -351,9 +358,12 @@ self.stripTags = async (name, extname) => { .on('end', () => resolve(true)) .run() }) + } else { + return false } } catch (error) { - logger.error(`[${name}]: ${error.toString().trim()}`) + logger.error(`[${name}]: stripTags(): ${error.toString().trim()}`) + isError = true } if (tmpfile) { @@ -361,11 +371,15 @@ self.stripTags = async (name, extname) => { await paths.unlink(tmpfile) } catch (error) { if (error.code !== 'ENOENT') { - logger.error(`[${name}]: ${error.toString().trim()}`) + logger.error(`[${name}]: stripTags(): ${error.toString().trim()}`) } } } + if (isError) { + throw new ServerError('An error occurred while stripping tags. The format may not be supported.') + } + return true }