From a230423d7f6206a85ab897dedab94d4fa58ba73a Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Tue, 25 Jun 2024 14:04:23 -0500 Subject: [PATCH] Issue 374: Allow an option to choose the hashing algorithm - hashAlgorithm key added to DEFAULT_OPTIONS - hashAlgorithm key can be overriden by value given in options argument - buildOptions function will ensure a default a hashAlgorithm exists, and throw an error if the provided option is not supported by the system. - throws early error during app setup, rather than waiting until an upload is attempted - memHandler and tempFileHandler use the hashAlgorithm option now - Updated tests for buildOptions function in utilities.spec.js ref: https://github.com/richardgirges/express-fileupload/issues/374 --- lib/index.js | 3 ++- lib/memHandler.js | 2 +- lib/tempFileHandler.js | 4 ++-- lib/utilities.js | 15 +++++++++++++++ test/utilities.spec.js | 23 +++++++++++++++-------- 5 files changed, 35 insertions(+), 12 deletions(-) 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..2cbf583 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. @@ -75,6 +76,20 @@ const buildOptions = function() { if (!options || typeof options !== 'object') return; Object.keys(options).forEach(i => result[i] = options[i]); }); + + // Ensure a hashAlgorithm option exists. + if (!result.hashAlgorithm) { + result.hashAlgorithm = 'md5'; + } + + // 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/test/utilities.spec.js b/test/utilities.spec.js index a9cc1b1..90380e0 100644 --- a/test/utilities.spec.js +++ b/test/utilities.spec.js @@ -199,25 +199,32 @@ describe('utilities: Test of the utilities functions', function() { 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 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', () => { - let result = buildOptions(source); - assert.deepStrictEqual(result, source); - }); + it( + 'buildOptions returns an equal object to the object which was passed + hashAlgorithm ' + + 'property', + () => { + let result = buildOptions(source); + assert.deepStrictEqual(result, expected); + } + ); it('buildOptions doesnt add non object or null arguments to the result', () => { let result = buildOptions(source, 2, '3', null); 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 given an unsupported hashAlgorithm', () => { + assert.throws(() => buildOptions({ hashAlgorithm: 'not-actual-algo' })); + }); }); //buildFields tests describe('Test buildFields function', () => {