diff --git a/README.md b/README.md index 31e1270..195ca54 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ The **req.files.foo** object will contain the following: * Before 1.0.0, `md5` is an MD5 checksum of the uploaded file. * From 1.0.0 until 1.1.1, `md5` is a function to compute an MD5 hash ([Read about it here.](https://github.com/richardgirges/express-fileupload/releases/tag/v1.0.0-alpha.1)). -* From 1.1.1 onward, `md5` is reverted back to MD5 checksum value and also added full MD5 support in case you are using temporary files. +* From 1.1.1 until 1.5.1, `md5` is reverted back to MD5 checksum value and also added full MD5 support in case you are using temporary files. +* From 1.5.1 onward, `md5` still holds the checksum value, but the checksum is generated with the provided `hashAlgorithm` option. The property name remains `md5` for backwards compatibility. ### Examples @@ -124,6 +125,7 @@ parseNested | | Turn on/off upload process logging. Can be useful for troubleshooting. logger | | Customizable logger to write debug messages to. Console is default. uploadTimeout | | This defines how long to wait for data before aborting. Set to 0 if you want to turn off timeout checks. +hashAlgorithm | | Allows the usage of alternative hashing algorithms for file integrity checks. This option must be an algorithm that is supported on the running system's installed OpenSSL version. On recent releases of OpenSSL, openssl list -digest-algorithms will display the available digest algorithms. # Help Wanted Looking for additional maintainers. Please contact `richardgirges [ at ] gmail.com` if you're interested. Pull Requests are welcome! diff --git a/lib/index.js b/lib/index.js index 5537c29..0908909 100644 --- a/lib/index.js +++ b/lib/index.js @@ -20,7 +20,8 @@ const DEFAULT_OPTIONS = { createParentPath: false, parseNested: false, useTempFiles: false, - tempFileDir: path.join(process.cwd(), 'tmp') + tempFileDir: path.join(process.cwd(), 'tmp'), + hashAlgorithm: 'md5' }; /** diff --git a/lib/memHandler.js b/lib/memHandler.js index 09accfe..a138484 100644 --- a/lib/memHandler.js +++ b/lib/memHandler.js @@ -10,7 +10,7 @@ const { debugLog } = require('./utilities'); */ module.exports = (options, fieldname, filename) => { const buffers = []; - const hash = crypto.createHash('md5'); + const hash = crypto.createHash(options.hashAlgorithm); let fileSize = 0; let completed = false; diff --git a/lib/tempFileHandler.js b/lib/tempFileHandler.js index d24416a..6751935 100644 --- a/lib/tempFileHandler.js +++ b/lib/tempFileHandler.js @@ -14,8 +14,8 @@ module.exports = (options, fieldname, filename) => { checkAndMakeDir({ createParentPath: true }, tempFilePath); debugLog(options, `Temporary file path is ${tempFilePath}`); - - const hash = crypto.createHash('md5'); + + const hash = crypto.createHash(options.hashAlgorithm); let fileSize = 0; let completed = false; diff --git a/lib/utilities.js b/lib/utilities.js index 7ecf94d..1545399 100644 --- a/lib/utilities.js +++ b/lib/utilities.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path'); +const crypto = require('crypto'); const { Readable } = require('stream'); // Parameters for safe file name parsing. @@ -68,6 +69,7 @@ const promiseCallback = (resolve, reject) => { /** * Builds instance options from arguments objects(can't be arrow function). * @returns {Object} - result options. + * @throws {Error} - when a valid hashAlgorithm option is not provided. */ const buildOptions = function() { const result = {}; @@ -75,6 +77,15 @@ const buildOptions = function() { if (!options || typeof options !== 'object') return; Object.keys(options).forEach(i => result[i] = options[i]); }); + + // Ensure the configured hashAlgorithm is available on the system + if (crypto.getHashes().find(h => result.hashAlgorithm === h) === undefined) { + throw Error( + `Hashing algorithm '${result.hashAlgorithm}' is not supported by this system's OpenSSL ` + + `version` + ); + } + return result; }; diff --git a/package.json b/package.json index a5f2785..6360fbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "express-fileupload", - "version": "1.5.0", + "version": "1.5.1", "author": "Richard Girges ", "description": "Simple express file upload middleware that wraps around Busboy", "main": "./lib/index", diff --git a/test/utilities.spec.js b/test/utilities.spec.js index a9cc1b1..1386df5 100644 --- a/test/utilities.spec.js +++ b/test/utilities.spec.js @@ -198,12 +198,12 @@ describe('utilities: Test of the utilities functions', function() { //buildOptions tests describe('Test buildOptions function', () => { - const source = { option1: '1', option2: '2' }; - const sourceAddon = { option3: '3'}; - const expected = { option1: '1', option2: '2' }; - const expectedAddon = { option1: '1', option2: '2', option3: '3'}; + const source = { option1: '1', option2: '2', hashAlgorithm: 'md5' }; + const sourceAddon = { option3: '3', hashAlgorithm: 'sha256'}; + const expected = { option1: '1', option2: '2', hashAlgorithm: 'md5' }; + const expectedAddon = { option1: '1', option2: '2', option3: '3', hashAlgorithm: 'sha256'}; - it('buildOptions returns and equal object to the object which was paased', () => { + it('buildOptions returns an equal object to the object which was passed', () => { let result = buildOptions(source); assert.deepStrictEqual(result, source); }); @@ -213,11 +213,18 @@ describe('utilities: Test of the utilities functions', function() { assert.deepStrictEqual(result, expected); }); - it('buildOptions adds value to the result from the several source argumets', () => { + it('buildOptions adds value to the result from the several source arguments', () => { let result = buildOptions(source, sourceAddon); assert.deepStrictEqual(result, expectedAddon); }); + it('buildOptions throws an error when not provided a supported hashAlgorithm', () => { + assert.throws(() => buildOptions({})); + }); + + it('buildOptions throws an error when given an unsupported hashAlgorithm', () => { + assert.throws(() => buildOptions({ hashAlgorithm: 'not-actual-algo' })); + }); }); //buildFields tests describe('Test buildFields function', () => {