From a99ec71cf6b68ae345f24788d11e0f007c8f6afa Mon Sep 17 00:00:00 2001 From: Sujal Date: Mon, 23 Aug 2021 19:31:43 +0530 Subject: [PATCH 1/3] Check --- bcrypt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bcrypt.js b/bcrypt.js index 612f9dc..c4a9d0c 100644 --- a/bcrypt.js +++ b/bcrypt.js @@ -15,7 +15,7 @@ var promises = require('./promises'); module.exports.genSaltSync = function genSaltSync(rounds, minor) { // default 10 rounds if (!rounds) { - rounds = 10; + rounds = 18; } else if (typeof rounds !== 'number') { throw new Error('rounds must be a number'); } From ed357f948a35878adc51e86b5acfcc12aad06cc4 Mon Sep 17 00:00:00 2001 From: Sujal Date: Tue, 24 Aug 2021 00:57:07 +0530 Subject: [PATCH 2/3] [FEATURE] Hash by max time allotted #787 --- README.md | 9 ++ bcrypt.js | 369 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 249 insertions(+), 129 deletions(-) diff --git a/README.md b/README.md index dfa800f..929bbc1 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,15 @@ bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) { Note that both techniques achieve the same end-result. +Technique 3 (same as technique 2 but defining work in terms of time (not rounds)): + +exptime = maximum time allotted for hashing [#787](https://github.com/kelektiv/node.bcrypt.js/issues/787) +```javascript +bcrypt.hashByTime(myPlaintextPassword, expTime, function(err, hash) { + // Store hash in your password DB. +}); +``` + #### To check a password: ```javascript diff --git a/bcrypt.js b/bcrypt.js index c4a9d0c..c3df6ea 100644 --- a/bcrypt.js +++ b/bcrypt.js @@ -1,37 +1,35 @@ 'use strict'; - var nodePreGyp = require('@mapbox/node-pre-gyp'); var path = require('path'); var binding_path = nodePreGyp.find(path.resolve(path.join(__dirname, './package.json'))); var bindings = require(binding_path); - var crypto = require('crypto'); - var promises = require('./promises'); /// generate a salt (sync) /// @param {Number} [rounds] number of rounds (default 10) /// @return {String} salt module.exports.genSaltSync = function genSaltSync(rounds, minor) { - // default 10 rounds - if (!rounds) { - rounds = 18; - } else if (typeof rounds !== 'number') { - throw new Error('rounds must be a number'); - } - - if(!minor) { - minor = 'b'; - } else if(minor !== 'b' && minor !== 'a') { - throw new Error('minor must be either "a" or "b"'); - } - - return bindings.gen_salt_sync(minor, rounds, crypto.randomBytes(16)); + // default 10 rounds + if (!rounds) { + rounds = 18; + } else if (typeof rounds !== 'number') { + throw new Error('rounds must be a number'); + } + + if (!minor) { + minor = 'b'; + } else if (minor !== 'b' && minor !== 'a') { + throw new Error('minor must be either "a" or "b"'); + } + + return bindings.gen_salt_sync(minor, rounds, crypto.randomBytes(16)); }; /// generate a salt /// @param {Number} [rounds] number of rounds (default 10) /// @param {Function} cb callback(err, salt) + module.exports.genSalt = function genSalt(rounds, minor, cb) { var error; @@ -63,23 +61,23 @@ module.exports.genSalt = function genSalt(rounds, minor, cb) { }); } - if(!minor) { - minor = 'b' - } else if(minor !== 'b' && minor !== 'a') { - error = new Error('minor must be either "a" or "b"'); - return process.nextTick(function() { - cb(error); - }); + if (!minor) { + minor = 'b' + } else if (minor !== 'b' && minor !== 'a') { + error = new Error('minor must be either "a" or "b"'); + return process.nextTick(function() { + cb(error); + }); } crypto.randomBytes(16, function(error, randomBytes) { - if (error) { - cb(error); - return; - } + if (error) { + cb(error); + return; + } - bindings.gen_salt(minor, rounds, randomBytes, cb); - }); + bindings.gen_salt(minor, rounds, randomBytes, cb); + }); }; /// hash data using a salt @@ -87,19 +85,19 @@ module.exports.genSalt = function genSalt(rounds, minor, cb) { /// @param {String} salt the salt to use when hashing /// @return {String} hash module.exports.hashSync = function hashSync(data, salt) { - if (data == null || salt == null) { - throw new Error('data and salt arguments required'); - } + if (data == null || salt == null) { + throw new Error('data and salt arguments required'); + } - if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { - throw new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - } + if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { + throw new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + } - if (typeof salt === 'number') { - salt = module.exports.genSaltSync(salt); - } + if (typeof salt === 'number') { + salt = module.exports.genSaltSync(salt); + } - return bindings.encrypt_sync(data, salt); + return bindings.encrypt_sync(data, salt); }; /// hash data using a salt @@ -107,54 +105,167 @@ module.exports.hashSync = function hashSync(data, salt) { /// @param {String} salt the salt to use when hashing /// @param {Function} cb callback(err, hash) module.exports.hash = function hash(data, salt, cb) { - var error; + var error; - if (typeof data === 'function') { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - data(error); - }); - } + if (typeof data === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + data(error); + }); + } - if (typeof salt === 'function') { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - salt(error); - }); - } + if (typeof salt === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + salt(error); + }); + } + + // cb exists but is not a function + // return a rejecting promise + if (cb && typeof cb !== 'function') { + return promises.reject(new Error('cb must be a function or null to return a Promise')); + } + + if (!cb) { + return promises.promise(hash, this, [data, salt]); + } + + if (data == null || salt == null) { + error = new Error('data and salt arguments required'); + return process.nextTick(function() { + cb(error); + }); + } - // cb exists but is not a function - // return a rejecting promise - if (cb && typeof cb !== 'function') { - return promises.reject(new Error('cb must be a function or null to return a Promise')); - } + if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + cb(error); + }); + } - if (!cb) { - return promises.promise(hash, this, [data, salt]); - } - if (data == null || salt == null) { - error = new Error('data and salt arguments required'); - return process.nextTick(function() { - cb(error); - }); - } + if (typeof salt === 'number') { + return module.exports.genSalt(salt, function(err, salt) { + return bindings.encrypt(data, salt, cb); + }); + } - if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - cb(error); - }); - } + return bindings.encrypt(data, salt, cb); +}; +//For getting salts with the help of expected time, not rounds + +module.exports.genSaltByTime = function genSaltByTime(exptime, minor, cb) { + var error; + var rounds = 10; + // if callback is first argument, then use defaults for others + if (typeof arguments[0] === 'function') { + // have to set callback first otherwise arguments are overriden + cb = arguments[0]; + exptime = 100; + minor = 'b'; + // callback is second argument + } else if (typeof arguments[1] === 'function') { + // have to set callback first otherwise arguments are overriden + cb = arguments[1]; + minor = 'b'; + } + + if (!cb) { + return promises.promise(genSalt, this, [rounds, minor]); + } + + // default 100 miliseconds and minimum 4 miliseconds + if (!exptime) { + exptime = 100; + } else if (exptime < 4) { + exptime = 4; + } else if (typeof exptime !== 'number') { + // callback error asynchronously + error = new Error('Expected time must be a number'); + return process.nextTick(function() { + cb(error); + }); + } + + if (!minor) { + minor = 'b' + } else if (minor !== 'b' && minor !== 'a') { + error = new Error('minor must be either "a" or "b"'); + return process.nextTick(function() { + cb(error); + }); + } - if (typeof salt === 'number') { - return module.exports.genSalt(salt, function(err, salt) { - return bindings.encrypt(data, salt, cb); - }); + crypto.randomBytes(16, function(error, randomBytes) { + if (error) { + cb(error); + return; } - return bindings.encrypt(data, salt, cb); + //since the relation b/w expected time and rounds roughly follows exptime = 2^(rounds-3) + //rounds is equal to log2(exptime)+3 + rounds = Math.log(exptime)/Math.log(2); + rounds = Math.round(rounds)+3; + + // for a secure hash, taking 4 as minimum rounds + rounds = Math.max(rounds, 4); + bindings.gen_salt(minor, rounds, randomBytes, cb); + + }); +}; + +module.exports.hashByTime = function hashByTime(data, salt, cb) { + var error; + + if (typeof data === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + data(error); + }); + } + + if (typeof salt === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + salt(error); + }); + } + + // cb exists but is not a function + // return a rejecting promise + if (cb && typeof cb !== 'function') { + return promises.reject(new Error('cb must be a function or null to return a Promise')); + } + + if (!cb) { + return promises.promise(hash, this, [data, salt]); + } + + if (data == null || salt == null) { + error = new Error('data and salt arguments required'); + return process.nextTick(function() { + cb(error); + }); + } + + if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + cb(error); + }); + } + + + if (typeof salt === 'number') { + return module.exports.genSaltByTime(salt, function(err, salt) { + return bindings.encrypt(data, salt, cb); + }); + } + + return bindings.encrypt(data, salt, cb); }; /// compare raw data to hash @@ -162,15 +273,15 @@ module.exports.hash = function hash(data, salt, cb) { /// @param {String} hash expected hash /// @return {bool} true if hashed data matches hash module.exports.compareSync = function compareSync(data, hash) { - if (data == null || hash == null) { - throw new Error('data and hash arguments required'); - } + if (data == null || hash == null) { + throw new Error('data and hash arguments required'); + } - if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { - throw new Error('data must be a string or Buffer and hash must be a string'); - } + if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { + throw new Error('data must be a string or Buffer and hash must be a string'); + } - return bindings.compare_sync(data, hash); + return bindings.compare_sync(data, hash); }; /// compare raw data to hash @@ -178,59 +289,59 @@ module.exports.compareSync = function compareSync(data, hash) { /// @param {String} hash expected hash /// @param {Function} cb callback(err, matched) - matched is true if hashed data matches hash module.exports.compare = function compare(data, hash, cb) { - var error; - - if (typeof data === 'function') { - error = new Error('data and hash arguments required'); - return process.nextTick(function() { - data(error); - }); - } - - if (typeof hash === 'function') { - error = new Error('data and hash arguments required'); - return process.nextTick(function() { - hash(error); - }); - } - - // cb exists but is not a function - // return a rejecting promise - if (cb && typeof cb !== 'function') { - return promises.reject(new Error('cb must be a function or null to return a Promise')); - } + var error; - if (!cb) { - return promises.promise(compare, this, [data, hash]); - } + if (typeof data === 'function') { + error = new Error('data and hash arguments required'); + return process.nextTick(function() { + data(error); + }); + } - if (data == null || hash == null) { - error = new Error('data and hash arguments required'); - return process.nextTick(function() { - cb(error); - }); - } + if (typeof hash === 'function') { + error = new Error('data and hash arguments required'); + return process.nextTick(function() { + hash(error); + }); + } + + // cb exists but is not a function + // return a rejecting promise + if (cb && typeof cb !== 'function') { + return promises.reject(new Error('cb must be a function or null to return a Promise')); + } + + if (!cb) { + return promises.promise(compare, this, [data, hash]); + } + + if (data == null || hash == null) { + error = new Error('data and hash arguments required'); + return process.nextTick(function() { + cb(error); + }); + } - if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { - error = new Error('data and hash must be strings'); - return process.nextTick(function() { - cb(error); - }); - } + if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { + error = new Error('data and hash must be strings'); + return process.nextTick(function() { + cb(error); + }); + } - return bindings.compare(data, hash, cb); + return bindings.compare(data, hash, cb); }; /// @param {String} hash extract rounds from this hash /// @return {Number} the number of rounds used to encrypt a given hash module.exports.getRounds = function getRounds(hash) { - if (hash == null) { - throw new Error('hash argument required'); - } + if (hash == null) { + throw new Error('hash argument required'); + } - if (typeof hash !== 'string') { - throw new Error('hash must be a string'); - } + if (typeof hash !== 'string') { + throw new Error('hash must be a string'); + } - return bindings.get_rounds(hash); + return bindings.get_rounds(hash); }; From a179c500948889d0ad01a6f7d9a0e183e8f765ed Mon Sep 17 00:00:00 2001 From: Sujal Date: Tue, 24 Aug 2021 12:14:56 +0530 Subject: [PATCH 3/3] [FIXED] Indentation inconsistency --- bcrypt.js | 457 +++++++++++++++++++++++++++--------------------------- 1 file changed, 228 insertions(+), 229 deletions(-) diff --git a/bcrypt.js b/bcrypt.js index c3df6ea..70758dc 100644 --- a/bcrypt.js +++ b/bcrypt.js @@ -1,35 +1,37 @@ 'use strict'; + var nodePreGyp = require('@mapbox/node-pre-gyp'); var path = require('path'); var binding_path = nodePreGyp.find(path.resolve(path.join(__dirname, './package.json'))); var bindings = require(binding_path); + var crypto = require('crypto'); + var promises = require('./promises'); /// generate a salt (sync) /// @param {Number} [rounds] number of rounds (default 10) /// @return {String} salt module.exports.genSaltSync = function genSaltSync(rounds, minor) { - // default 10 rounds - if (!rounds) { - rounds = 18; - } else if (typeof rounds !== 'number') { - throw new Error('rounds must be a number'); - } - - if (!minor) { - minor = 'b'; - } else if (minor !== 'b' && minor !== 'a') { - throw new Error('minor must be either "a" or "b"'); - } - - return bindings.gen_salt_sync(minor, rounds, crypto.randomBytes(16)); + // default 10 rounds + if (!rounds) { + rounds = 10; + } else if (typeof rounds !== 'number') { + throw new Error('rounds must be a number'); + } + + if(!minor) { + minor = 'b'; + } else if(minor !== 'b' && minor !== 'a') { + throw new Error('minor must be either "a" or "b"'); + } + + return bindings.gen_salt_sync(minor, rounds, crypto.randomBytes(16)); }; /// generate a salt /// @param {Number} [rounds] number of rounds (default 10) /// @param {Function} cb callback(err, salt) - module.exports.genSalt = function genSalt(rounds, minor, cb) { var error; @@ -61,23 +63,82 @@ module.exports.genSalt = function genSalt(rounds, minor, cb) { }); } + if(!minor) { + minor = 'b' + } else if(minor !== 'b' && minor !== 'a') { + error = new Error('minor must be either "a" or "b"'); + return process.nextTick(function() { + cb(error); + }); + } + + crypto.randomBytes(16, function(error, randomBytes) { + if (error) { + cb(error); + return; + } + + bindings.gen_salt(minor, rounds, randomBytes, cb); + }); +}; + +module.exports.genSaltByTime = function genSaltByTime(exptime, minor, cb) { + var error; + var rounds = 10; + // if callback is first argument, then use defaults for others + if (typeof arguments[0] === 'function') { + // have to set callback first otherwise arguments are overriden + cb = arguments[0]; + exptime = 100; + minor = 'b'; + // callback is second argument + } else if (typeof arguments[1] === 'function') { + // have to set callback first otherwise arguments are overriden + cb = arguments[1]; + minor = 'b'; + } + + if (!cb) { + return promises.promise(genSaltByTime, this, [exptime, minor]); + } + + // default 100 milliseconds and minimum 4 miliseconds + if (!exptime) { + exptime = 100; + } else if (exptime < 4) { + exptime = 4; + } else if (typeof exptime !== 'number') { + // callback error asynchronously + error = new Error('Expected time must be a number'); + return process.nextTick(function() { + cb(error); + }); + } + if (!minor) { - minor = 'b' + minor = 'b' } else if (minor !== 'b' && minor !== 'a') { - error = new Error('minor must be either "a" or "b"'); - return process.nextTick(function() { - cb(error); - }); + error = new Error('minor must be either "a" or "b"'); + return process.nextTick(function() { + cb(error); + }); } crypto.randomBytes(16, function(error, randomBytes) { - if (error) { - cb(error); - return; - } + if (error) { + cb(error); + return; + } - bindings.gen_salt(minor, rounds, randomBytes, cb); - }); + //since the relation b/w expected time and rounds roughly follows exptime = 2^(rounds-3) + //rounds is equal to log2(exptime)+3 + rounds = Math.log(exptime)/Math.log(2); + rounds = Math.round(rounds)+3; + // for a secure hash, taking 4 as minimum rounds + rounds = Math.max(rounds, 4); + + bindings.gen_salt(minor, rounds, randomBytes, cb); + }); }; /// hash data using a salt @@ -85,19 +146,19 @@ module.exports.genSalt = function genSalt(rounds, minor, cb) { /// @param {String} salt the salt to use when hashing /// @return {String} hash module.exports.hashSync = function hashSync(data, salt) { - if (data == null || salt == null) { - throw new Error('data and salt arguments required'); - } + if (data == null || salt == null) { + throw new Error('data and salt arguments required'); + } - if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { - throw new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - } + if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { + throw new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + } - if (typeof salt === 'number') { - salt = module.exports.genSaltSync(salt); - } + if (typeof salt === 'number') { + salt = module.exports.genSaltSync(salt); + } - return bindings.encrypt_sync(data, salt); + return bindings.encrypt_sync(data, salt); }; /// hash data using a salt @@ -105,167 +166,105 @@ module.exports.hashSync = function hashSync(data, salt) { /// @param {String} salt the salt to use when hashing /// @param {Function} cb callback(err, hash) module.exports.hash = function hash(data, salt, cb) { - var error; - - if (typeof data === 'function') { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - data(error); - }); - } - - if (typeof salt === 'function') { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - salt(error); - }); - } - - // cb exists but is not a function - // return a rejecting promise - if (cb && typeof cb !== 'function') { - return promises.reject(new Error('cb must be a function or null to return a Promise')); - } - - if (!cb) { - return promises.promise(hash, this, [data, salt]); - } - - if (data == null || salt == null) { - error = new Error('data and salt arguments required'); - return process.nextTick(function() { - cb(error); - }); - } - - if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - cb(error); - }); - } + var error; + if (typeof data === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + data(error); + }); + } - if (typeof salt === 'number') { - return module.exports.genSalt(salt, function(err, salt) { - return bindings.encrypt(data, salt, cb); - }); - } + if (typeof salt === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + salt(error); + }); + } - return bindings.encrypt(data, salt, cb); -}; + // cb exists but is not a function + // return a rejecting promise + if (cb && typeof cb !== 'function') { + return promises.reject(new Error('cb must be a function or null to return a Promise')); + } -//For getting salts with the help of expected time, not rounds + if (!cb) { + return promises.promise(hash, this, [data, salt]); + } -module.exports.genSaltByTime = function genSaltByTime(exptime, minor, cb) { - var error; - var rounds = 10; - // if callback is first argument, then use defaults for others - if (typeof arguments[0] === 'function') { - // have to set callback first otherwise arguments are overriden - cb = arguments[0]; - exptime = 100; - minor = 'b'; - // callback is second argument - } else if (typeof arguments[1] === 'function') { - // have to set callback first otherwise arguments are overriden - cb = arguments[1]; - minor = 'b'; - } - - if (!cb) { - return promises.promise(genSalt, this, [rounds, minor]); - } - - // default 100 miliseconds and minimum 4 miliseconds - if (!exptime) { - exptime = 100; - } else if (exptime < 4) { - exptime = 4; - } else if (typeof exptime !== 'number') { - // callback error asynchronously - error = new Error('Expected time must be a number'); - return process.nextTick(function() { - cb(error); - }); - } - - if (!minor) { - minor = 'b' - } else if (minor !== 'b' && minor !== 'a') { - error = new Error('minor must be either "a" or "b"'); - return process.nextTick(function() { - cb(error); - }); - } + if (data == null || salt == null) { + error = new Error('data and salt arguments required'); + return process.nextTick(function() { + cb(error); + }); + } - crypto.randomBytes(16, function(error, randomBytes) { - if (error) { - cb(error); - return; + if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + cb(error); + }); } - //since the relation b/w expected time and rounds roughly follows exptime = 2^(rounds-3) - //rounds is equal to log2(exptime)+3 - rounds = Math.log(exptime)/Math.log(2); - rounds = Math.round(rounds)+3; - // for a secure hash, taking 4 as minimum rounds - rounds = Math.max(rounds, 4); - bindings.gen_salt(minor, rounds, randomBytes, cb); + if (typeof salt === 'number') { + return module.exports.genSalt(salt, function(err, salt) { + return bindings.encrypt(data, salt, cb); + }); + } - }); + return bindings.encrypt(data, salt, cb); }; module.exports.hashByTime = function hashByTime(data, salt, cb) { - var error; + var error; - if (typeof data === 'function') { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - data(error); - }); - } + if (typeof data === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + data(error); + }); + } - if (typeof salt === 'function') { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - salt(error); - }); - } - - // cb exists but is not a function - // return a rejecting promise - if (cb && typeof cb !== 'function') { - return promises.reject(new Error('cb must be a function or null to return a Promise')); - } - - if (!cb) { - return promises.promise(hash, this, [data, salt]); - } - - if (data == null || salt == null) { - error = new Error('data and salt arguments required'); - return process.nextTick(function() { - cb(error); - }); - } + if (typeof salt === 'function') { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + salt(error); + }); + } - if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { - error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); - return process.nextTick(function() { - cb(error); - }); - } + // cb exists but is not a function + // return a rejecting promise + if (cb && typeof cb !== 'function') { + return promises.reject(new Error('cb must be a function or null to return a Promise')); + } + if (!cb) { + return promises.promise(hashByTime, this, [data, salt]); + } - if (typeof salt === 'number') { - return module.exports.genSaltByTime(salt, function(err, salt) { - return bindings.encrypt(data, salt, cb); - }); - } + if (data == null || salt == null) { + error = new Error('data and salt arguments required'); + return process.nextTick(function() { + cb(error); + }); + } + + if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) { + error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds'); + return process.nextTick(function() { + cb(error); + }); + } - return bindings.encrypt(data, salt, cb); + + if (typeof salt === 'number') { + return module.exports.genSaltByTime(salt, function(err, salt) { + return bindings.encrypt(data, salt, cb); + }); + } + + return bindings.encrypt(data, salt, cb); }; /// compare raw data to hash @@ -273,15 +272,15 @@ module.exports.hashByTime = function hashByTime(data, salt, cb) { /// @param {String} hash expected hash /// @return {bool} true if hashed data matches hash module.exports.compareSync = function compareSync(data, hash) { - if (data == null || hash == null) { - throw new Error('data and hash arguments required'); - } + if (data == null || hash == null) { + throw new Error('data and hash arguments required'); + } - if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { - throw new Error('data must be a string or Buffer and hash must be a string'); - } + if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { + throw new Error('data must be a string or Buffer and hash must be a string'); + } - return bindings.compare_sync(data, hash); + return bindings.compare_sync(data, hash); }; /// compare raw data to hash @@ -289,59 +288,59 @@ module.exports.compareSync = function compareSync(data, hash) { /// @param {String} hash expected hash /// @param {Function} cb callback(err, matched) - matched is true if hashed data matches hash module.exports.compare = function compare(data, hash, cb) { - var error; + var error; - if (typeof data === 'function') { - error = new Error('data and hash arguments required'); - return process.nextTick(function() { - data(error); - }); - } + if (typeof data === 'function') { + error = new Error('data and hash arguments required'); + return process.nextTick(function() { + data(error); + }); + } - if (typeof hash === 'function') { - error = new Error('data and hash arguments required'); - return process.nextTick(function() { - hash(error); - }); - } - - // cb exists but is not a function - // return a rejecting promise - if (cb && typeof cb !== 'function') { - return promises.reject(new Error('cb must be a function or null to return a Promise')); - } - - if (!cb) { - return promises.promise(compare, this, [data, hash]); - } - - if (data == null || hash == null) { - error = new Error('data and hash arguments required'); - return process.nextTick(function() { - cb(error); - }); - } + if (typeof hash === 'function') { + error = new Error('data and hash arguments required'); + return process.nextTick(function() { + hash(error); + }); + } - if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { - error = new Error('data and hash must be strings'); - return process.nextTick(function() { - cb(error); - }); - } + // cb exists but is not a function + // return a rejecting promise + if (cb && typeof cb !== 'function') { + return promises.reject(new Error('cb must be a function or null to return a Promise')); + } + + if (!cb) { + return promises.promise(compare, this, [data, hash]); + } + + if (data == null || hash == null) { + error = new Error('data and hash arguments required'); + return process.nextTick(function() { + cb(error); + }); + } - return bindings.compare(data, hash, cb); + if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') { + error = new Error('data and hash must be strings'); + return process.nextTick(function() { + cb(error); + }); + } + + return bindings.compare(data, hash, cb); }; /// @param {String} hash extract rounds from this hash /// @return {Number} the number of rounds used to encrypt a given hash module.exports.getRounds = function getRounds(hash) { - if (hash == null) { - throw new Error('hash argument required'); - } + if (hash == null) { + throw new Error('hash argument required'); + } - if (typeof hash !== 'string') { - throw new Error('hash must be a string'); - } + if (typeof hash !== 'string') { + throw new Error('hash must be a string'); + } - return bindings.get_rounds(hash); + return bindings.get_rounds(hash); };