Skip to content

Commit 4e94d15

Browse files
committed
fix: Integrity#match prioritizes overlapping hashes
1 parent dce3dab commit 4e94d15

File tree

2 files changed

+35
-17
lines changed

2 files changed

+35
-17
lines changed

Diff for: lib/index.js

+28-15
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,12 @@ class IntegrityStream extends MiniPass {
5151

5252
if (!this.sri) {
5353
this.algorithm = null
54-
} else if (this.sri.isIntegrity) {
55-
this.goodSri = !this.sri.isEmpty()
56-
57-
if (this.goodSri) {
58-
this.algorithm = this.sri.pickAlgorithm(this.opts)
59-
}
6054
} else if (this.sri.isHash) {
6155
this.goodSri = true
6256
this.algorithm = this.sri.algorithm
57+
} else {
58+
this.goodSri = !this.sri.isEmpty()
59+
this.algorithm = this.sri.pickAlgorithm(this.opts)
6360
}
6461

6562
this.digests = this.goodSri ? this.sri[this.algorithm] : null
@@ -184,8 +181,13 @@ class Hash {
184181
if (!other) {
185182
return false
186183
}
187-
if (other instanceof Integrity) {
188-
const algo = other.pickAlgorithm(opts)
184+
if (other.isIntegrity) {
185+
const algo = other.pickAlgorithm(opts, [this.algorithm])
186+
187+
if (!algo) {
188+
return false
189+
}
190+
189191
const foundHash = other[algo].find(hash => hash.digest === this.digest)
190192

191193
if (foundHash) {
@@ -323,8 +325,9 @@ class Integrity {
323325
if (!other) {
324326
return false
325327
}
326-
const algo = other.pickAlgorithm(opts)
328+
const algo = other.pickAlgorithm(opts, Object.keys(this))
327329
return (
330+
!!algo &&
328331
this[algo] &&
329332
other[algo] &&
330333
this[algo].find(hash =>
@@ -335,12 +338,22 @@ class Integrity {
335338
) || false
336339
}
337340

338-
pickAlgorithm (opts) {
341+
// Pick the highest priority algorithm present, optionally also limited to a
342+
// set of hashes found in another integrity. When limiting it may return
343+
// nothing.
344+
pickAlgorithm (opts, hashes) {
339345
const pickAlgorithm = opts?.pickAlgorithm || getPrioritizedHash
340-
const keys = Object.keys(this)
341-
return keys.reduce((acc, algo) => {
342-
return pickAlgorithm(acc, algo) || acc
346+
const keys = Object.keys(this).filter(k => {
347+
if (hashes?.length) {
348+
return hashes.includes(k)
349+
}
350+
return true
343351
})
352+
if (keys.length) {
353+
return keys.reduce((acc, algo) => pickAlgorithm(acc, algo) || acc)
354+
}
355+
// no intersection between this and hashes,
356+
return null
344357
}
345358
}
346359

@@ -550,7 +563,7 @@ function createIntegrity (opts) {
550563
}
551564
}
552565

553-
const NODE_HASHES = new Set(crypto.getHashes())
566+
const NODE_HASHES = crypto.getHashes()
554567

555568
// This is a Best Effort™ at a reasonable priority for hash algos
556569
const DEFAULT_PRIORITY = [
@@ -560,7 +573,7 @@ const DEFAULT_PRIORITY = [
560573
'sha3',
561574
'sha3-256', 'sha3-384', 'sha3-512',
562575
'sha3_256', 'sha3_384', 'sha3_512',
563-
].filter(algo => NODE_HASHES.has(algo))
576+
].filter(algo => NODE_HASHES.includes(algo))
564577

565578
function getPrioritizedHash (algo1, algo2) {
566579
/* eslint-disable-next-line max-len */

Diff for: test/match.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ function hash (data, algorithm) {
1313
}
1414

1515
test('hashes should match when valid', t => {
16-
const sha = hash(TEST_DATA, 'sha512')
17-
const integrity = `sha512-${sha}`
16+
const integrity = `sha512-${hash(TEST_DATA, 'sha512')}`
17+
const otherIntegrity = `sha512-${hash('mismatch', 'sha512')}`
1818
const parsed = ssri.parse(integrity, { single: true })
1919
t.same(
2020
parsed.match(integrity, { single: true }),
@@ -47,5 +47,10 @@ test('hashes should match when valid', t => {
4747
false,
4848
'null integrity just returns false'
4949
)
50+
t.same(
51+
parsed.match(otherIntegrity),
52+
false,
53+
'should not match with a totally different integrity'
54+
)
5055
t.end()
5156
})

0 commit comments

Comments
 (0)