UNPKG

koa-body-images

Version:

Middleware to extract images from multipart/form-data uses koa-body

131 lines (98 loc) 3.87 kB
const validators = require('./validators'); const types = Object.freeze({ 'gif' : true, 'jpeg' : true, 'pjpeg' : true, 'png' : true, 'svg+xml' : true, 'tiff' : true, 'vnd.microsoft.icon': true, 'vnd.wap.wbmp' : true, 'webp' : true, 'x-icon' : true, 'x-jng' : true, 'x-ms-bmp' : true, }); module.exports = koaBodyImages; function koaBodyImages(opts) { opts = opts || {}; opts.fromKeys = 'fromKeys' in opts ? opts.fromKeys : []; opts.multiples = 'multiples' in opts ? opts.multiples : true; opts.types = 'types' in opts ? opts.types : []; //check opts.fromKeys if ( ! Array.isArray(opts.fromKeys) ) throw new KoaBodyImagesTypeError("Option 'fromKeys' is not an array"); if ( ! checkArrayElementsTypes(opts.fromKeys, "string")) throw new KoaBodyImagesTypeError("Some of elements in 'fromKeys' option is not a string"); //check opts.types if ( ! Array.isArray(opts.types) ) throw new KoaBodyImagesTypeError("Option 'types' is not an array"); if ( ! checkArrayElementsTypes(opts.types, "string")) throw new KoaBodyImagesTypeError("Some of elements in 'types' option is not a string"); if ( ! opts.types.every( t => t.toLowerCase() in types) ) throw new KoaBodyImagesTypeError("Some of elements in 'types' is not a correct type value"); //check opts.multiples if ( typeof opts.multiples !== "boolean") throw new KoaBodyImagesTypeError("Option 'multiples' is not a boolean"); return function (ctx, next) { const isMultiples = Boolean( opts.multiples ); const isFromKeys = Boolean( opts.fromKeys.length ); const { files } = ctx.request; const images = Object.assign({}, files); if ( !files ) return next(); const keys = Object.keys(files); keys.forEach( key => { let value = images[key]; const valueIsMultiples = Array.isArray(value); const valueIsFromKeys = Boolean( !isFromKeys || ~opts.fromKeys.indexOf(key) ); const validationData = { value, valueIsMultiples, valueIsFromKeys, isMultiples, isFromKeys, }; if ( ! validators.every( f => f(validationData)) ) { return delete images[key]; } if( isMultiples && !valueIsMultiples) { value = [value]; } const valueImages = getImages(value, opts.types); if ( !valueImages ) { return delete images[key]; } images[key] = valueImages; }); ctx.request.images = Object.keys(images).length ? images : undefined; return next(); } } function checkType(variable, type) { return typeof variable === type; } function checkArrayElementsTypes(array, type) { return array.every( x => checkType(x, type) ); } function isImage(file, types) { if ( !file || !file.type ) return false; if( types.length ) { return types.some( type => file.type.indexOf("image/" + type) === 0); } return file.type.indexOf("image/") === 0; } function getImages(files, types) { files = files || {}; let images; if (Array.isArray(files)) { images = files.filter( file => isImage(file, types)); return images.length ? images : null; } return isImage(files, types) ? files : null; } class KoaBodyImagesError extends Error { constructor(...args) { super(...args); Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; } } class KoaBodyImagesTypeError extends KoaBodyImagesError { constructor(...args) { super(...args); } }