mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
check if image is faulty in enhanceFile
This commit is contained in:
parent
096dba7983
commit
d61104de72
@ -4,11 +4,10 @@
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
const { ApplicationError } = require('@strapi/utils').errors;
|
||||
const sharp = require('sharp');
|
||||
|
||||
const { getService } = require('../utils');
|
||||
const { bytesToKbytes } = require('../utils/file');
|
||||
const { bytesToKbytes, writableStreamDiscard } = require('../utils/file');
|
||||
|
||||
const FORMATS_TO_PROCESS = ['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif'];
|
||||
const FORMATS_TO_OPTIMIZE = ['jpeg', 'png', 'webp', 'tiff'];
|
||||
@ -47,12 +46,7 @@ const THUMBNAIL_RESIZE_OPTIONS = {
|
||||
const resizeFileTo = async (file, options, { name, hash }) => {
|
||||
const filePath = join(file.tmpWorkingDirectory, hash);
|
||||
|
||||
try {
|
||||
await writeStreamToFile(file.getStream().pipe(sharp().resize(options)), filePath);
|
||||
} catch (err) {
|
||||
throw new ApplicationError('File is not a valid image');
|
||||
}
|
||||
|
||||
await writeStreamToFile(file.getStream().pipe(sharp().resize(options)), filePath);
|
||||
const newFile = {
|
||||
name,
|
||||
hash,
|
||||
@ -108,11 +102,7 @@ const optimize = async file => {
|
||||
}
|
||||
const filePath = join(file.tmpWorkingDirectory, `optimized-${file.hash}`);
|
||||
|
||||
try {
|
||||
await writeStreamToFile(file.getStream().pipe(transformer), filePath);
|
||||
} catch {
|
||||
throw new ApplicationError('File is not a valid image');
|
||||
}
|
||||
await writeStreamToFile(file.getStream().pipe(transformer), filePath);
|
||||
|
||||
newFile.getStream = () => fs.createReadStream(filePath);
|
||||
}
|
||||
@ -190,6 +180,20 @@ const isSupportedImage = (...args) => {
|
||||
return isOptimizableImage(...args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies a simple image transformation to see if the image is faulty/corrupted.
|
||||
*/
|
||||
const isFaultyImage = file =>
|
||||
new Promise(resolve => {
|
||||
file
|
||||
.getStream()
|
||||
.pipe(sharp().rotate())
|
||||
.on('error', () => resolve(true))
|
||||
.pipe(writableStreamDiscard())
|
||||
.on('error', () => resolve(true))
|
||||
.on('close', () => resolve(false));
|
||||
});
|
||||
|
||||
const isOptimizableImage = async file => {
|
||||
let format;
|
||||
try {
|
||||
@ -216,6 +220,7 @@ const isImage = async file => {
|
||||
|
||||
module.exports = () => ({
|
||||
isSupportedImage,
|
||||
isFaultyImage,
|
||||
isOptimizableImage,
|
||||
isImage,
|
||||
getDimensions,
|
||||
|
||||
@ -22,6 +22,7 @@ const { NotFoundError } = require('@strapi/utils').errors;
|
||||
|
||||
const { MEDIA_UPDATE, MEDIA_CREATE, MEDIA_DELETE } = webhookUtils.webhookEvents;
|
||||
|
||||
const { ApplicationError } = require('@strapi/utils/lib/errors');
|
||||
const { FILE_MODEL_UID } = require('../constants');
|
||||
const { getService } = require('../utils');
|
||||
const { bytesToKbytes } = require('../utils/file');
|
||||
@ -106,7 +107,7 @@ module.exports = ({ strapi }) => ({
|
||||
return entity;
|
||||
},
|
||||
|
||||
async enhanceFile(file, fileInfo = {}, metas = {}) {
|
||||
async enhanceAndValidateFile(file, fileInfo = {}, metas = {}) {
|
||||
const currentFile = await this.formatFileInfo(
|
||||
{
|
||||
filename: file.name,
|
||||
@ -121,14 +122,29 @@ module.exports = ({ strapi }) => ({
|
||||
);
|
||||
currentFile.getStream = () => fs.createReadStream(file.path);
|
||||
|
||||
const { optimize, isOptimizableImage } = strapi.plugin('upload').service('image-manipulation');
|
||||
const { optimize, isImage, isFaultyImage, isOptimizableImage } = strapi
|
||||
.plugin('upload')
|
||||
.service('image-manipulation');
|
||||
|
||||
if (!(await isOptimizableImage(currentFile))) {
|
||||
return currentFile;
|
||||
if (await isImage(currentFile)) {
|
||||
if (await isFaultyImage(currentFile)) {
|
||||
throw new ApplicationError('File is not a valid image');
|
||||
}
|
||||
if (!(await isOptimizableImage(currentFile))) {
|
||||
return currentFile;
|
||||
}
|
||||
}
|
||||
return optimize(currentFile);
|
||||
},
|
||||
|
||||
// TODO V5: remove enhanceFile
|
||||
async enhanceFile(file, fileInfo = {}, metas = {}) {
|
||||
process.emitWarning(
|
||||
'[deprecated] In future versions, `enhanceFile` will be removed. Replace it with `enhanceAndValidateFile` instead.'
|
||||
);
|
||||
return this.enhanceAndValidateFile(file, fileInfo, metas);
|
||||
},
|
||||
|
||||
async upload({ data, files }, { user } = {}) {
|
||||
// create temporary folder to store files for stream manipulation
|
||||
const tmpWorkingDirectory = await createAndAssignTmpWorkingDirectoryToFiles(files);
|
||||
@ -142,7 +158,7 @@ module.exports = ({ strapi }) => ({
|
||||
const fileInfoArray = Array.isArray(fileInfo) ? fileInfo : [fileInfo];
|
||||
|
||||
const doUpload = async (file, fileInfo) => {
|
||||
const fileData = await this.enhanceFile(file, fileInfo, metas);
|
||||
const fileData = await this.enhanceAndValidateFile(file, fileInfo, metas);
|
||||
return this.uploadFileAndPersist(fileData, { user });
|
||||
};
|
||||
|
||||
@ -266,7 +282,7 @@ module.exports = ({ strapi }) => ({
|
||||
|
||||
try {
|
||||
const { fileInfo } = data;
|
||||
fileData = await this.enhanceFile(file, fileInfo);
|
||||
fileData = await this.enhanceAndValidateFile(file, fileInfo);
|
||||
|
||||
// keep a constant hash and extension so the file url doesn't change when the file is replaced
|
||||
_.assign(fileData, {
|
||||
@ -386,7 +402,7 @@ module.exports = ({ strapi }) => ({
|
||||
try {
|
||||
const enhancedFiles = await Promise.all(
|
||||
arr.map(file => {
|
||||
return this.enhanceFile(
|
||||
return this.enhanceAndValidateFile(
|
||||
file,
|
||||
{ folder: apiUploadFolder.id },
|
||||
{
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
/**
|
||||
* Utils file containing file treatment utils
|
||||
*/
|
||||
const { Writable } = require('stream');
|
||||
|
||||
const bytesToKbytes = bytes => Math.round((bytes / 1000) * 100) / 100;
|
||||
|
||||
@ -26,8 +27,22 @@ const getStreamSize = stream =>
|
||||
stream.resume();
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a writeable Node.js stream that discards received data.
|
||||
* Useful for testing, draining a stream of data, etc.
|
||||
*/
|
||||
function writableStreamDiscard(options) {
|
||||
return new Writable({
|
||||
...options,
|
||||
write(chunk, encding, callback) {
|
||||
setImmediate(callback);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
streamToBuffer,
|
||||
bytesToKbytes,
|
||||
getStreamSize,
|
||||
writableStreamDiscardData: writableStreamDiscard,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user