From 8ebcdb4c649eb9a4b013f58fe45002af054ee43b Mon Sep 17 00:00:00 2001 From: BuzCarter Date: Tue, 10 Sep 2019 18:40:04 -0700 Subject: [PATCH 1/2] add hashAlgorithm to options; move hash to object instance property --- README.md | 4 ++++ index.js | 29 +++++++++++++++++++---------- test/test.js | 12 ++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d8d9f8b..8cf198d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,10 @@ The length of the secret to generate, in bytes. Note that the secret is passed around base-64 encoded and that this length refers to the underlying bytes, not the length of the base-64 string. Defaults to `18` bytes. +##### hashAlgorithm + +The algorithm to be used in generating hash digests. "*The algorithm is dependent on the available algorithms supported by the version of OpenSSL on the platform*" ([see Node crypto.createHash documentation](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options)) + #### tokens.create(secret) Create a new CSRF token attached to the given `secret`. The `secret` is a diff --git a/index.js b/index.js index 78babe1..cc5bdfc 100644 --- a/index.js +++ b/index.js @@ -26,6 +26,12 @@ var EQUAL_GLOBAL_REGEXP = /=/g var PLUS_GLOBAL_REGEXP = /\+/g var SLASH_GLOBAL_REGEXP = /\//g +var DefaultOptions = { + saltLength: 8, + secretLength: 18, + hashAlgorithm: 'sha1' +} + /** * Module exports. * @public @@ -47,26 +53,29 @@ function Tokens (options) { return new Tokens(options) } - var opts = options || {} + var opts = Object.assign({}, DefaultOptions, options || {}) - var saltLength = opts.saltLength !== undefined - ? opts.saltLength - : 8 + var saltLength = opts.saltLength if (typeof saltLength !== 'number' || !isFinite(saltLength) || saltLength < 1) { throw new TypeError('option saltLength must be finite number > 1') } - var secretLength = opts.secretLength !== undefined - ? opts.secretLength - : 18 + var secretLength = opts.secretLength if (typeof secretLength !== 'number' || !isFinite(secretLength) || secretLength < 1) { throw new TypeError('option secretLength must be finite number > 1') } + var hashAlgorithm = opts.hashAlgorithm + + if (typeof hashAlgorithm !== 'string' || !hashAlgorithm) { + throw new TypeError('option hashAlgorithm must be valid hash algorithn') + } + this.saltLength = saltLength this.secretLength = secretLength + this.hashAlgorithm = hashAlgorithm } /** @@ -110,7 +119,7 @@ Tokens.prototype.secretSync = function secretSync () { */ Tokens.prototype._tokenize = function tokenize (secret, salt) { - return salt + '-' + hash(salt + '-' + secret) + return salt + '-' + this.hash(salt + '-' + secret) } /** @@ -148,9 +157,9 @@ Tokens.prototype.verify = function verify (secret, token) { * @private */ -function hash (str) { +Tokens.prototype.hash = function hash (str) { return crypto - .createHash('sha1') + .createHash(this.hashAlgorithm) .update(str, 'ascii') .digest('base64') .replace(PLUS_GLOBAL_REGEXP, '-') diff --git a/test/test.js b/test/test.js index a9161f4..113f988 100644 --- a/test/test.js +++ b/test/test.js @@ -50,6 +50,18 @@ describe('Tokens', function () { assert.strictEqual(Tokens({ secretLength: 4 }).secretSync().length, 6) }) }) + + describe('hashAlgorithm', function () { + it('should reject non-strings', function () { + assert.throws(Tokens.bind(null, { hashAlgorithm: 256 }), + /option hashAlgorithm/) + }) + + it('should reject empty strings', function () { + assert.throws(Tokens.bind(null, { hashAlgorithm: '' }), + /option hashAlgorithm/) + }) + }) }) describe('.create(secret)', function () { From cf459a7ed5aecd832023161dd454bfcc357241ac Mon Sep 17 00:00:00 2001 From: BuzCarter Date: Wed, 11 Sep 2019 10:59:05 -0700 Subject: [PATCH 2/2] fix for older Node version --- index.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index cc5bdfc..31ea4a0 100644 --- a/index.js +++ b/index.js @@ -53,21 +53,27 @@ function Tokens (options) { return new Tokens(options) } - var opts = Object.assign({}, DefaultOptions, options || {}) + var opts = options || {} - var saltLength = opts.saltLength + var saltLength = opts.saltLength !== undefined + ? opts.saltLength + : DefaultOptions.saltLength if (typeof saltLength !== 'number' || !isFinite(saltLength) || saltLength < 1) { throw new TypeError('option saltLength must be finite number > 1') } - var secretLength = opts.secretLength + var secretLength = opts.secretLength !== undefined + ? opts.secretLength + : DefaultOptions.secretLength if (typeof secretLength !== 'number' || !isFinite(secretLength) || secretLength < 1) { throw new TypeError('option secretLength must be finite number > 1') } - var hashAlgorithm = opts.hashAlgorithm + var hashAlgorithm = opts.hashAlgorithm !== undefined + ? opts.hashAlgorithm + : DefaultOptions.hashAlgorithm if (typeof hashAlgorithm !== 'string' || !hashAlgorithm) { throw new TypeError('option hashAlgorithm must be valid hash algorithn')