Skip to content

Commit

Permalink
fix: faster stream verification
Browse files Browse the repository at this point in the history
  • Loading branch information
H4ad authored and wraithgar committed Apr 11, 2023
1 parent 3e72ec0 commit dce3dab
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 8 deletions.
54 changes: 46 additions & 8 deletions lib/index.js
Expand Up @@ -29,19 +29,39 @@ class IntegrityStream extends MiniPass {
this.#getOptions()

// options used for calculating stream. can't be changed.
const algorithms = opts?.algorithms || DEFAULT_ALGORITHMS
this.algorithms = Array.from(
new Set(algorithms.concat(this.algorithm ? [this.algorithm] : []))
)
if (opts?.algorithms) {
this.algorithms = Array.from(
new Set(opts.algorithms.concat(this.algorithm ? [this.algorithm] : []))
)
} else {
this.algorithms = DEFAULT_ALGORITHMS

if (this.algorithm !== null && this.algorithm !== DEFAULT_ALGORITHMS[0]) {
this.algorithms.push(this.algorithm)
}
}

this.hashes = this.algorithms.map(crypto.createHash)
}

#getOptions () {
// For verification
this.sri = this.opts?.integrity ? parse(this.opts?.integrity, this.opts) : null
this.expectedSize = this.opts?.size
this.goodSri = this.sri ? !!Object.keys(this.sri).length : false
this.algorithm = this.goodSri ? this.sri.pickAlgorithm(this.opts) : null

if (!this.sri) {
this.algorithm = null
} else if (this.sri.isIntegrity) {
this.goodSri = !this.sri.isEmpty()

if (this.goodSri) {
this.algorithm = this.sri.pickAlgorithm(this.opts)
}
} else if (this.sri.isHash) {
this.goodSri = true
this.algorithm = this.sri.algorithm
}

this.digests = this.goodSri ? this.sri[this.algorithm] : null
this.optString = getOptString(this.opts?.options)
}
Expand Down Expand Up @@ -159,6 +179,24 @@ class Hash {
return this.toString()
}

match (integrity, opts) {
const other = parse(integrity, opts)
if (!other) {
return false
}
if (other instanceof Integrity) {
const algo = other.pickAlgorithm(opts)
const foundHash = other[algo].find(hash => hash.digest === this.digest)

if (foundHash) {
return foundHash
}

return false
}
return other.digest === this.digest ? other : false
}

toString (opts) {
if (opts?.strict) {
// Strict mode enforces the standard as close to the foot of the
Expand Down Expand Up @@ -399,7 +437,7 @@ function fromStream (stream, opts) {
sri = s
})
istream.on('end', () => resolve(sri))
istream.on('data', () => {})
istream.resume()
})
}

Expand Down Expand Up @@ -466,7 +504,7 @@ function checkStream (stream, sri, opts) {
verified = s
})
checker.on('end', () => resolve(verified))
checker.on('data', () => {})
checker.resume()
})
}

Expand Down
3 changes: 3 additions & 0 deletions test/check.js
Expand Up @@ -160,6 +160,9 @@ test('checkStream', t => {
})
}).then(res => {
t.same(res, meta, 'Accepts Hash-like SRI')
return ssri.checkStream(fileStream(), `sha512-${hash(TEST_DATA, 'sha512')}`, { single: true })
}).then(res => {
t.same(res, meta, 'Process successfully with single option')
return ssri.checkStream(
fileStream(),
`sha512-nope sha512-${hash(TEST_DATA, 'sha512')}`
Expand Down
51 changes: 51 additions & 0 deletions test/match.js
@@ -0,0 +1,51 @@
'use strict'

const crypto = require('crypto')
const fs = require('fs')
const test = require('tap').test

const ssri = require('..')

const TEST_DATA = fs.readFileSync(__filename)

function hash (data, algorithm) {
return crypto.createHash(algorithm).update(data).digest('base64')
}

test('hashes should match when valid', t => {
const sha = hash(TEST_DATA, 'sha512')
const integrity = `sha512-${sha}`
const parsed = ssri.parse(integrity, { single: true })
t.same(
parsed.match(integrity, { single: true }),
parsed,
'should return the same algo when digest is equal (single option)'
)
t.same(
parsed.match('sha-233', { single: true }),
false,
'invalid integrity should not match (single option)'
)
t.same(
parsed.match(null, { single: true }),
false,
'null integrity just returns false (single option)'
)

t.same(
parsed.match(integrity),
parsed,
'should return the same algo when digest is equal'
)
t.same(
parsed.match('sha-233'),
false,
'invalid integrity should not match'
)
t.same(
parsed.match(null),
false,
'null integrity just returns false'
)
t.end()
})

1 comment on commit dce3dab

@CarolSmith60

This comment was marked as spam.

Please sign in to comment.