diff --git a/README.md b/README.md index 8011418..a6c07e7 100644 --- a/README.md +++ b/README.md @@ -389,6 +389,9 @@ If `opts.pickAlgorithm` is provided, it will be used by [`Integrity#pickAlgorithm`](#integrity-pick-algorithm) when deciding which of the available digests to match against. +If `opts.error` is true, and verification fails, `checkData` will throw either +an `EBADSIZE` or an `EINTEGRITY` error, instead of just returning false. + ##### Example ```javascript @@ -396,6 +399,7 @@ const data = fs.readFileSync('index.js') ssri.checkData(data, ssri.fromData(data)) // -> 'sha512' ssri.checkData(data, 'sha256-l981iLWj8kurw4UbNy8Lpxqdzd7UOxS50Glhv8FwfZ0') ssri.checkData(data, 'sha1-BaDDigEST') // -> false +ssri.checkData(data, 'sha1-BaDDigEST', {error: true}) // -> Error! EINTEGRITY ``` #### `> ssri.checkStream(stream, sri, [opts]) -> Promise` diff --git a/index.js b/index.js index 5418256..ff7881f 100644 --- a/index.js +++ b/index.js @@ -216,10 +216,39 @@ module.exports.checkData = checkData function checkData (data, sri, opts) { opts = opts || {} sri = parse(sri, opts) - if (!Object.keys(sri).length) { return false } + if (!Object.keys(sri).length) { + if (opts.error) { + throw Object.assign( + new Error('No valid integrity hashes to check against'), { + code: 'EINTEGRITY' + } + ) + } else { + return false + } + } const algorithm = sri.pickAlgorithm(opts) const digest = crypto.createHash(algorithm).update(data).digest('base64') - return parse({algorithm, digest}).match(sri, opts) + const newSri = parse({algorithm, digest}) + const match = newSri.match(sri, opts) + if (match || !opts.error) { + return match + } else if (typeof opts.size === 'number' && (data.length !== opts.size)) { + const err = new Error(`data size mismatch when checking ${sri}.\n Wanted: ${opts.size}\n Found: ${data.length}`) + err.code = 'EBADSIZE' + err.found = data.length + err.expected = opts.size + err.sri = sri + throw err + } else { + const err = new Error(`Integrity checksum failed when using ${algorithm}: Wanted ${sri}, but got ${newSri}. (${data.length} bytes)`) + err.code = 'EINTEGRITY' + err.found = newSri + err.expected = sri + err.algorithm = algorithm + err.sri = sri + throw err + } } module.exports.checkStream = checkStream diff --git a/test/check.js b/test/check.js index e099716..029c0ee 100644 --- a/test/check.js +++ b/test/check.js @@ -28,6 +28,9 @@ test('checkData', t => { meta, 'Buffer data successfully verified' ) + t.doesNotThrow(() => { + ssri.checkData(TEST_DATA, sri, {error: true}) + }, 'error not thrown when error: true and data verifies') t.deepEqual( ssri.checkData(TEST_DATA, `sha512-${hash(TEST_DATA, 'sha512')}`), meta, @@ -59,6 +62,12 @@ test('checkData', t => { false, 'returns false when verification fails' ) + t.throws(() => { + ssri.checkData('nope', sri, {error: true}) + }, /Integrity checksum failed/, 'integrity error thrown when error: true with bad data') + t.throws(() => { + ssri.checkData('nope', sri, {error: true, size: 3}) + }, /data size mismatch/, 'size error thrown when error: true with bad size') t.equal( ssri.checkData('nope', 'sha512-nope'), false, @@ -74,6 +83,9 @@ test('checkData', t => { false, 'returns false on empty sri input' ) + t.throws(() => { + ssri.checkData('nope', '', {error: true}) + }, /No valid integrity hashes/, 'errors on empty sri input if error: true') t.deepEqual( ssri.checkData(TEST_DATA, [ 'sha512-nope',