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..31ea4a0 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 @@ -51,7 +57,7 @@ function Tokens (options) { var saltLength = opts.saltLength !== undefined ? opts.saltLength - : 8 + : DefaultOptions.saltLength if (typeof saltLength !== 'number' || !isFinite(saltLength) || saltLength < 1) { throw new TypeError('option saltLength must be finite number > 1') @@ -59,14 +65,23 @@ function Tokens (options) { var secretLength = opts.secretLength !== undefined ? opts.secretLength - : 18 + : DefaultOptions.secretLength if (typeof secretLength !== 'number' || !isFinite(secretLength) || secretLength < 1) { throw new TypeError('option secretLength must be finite number > 1') } + var hashAlgorithm = opts.hashAlgorithm !== undefined + ? opts.hashAlgorithm + : DefaultOptions.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 +125,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 +163,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 () {