{"version":3,"sources":["../../../src/uploads/fetchAPI-multipart/utilities.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { Readable } from 'stream'\n\nimport type { FetchAPIFileUploadOptions } from '../../config/types.js'\n\n// Parameters for safe file name parsing.\nconst SAFE_FILE_NAME_REGEX = /[^\\w-]/g\nconst MAX_EXTENSION_LENGTH = 3\n\n// Parameters to generate unique temporary file names:\nconst TEMP_COUNTER_MAX = 65536\nconst TEMP_PREFIX = 'tmp'\nlet tempCounter = 0\n\n/**\n * Logs message to console if options.debug option set to true.\n */\nexport const debugLog = (options: FetchAPIFileUploadOptions, msg: string) => {\n const opts = options || {}\n if (!opts.debug) {\n return false\n }\n console.log(`Next-file-upload: ${msg}`) // eslint-disable-line\n return true\n}\n\n/**\n * Generates unique temporary file name. e.g. tmp-5000-156788789789.\n */\nexport const getTempFilename = (prefix: string = TEMP_PREFIX) => {\n tempCounter = tempCounter >= TEMP_COUNTER_MAX ? 1 : tempCounter + 1\n return `${prefix}-${tempCounter}-${Date.now()}`\n}\n\ntype FuncType = (...args: any[]) => any\nexport const isFunc = (value: any): value is FuncType => {\n return typeof value === 'function'\n}\n\n/**\n * Set errorFunc to the same value as successFunc for callback mode.\n */\ntype ErrorFunc = (resolve: () => void, reject: (err: Error) => void) => (err: Error) => void\nconst errorFunc: ErrorFunc = (resolve, reject) => (isFunc(reject) ? reject : resolve)\n\n/**\n * Return a callback function for promise resole/reject args.\n * Ensures that callback is called only once.\n */\ntype PromiseCallback = (resolve: () => void, reject: (err: Error) => void) => (err: Error) => void\nexport const promiseCallback: PromiseCallback = (resolve, reject) => {\n let hasFired = false\n return (err: Error) => {\n if (hasFired) {\n return\n }\n\n hasFired = true\n return err ? errorFunc(resolve, reject)(err) : resolve()\n }\n}\n\n// The default prototypes for both objects and arrays.\n// Used by isSafeFromPollution\nconst OBJECT_PROTOTYPE_KEYS = Object.getOwnPropertyNames(Object.prototype)\nconst ARRAY_PROTOTYPE_KEYS = Object.getOwnPropertyNames(Array.prototype)\n\n/**\n * Determines whether a key insertion into an object could result in a prototype pollution\n */\ntype IsSafeFromPollution = (base: any, key: string) => boolean\nexport const isSafeFromPollution: IsSafeFromPollution = (base, key) => {\n // We perform an instanceof check instead of Array.isArray as the former is more\n // permissive for cases in which the object as an Array prototype but was not constructed\n // via an Array constructor or literal.\n const TOUCHES_ARRAY_PROTOTYPE = base instanceof Array && ARRAY_PROTOTYPE_KEYS.includes(key)\n const TOUCHES_OBJECT_PROTOTYPE = OBJECT_PROTOTYPE_KEYS.includes(key)\n\n return !TOUCHES_ARRAY_PROTOTYPE && !TOUCHES_OBJECT_PROTOTYPE\n}\n\n/**\n * Build request field/file objects to return\n */\ntype BuildFields = (instance: any, field: string, value: any) => any\nexport const buildFields: BuildFields = (instance, field, value) => {\n // Do nothing if value is not set.\n if (value === null || value === undefined) {\n return instance\n }\n instance = instance || Object.create(null)\n\n if (!isSafeFromPollution(instance, field)) {\n return instance\n }\n // Non-array fields\n if (!instance[field]) {\n instance[field] = value\n return instance\n }\n // Array fields\n if (instance[field] instanceof Array) {\n instance[field].push(value)\n } else {\n instance[field] = [instance[field], value]\n }\n return instance\n}\n\n/**\n * Creates a folder if it does not exist\n * for file specified in the path variable\n */\ntype CheckAndMakeDir = (fileUploadOptions: FetchAPIFileUploadOptions, filePath: string) => boolean\nexport const checkAndMakeDir: CheckAndMakeDir = (fileUploadOptions, filePath) => {\n if (!fileUploadOptions.createParentPath) {\n return false\n }\n // Check whether folder for the file exists.\n const parentPath = path.dirname(path.resolve(filePath))\n // Create folder if it doesn't exist.\n if (!fs.existsSync(parentPath)) {\n fs.mkdirSync(parentPath, { recursive: true })\n }\n // Checks folder again and return a results.\n return fs.existsSync(parentPath)\n}\n\n/**\n * Delete a file.\n */\ntype DeleteFile = (filePath: string, callback: (args: any) => void) => void\nexport const deleteFile: DeleteFile = (filePath, callback) => fs.unlink(filePath, callback)\n\n/**\n * Copy file via streams\n */\ntype CopyFile = (src: string, dst: string, callback: (err: Error) => void) => void\nconst copyFile: CopyFile = (src, dst, callback) => {\n // cbCalled flag and runCb helps to run cb only once.\n let cbCalled = false\n const runCb = (err?: Error) => {\n if (cbCalled) {\n return\n }\n cbCalled = true\n callback(err!)\n }\n // Create read stream\n const readable = fs.createReadStream(src)\n readable.on('error', runCb)\n // Create write stream\n const writable = fs.createWriteStream(dst)\n writable.on('error', (err: Error) => {\n readable.destroy()\n runCb(err)\n })\n writable.on('close', () => runCb())\n // Copy file via piping streams.\n readable.pipe(writable)\n}\n\n/**\n * moveFile: moves the file from src to dst.\n * Firstly trying to rename the file if no luck copying it to dst and then deleting src.\n */\ntype MoveFile = (\n src: string,\n dst: string,\n callback: (err: Error, renamed?: boolean) => void,\n) => void\nexport const moveFile: MoveFile = (src, dst, callback) =>\n fs.rename(src, dst, (err) => {\n if (err) {\n // Try to copy file if rename didn't work.\n copyFile(src, dst, (cpErr) => (cpErr ? callback(cpErr) : deleteFile(src, callback)))\n return\n }\n // File was renamed successfully: Add true to the callback to indicate that.\n callback(null!, true)\n })\n\n/**\n * Save buffer data to a file.\n * @param {Buffer} buffer - buffer to save to a file.\n * @param {string} filePath - path to a file.\n */\nexport const saveBufferToFile = (\n buffer: Buffer,\n filePath: string,\n callback: (err?: Error) => void,\n) => {\n if (!Buffer.isBuffer(buffer)) {\n return callback(new Error('buffer variable should be type of Buffer!'))\n }\n // Setup readable stream from buffer.\n let streamData = buffer\n const readStream = new Readable()\n readStream._read = () => {\n readStream.push(streamData)\n streamData = null!\n }\n // Setup file system writable stream.\n const fstream = fs.createWriteStream(filePath)\n // console.log(\"Calling saveBuffer\");\n fstream.on('error', (err) => {\n // console.log(\"err cb\")\n callback(err)\n })\n fstream.on('close', () => {\n // console.log(\"close cb\");\n callback()\n })\n // Copy file via piping streams.\n readStream.pipe(fstream)\n}\n\n/**\n * Decodes uriEncoded file names.\n * @param {Object} opts - middleware options.\n * @param fileName {String} - file name to decode.\n * @returns {String}\n */\nconst uriDecodeFileName = (opts: FetchAPIFileUploadOptions, fileName: string) => {\n if (!opts || !opts.uriDecodeFileNames) {\n return fileName\n }\n // Decode file name from URI with checking URI malformed errors.\n // See Issue https://github.com/richardgirges/express-fileupload/issues/342.\n try {\n return decodeURIComponent(fileName)\n } catch (ignore) {\n const matcher = /(%[a-f\\d]{2})/gi\n return fileName\n .split(matcher)\n .map((str) => {\n try {\n return decodeURIComponent(str)\n } catch (ignore) {\n return ''\n }\n })\n .join('')\n }\n}\n\n/**\n * Parses filename and extension and returns object {name, extension}.\n */\ntype ParseFileNameExtension = (\n preserveExtension: boolean | number,\n fileName: string,\n) => {\n extension: string\n name: string\n}\nexport const parseFileNameExtension: ParseFileNameExtension = (preserveExtension, fileName) => {\n const defaultResult = {\n name: fileName,\n extension: '',\n }\n if (!preserveExtension) {\n return defaultResult\n }\n\n // Define maximum extension length\n const maxExtLength =\n typeof preserveExtension === 'boolean' ? MAX_EXTENSION_LENGTH : preserveExtension\n\n const nameParts = fileName.split('.')\n if (nameParts.length < 2) {\n return defaultResult\n }\n\n let extension = nameParts.pop()\n if (extension!.length > maxExtLength && maxExtLength > 0) {\n nameParts[nameParts.length - 1] += '.' + extension!.substr(0, extension!.length - maxExtLength)\n extension = extension!.substr(-maxExtLength)\n }\n\n return {\n name: nameParts.join('.'),\n extension: maxExtLength ? extension! : '',\n }\n}\n\n/**\n * Parse file name and extension.\n */\ntype ParseFileName = (opts: FetchAPIFileUploadOptions, fileName: string) => string\nexport const parseFileName: ParseFileName = (opts, fileName) => {\n // Check fileName argument\n if (!fileName || typeof fileName !== 'string') {\n return getTempFilename()\n }\n // Cut off file name if it's length more then 255.\n let parsedName = fileName.length <= 255 ? fileName : fileName.substr(0, 255)\n // Decode file name if uriDecodeFileNames option set true.\n parsedName = uriDecodeFileName(opts, parsedName)\n // Stop parsing file name if safeFileNames options hasn't been set.\n if (!opts.safeFileNames) {\n return parsedName\n }\n // Set regular expression for the file name.\n const nameRegex =\n typeof opts.safeFileNames === 'object' && opts.safeFileNames instanceof RegExp\n ? opts.safeFileNames\n : SAFE_FILE_NAME_REGEX\n // Parse file name extension.\n const parsedFileName = parseFileNameExtension(opts.preserveExtension!, parsedName)\n if (parsedFileName.extension.length) {\n parsedFileName.extension = '.' + parsedFileName.extension.replace(nameRegex, '')\n }\n\n return parsedFileName.name.replace(nameRegex, '').concat(parsedFileName.extension)\n}\n"],"names":["fs","path","Readable","SAFE_FILE_NAME_REGEX","MAX_EXTENSION_LENGTH","TEMP_COUNTER_MAX","TEMP_PREFIX","tempCounter","debugLog","options","msg","opts","debug","console","log","getTempFilename","prefix","Date","now","isFunc","value","errorFunc","resolve","reject","promiseCallback","hasFired","err","OBJECT_PROTOTYPE_KEYS","Object","getOwnPropertyNames","prototype","ARRAY_PROTOTYPE_KEYS","Array","isSafeFromPollution","base","key","TOUCHES_ARRAY_PROTOTYPE","includes","TOUCHES_OBJECT_PROTOTYPE","buildFields","instance","field","undefined","create","push","checkAndMakeDir","fileUploadOptions","filePath","createParentPath","parentPath","dirname","existsSync","mkdirSync","recursive","deleteFile","callback","unlink","copyFile","src","dst","cbCalled","runCb","readable","createReadStream","on","writable","createWriteStream","destroy","pipe","moveFile","rename","cpErr","saveBufferToFile","buffer","Buffer","isBuffer","Error","streamData","readStream","_read","fstream","uriDecodeFileName","fileName","uriDecodeFileNames","decodeURIComponent","ignore","matcher","split","map","str","join","parseFileNameExtension","preserveExtension","defaultResult","name","extension","maxExtLength","nameParts","length","pop","substr","parseFileName","parsedName","safeFileNames","nameRegex","RegExp","parsedFileName","replace","concat"],"mappings":"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"}