/ node_modules / bcrypt / bcrypt.js
bcrypt.js
  1  const path = require('path');
  2  const bindings = require('node-gyp-build')(path.resolve(__dirname));
  3  
  4  const crypto = require('crypto');
  5  
  6  const promises = require('./promises');
  7  
  8  /// generate a salt (sync)
  9  /// @param {Number} [rounds] number of rounds (default 10)
 10  /// @return {String} salt
 11  function genSaltSync(rounds, minor) {
 12      // default 10 rounds
 13      if (!rounds) {
 14          rounds = 10;
 15      } else if (typeof rounds !== 'number') {
 16          throw new Error('rounds must be a number');
 17      }
 18  
 19      if (!minor) {
 20          minor = 'b';
 21      } else if (minor !== 'b' && minor !== 'a') {
 22          throw new Error('minor must be either "a" or "b"');
 23      }
 24  
 25      return bindings.gen_salt_sync(minor, rounds, crypto.randomBytes(16));
 26  }
 27  
 28  /// generate a salt
 29  /// @param {Number} [rounds] number of rounds (default 10)
 30  /// @param {Function} cb callback(err, salt)
 31  function genSalt(rounds, minor, cb) {
 32      let error;
 33  
 34      // if callback is first argument, then use defaults for others
 35      if (typeof arguments[0] === 'function') {
 36          // have to set callback first otherwise arguments are overridden
 37          cb = arguments[0];
 38          rounds = 10;
 39          minor = 'b';
 40          // callback is second argument
 41      } else if (typeof arguments[1] === 'function') {
 42          // have to set callback first otherwise arguments are overridden
 43          cb = arguments[1];
 44          minor = 'b';
 45      }
 46  
 47      if (!cb) {
 48          return promises.promise(genSalt, this, [rounds, minor]);
 49      }
 50  
 51      // default 10 rounds
 52      if (!rounds) {
 53          rounds = 10;
 54      } else if (typeof rounds !== 'number') {
 55          // callback error asynchronously
 56          error = new Error('rounds must be a number');
 57          return process.nextTick(function () {
 58              cb(error);
 59          });
 60      }
 61  
 62      if (!minor) {
 63          minor = 'b'
 64      } else if (minor !== 'b' && minor !== 'a') {
 65          error = new Error('minor must be either "a" or "b"');
 66          return process.nextTick(function () {
 67              cb(error);
 68          });
 69      }
 70  
 71      crypto.randomBytes(16, function (error, randomBytes) {
 72          if (error) {
 73              cb(error);
 74              return;
 75          }
 76  
 77          bindings.gen_salt(minor, rounds, randomBytes, cb);
 78      });
 79  }
 80  
 81  /// hash data using a salt
 82  /// @param {String|Buffer} data the data to encrypt
 83  /// @param {String} salt the salt to use when hashing
 84  /// @return {String} hash
 85  function hashSync(data, salt) {
 86      if (data == null || salt == null) {
 87          throw new Error('data and salt arguments required');
 88      }
 89  
 90      if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) {
 91          throw new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
 92      }
 93  
 94      if (typeof salt === 'number') {
 95          salt = module.exports.genSaltSync(salt);
 96      }
 97  
 98      return bindings.encrypt_sync(data, salt);
 99  }
100  
101  /// hash data using a salt
102  /// @param {String|Buffer} data the data to encrypt
103  /// @param {String} salt the salt to use when hashing
104  /// @param {Function} cb callback(err, hash)
105  function hash(data, salt, cb) {
106      let error;
107  
108      if (typeof data === 'function') {
109          error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
110          return process.nextTick(function () {
111              data(error);
112          });
113      }
114  
115      if (typeof salt === 'function') {
116          error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
117          return process.nextTick(function () {
118              salt(error);
119          });
120      }
121  
122      // cb exists but is not a function
123      // return a rejecting promise
124      if (cb && typeof cb !== 'function') {
125          return promises.reject(new Error('cb must be a function or null to return a Promise'));
126      }
127  
128      if (!cb) {
129          return promises.promise(hash, this, [data, salt]);
130      }
131  
132      if (data == null || salt == null) {
133          error = new Error('data and salt arguments required');
134          return process.nextTick(function () {
135              cb(error);
136          });
137      }
138  
139      if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) {
140          error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
141          return process.nextTick(function () {
142              cb(error);
143          });
144      }
145  
146  
147      if (typeof salt === 'number') {
148          return module.exports.genSalt(salt, function (err, salt) {
149              return bindings.encrypt(data, salt, cb);
150          });
151      }
152  
153      return bindings.encrypt(data, salt, cb);
154  }
155  
156  /// compare raw data to hash
157  /// @param {String|Buffer} data the data to hash and compare
158  /// @param {String} hash expected hash
159  /// @return {bool} true if hashed data matches hash
160  function compareSync(data, hash) {
161      if (data == null || hash == null) {
162          throw new Error('data and hash arguments required');
163      }
164  
165      if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') {
166          throw new Error('data must be a string or Buffer and hash must be a string');
167      }
168  
169      return bindings.compare_sync(data, hash);
170  }
171  
172  /// compare raw data to hash
173  /// @param {String|Buffer} data the data to hash and compare
174  /// @param {String} hash expected hash
175  /// @param {Function} cb callback(err, matched) - matched is true if hashed data matches hash
176  function compare(data, hash, cb) {
177      let error;
178  
179      if (typeof data === 'function') {
180          error = new Error('data and hash arguments required');
181          return process.nextTick(function () {
182              data(error);
183          });
184      }
185  
186      if (typeof hash === 'function') {
187          error = new Error('data and hash arguments required');
188          return process.nextTick(function () {
189              hash(error);
190          });
191      }
192  
193      // cb exists but is not a function
194      // return a rejecting promise
195      if (cb && typeof cb !== 'function') {
196          return promises.reject(new Error('cb must be a function or null to return a Promise'));
197      }
198  
199      if (!cb) {
200          return promises.promise(compare, this, [data, hash]);
201      }
202  
203      if (data == null || hash == null) {
204          error = new Error('data and hash arguments required');
205          return process.nextTick(function () {
206              cb(error);
207          });
208      }
209  
210      if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') {
211          error = new Error('data and hash must be strings');
212          return process.nextTick(function () {
213              cb(error);
214          });
215      }
216  
217      return bindings.compare(data, hash, cb);
218  }
219  
220  /// @param {String} hash extract rounds from this hash
221  /// @return {Number} the number of rounds used to encrypt a given hash
222  function getRounds(hash) {
223      if (hash == null) {
224          throw new Error('hash argument required');
225      }
226  
227      if (typeof hash !== 'string') {
228          throw new Error('hash must be a string');
229      }
230  
231      return bindings.get_rounds(hash);
232  }
233  
234  module.exports = {
235      genSaltSync,
236      genSalt,
237      hashSync,
238      hash,
239      compareSync,
240      compare,
241      getRounds,
242  }