From ccab3e40e98a7cec1bf4cf961f463054c19e8223 Mon Sep 17 00:00:00 2001 From: joeyrobert Date: Tue, 3 Oct 2017 08:21:23 -0700 Subject: [PATCH] Specify number of bcryptRounds on model (fixes #3) --- lib/secure-password.js | 21 ++++++++++++++++++--- test/secure-password.spec.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/secure-password.js b/lib/secure-password.js index 01b9ec4..72b58e7 100644 --- a/lib/secure-password.js +++ b/lib/secure-password.js @@ -34,13 +34,28 @@ function enableSecurePasswordPlugin (Bookshelf) { return DEFAULT_PASSWORD_DIGEST_FIELD } + /** + * Get the number of bcrypt salt rounds from the model. defaults to `DEFAULT_SALT_ROUNDS` + * + * @param {Model} model - the Bookshelf model + * @returns {Number} - The number of bcrypt salt rounds + */ + function bcryptRounds (model) { + if (typeof model.bcryptRounds === 'number' && model.bcryptRounds === parseInt(model.bcryptRounds, 10)) { + return model.bcryptRounds + } + + return DEFAULT_SALT_ROUNDS + } + /** * Generate the BCrypt hash for a given string. * + * @param {Number} rounds - The number of bcrypt salt rounds * @param {String} value - The string to hash * @returns {Promise.} - A BCrypt hashed version of the string */ - function hash (value) { + function hash (rounds, value) { if (value === null) { return Promise.resolve(null) } @@ -50,7 +65,7 @@ function enableSecurePasswordPlugin (Bookshelf) { } return bcrypt - .genSalt(DEFAULT_SALT_ROUNDS) + .genSalt(rounds) .then((salt) => { return bcrypt.hash(value, salt) }) @@ -90,7 +105,7 @@ function enableSecurePasswordPlugin (Bookshelf) { model.on('saving', (model) => { let value = model[PRIVATE_PASSWORD_FIELD] - return hash(value).then((_hashed) => { + return hash(bcryptRounds(model), value).then((_hashed) => { model.unset(DEFAULT_PASSWORD_FIELD) if (_hashed !== undefined) { model.set(field, _hashed) diff --git a/test/secure-password.spec.js b/test/secure-password.spec.js index 1ef91b1..3709097 100644 --- a/test/secure-password.spec.js +++ b/test/secure-password.spec.js @@ -13,6 +13,7 @@ describe('bookshelf-secure-password', function () { let model let BasicModel let CustomModel + let RoundsModel before(function () { knex = new Knex({ client: 'pg' }) @@ -28,6 +29,11 @@ describe('bookshelf-secure-password', function () { CustomModel = bookshelf.Model.extend({ hasSecurePassword: 'custom_column' }) + + RoundsModel = bookshelf.Model.extend({ + hasSecurePassword: true, + bcryptRounds: 5 + }) }) after(function () { @@ -131,6 +137,30 @@ describe('bookshelf-secure-password', function () { expect(model.attributes.custom_column).to.be.a.string }) }) + + describe('with a bcrypt rounds', function () { + describe('custom number of rounds', function () { + before(function () { + model = new RoundsModel({ id: 3, password: 'testing' }) + return model.save() + }) + + it('uses custom bcrypt rounds', function () { + expect(model.get('password_digest').substr(4, 2)).to.equal('05') + }) + }) + + describe('default number of rounds', function () { + before(function () { + model = new BasicModel({ id: 4, password: 'testing' }) + return model.save() + }) + + it('uses default bcrypt rounds', function () { + expect(model.get('password_digest').substr(4, 2)).to.equal('12') + }) + }) + }) }) describe('#authenticate', function () {