diff --git a/.eslintrc b/.eslintrc index 0877636..33bd34c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -60,5 +60,17 @@ "max-lines-per-function": "off", }, }, + { + "files": "hash.js", + "globals": { + "Uint8Array": false, + }, + }, + { + "files": "test/test.js", + "globals": { + "Uint16Array": false, + }, + }, ], } diff --git a/hash.js b/hash.js index 5a522ad..397b87a 100644 --- a/hash.js +++ b/hash.js @@ -1,6 +1,7 @@ 'use strict'; var Buffer = require('safe-buffer').Buffer; +var toBuffer = require('to-buffer'); // prototype class for hash functions function Hash(blockSize, finalSize) { @@ -12,10 +13,7 @@ function Hash(blockSize, finalSize) { Hash.prototype.update = function (data, enc) { /* eslint no-param-reassign: 0 */ - if (typeof data === 'string') { - enc = enc || 'utf8'; - data = Buffer.from(data, enc); - } + data = toBuffer(data, enc || 'utf8'); var block = this._block; var blockSize = this._blockSize; diff --git a/package.json b/package.json index 21884c8..2fc779e 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ }, "dependencies": { "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" }, "devDependencies": { "@ljharb/eslint-config": "^21.1.1", diff --git a/test/test.js b/test/test.js index 12eb031..a3fcaf1 100644 --- a/test/test.js +++ b/test/test.js @@ -6,6 +6,12 @@ var Buffer = require('safe-buffer').Buffer; var Sha1 = require('../').sha1; +var nodeSupportsUint16 = false; +try { + crypto.createHash('sha1').update(new Uint16Array()); + nodeSupportsUint16 = true; +} catch (err) {} + var inputs = [ ['', 'ascii'], ['abc', 'ascii'], @@ -15,8 +21,10 @@ var inputs = [ ['123456789abcdef123456789abcdef123456789abcdef123456789ab', 'ascii'], ['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde', 'ascii'], ['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'ascii'], - ['foobarbaz', 'ascii'] -]; + ['foobarbaz', 'ascii'], + [Buffer.from('buffer')], + nodeSupportsUint16 ? [new Uint16Array([1, 2, 3])] : null +].filter(Boolean); tape("hash is the same as node's crypto", function (t) { inputs.forEach(function (v) { @@ -35,7 +43,7 @@ tape('call update multiple times', function (t) { var sha1hash = crypto.createHash('sha1'); for (var i = 0; i < v[0].length; i = (i + 1) * 2) { - var s = v[0].substring(i, (i + 1) * 2); + var s = v[0].slice(i, (i + 1) * 2); hash.update(s, v[1]); sha1hash.update(s, v[1]); } @@ -74,7 +82,7 @@ tape('hex encoding', function (t) { var sha1hash = crypto.createHash('sha1'); for (var i = 0; i < v[0].length; i = (i + 1) * 2) { - var s = v[0].substring(i, (i + 1) * 2); + var s = v[0].slice(i, (i + 1) * 2); hash.update(Buffer.from(s, 'ascii').toString('hex'), 'hex'); sha1hash.update(Buffer.from(s, 'ascii').toString('hex'), 'hex'); } @@ -88,6 +96,29 @@ tape('hex encoding', function (t) { t.end(); }); +tape('throws on invalid input', function (t) { + var invalid = [ + {}, // non-arrayish + { length: 20 }, // undefined values + [NaN], // non-numbers + [[]], // non-numbers + [1, 1.5], // non-integers + [1, 256], // out of bounds + [-1, 0] // out of bounds + ]; + + invalid.forEach(function (input) { + var hash = new Sha1(); + + t['throws'](function () { + hash.update(input); + hash.digest('hex'); + }); + }); + + t.end(); +}); + tape('call digest for more than MAX_UINT32 bits of data', function (t) { var sha1hash = crypto.createHash('sha1'); var hash = new Sha1();