123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- 'use strict';
- const fs = require('fs');
- const path = require('path');
- const { Readable } = require('stream');
- const SAFE_FILE_NAME_REGEX = /[^\w-]/g;
- const MAX_EXTENSION_LENGTH = 3;
- const TEMP_COUNTER_MAX = 65536;
- const TEMP_PREFIX = 'tmp';
- let tempCounter = 0;
- const debugLog = (options, msg) => {
- const opts = options || {};
- if (!opts.debug) return false;
- console.log(`Express-file-upload: ${msg}`);
- return true;
- };
- const getTempFilename = (prefix = TEMP_PREFIX) => {
- tempCounter = tempCounter >= TEMP_COUNTER_MAX ? 1 : tempCounter + 1;
- return `${prefix}-${tempCounter}-${Date.now()}`;
- };
- const isFunc = func => func && func.constructor && func.call && func.apply ? true: false;
- const errorFunc = (resolve, reject) => isFunc(reject) ? reject : resolve;
- const promiseCallback = (resolve, reject) => {
- let hasFired = false;
- return (err) => {
- if (hasFired) {
- return;
- }
- hasFired = true;
- return err ? errorFunc(resolve, reject)(err) : resolve();
- };
- };
- const buildOptions = function() {
- const result = {};
- [...arguments].forEach(options => {
- if (!options || typeof options !== 'object') return;
- Object.keys(options).forEach(i => result[i] = options[i]);
- });
- return result;
- };
- const OBJECT_PROTOTYPE_KEYS = Object.getOwnPropertyNames(Object.prototype);
- const ARRAY_PROTOTYPE_KEYS = Object.getOwnPropertyNames(Array.prototype);
- const isSafeFromPollution = (base, key) => {
-
-
-
- const TOUCHES_ARRAY_PROTOTYPE = (base instanceof Array) && ARRAY_PROTOTYPE_KEYS.includes(key);
- const TOUCHES_OBJECT_PROTOTYPE = OBJECT_PROTOTYPE_KEYS.includes(key);
- return !TOUCHES_ARRAY_PROTOTYPE && !TOUCHES_OBJECT_PROTOTYPE;
- };
- const buildFields = (instance, field, value) => {
-
- if (value === null || value === undefined) return instance;
- instance = instance || Object.create(null);
- if (!isSafeFromPollution(instance, field)) {
- return instance;
- }
-
- if (!instance[field]) {
- instance[field] = value;
- return instance;
- }
-
- if (instance[field] instanceof Array) {
- instance[field].push(value);
- } else {
- instance[field] = [instance[field], value];
- }
- return instance;
- };
- const checkAndMakeDir = (fileUploadOptions, filePath) => {
-
- if (!fileUploadOptions) return false;
- if (!fileUploadOptions.createParentPath) return false;
-
- if (!filePath) return false;
- const parentPath = path.dirname(filePath);
-
- if (!fs.existsSync(parentPath)) fs.mkdirSync(parentPath, { recursive: true });
-
- return fs.existsSync(parentPath);
- };
- const deleteFile = (file, callback) => fs.unlink(file, callback);
- const copyFile = (src, dst, callback) => {
-
- let cbCalled = false;
- let runCb = (err) => {
- if (cbCalled) return;
- cbCalled = true;
- callback(err);
- };
-
- let readable = fs.createReadStream(src);
- readable.on('error', runCb);
-
- let writable = fs.createWriteStream(dst);
- writable.on('error', (err)=>{
- readable.destroy();
- runCb(err);
- });
- writable.on('close', () => runCb());
-
- readable.pipe(writable);
- };
- const moveFile = (src, dst, callback) => fs.rename(src, dst, err => (err
- ? copyFile(src, dst, err => err ? callback(err) : deleteFile(src, callback))
- : callback()
- ));
- const saveBufferToFile = (buffer, filePath, callback) => {
- if (!Buffer.isBuffer(buffer)) {
- return callback(new Error('buffer variable should be type of Buffer!'));
- }
-
- let streamData = buffer;
- let readStream = Readable();
- readStream._read = () => {
- readStream.push(streamData);
- streamData = null;
- };
-
- let fstream = fs.createWriteStream(filePath);
-
- fstream.on('error', err => {
-
- callback(err);
- });
- fstream.on('close', () => {
-
- callback();
- });
-
- readStream.pipe(fstream);
- };
- const uriDecodeFileName = (opts, fileName) => {
- return opts.uriDecodeFileNames ? decodeURIComponent(fileName) : fileName;
- };
- const parseFileNameExtension = (preserveExtension, fileName) => {
- const preserveExtensionLength = parseInt(preserveExtension);
- const result = {name: fileName, extension: ''};
- if (!preserveExtension && preserveExtensionLength !== 0) return result;
-
- const maxExtLength = isNaN(preserveExtensionLength)
- ? MAX_EXTENSION_LENGTH
- : Math.abs(preserveExtensionLength);
- const nameParts = fileName.split('.');
- if (nameParts.length < 2) return result;
- let extension = nameParts.pop();
- if (
- extension.length > maxExtLength &&
- maxExtLength > 0
- ) {
- nameParts[nameParts.length - 1] +=
- '.' +
- extension.substr(0, extension.length - maxExtLength);
- extension = extension.substr(-maxExtLength);
- }
- result.extension = maxExtLength ? extension : '';
- result.name = nameParts.join('.');
- return result;
- };
- const parseFileName = (opts, fileName) => {
-
- if (!fileName || typeof fileName !== 'string') return getTempFilename();
-
- let parsedName = fileName.length <= 255 ? fileName : fileName.substr(0, 255);
-
- parsedName = uriDecodeFileName(opts, parsedName);
-
- if (!opts.safeFileNames) return parsedName;
-
- const nameRegex = typeof opts.safeFileNames === 'object' && opts.safeFileNames instanceof RegExp
- ? opts.safeFileNames
- : SAFE_FILE_NAME_REGEX;
-
- let {name, extension} = parseFileNameExtension(opts.preserveExtension, parsedName);
- if (extension.length) extension = '.' + extension.replace(nameRegex, '');
- return name.replace(nameRegex, '').concat(extension);
- };
- module.exports = {
- isFunc,
- debugLog,
- copyFile,
- moveFile,
- errorFunc,
- deleteFile,
- buildFields,
- buildOptions,
- parseFileName,
- getTempFilename,
- promiseCallback,
- checkAndMakeDir,
- saveBufferToFile,
- uriDecodeFileName,
- isSafeFromPollution
- };
|