mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-04 11:54:10 +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');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 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