Skip to content

Commit 34a7c74

Browse files
claudiahdzisaacs
authored andcommittedSep 18, 2019
chore(streams): refactor integrityStream fn
1 parent 363995e commit 34a7c74

File tree

1 file changed

+49
-50
lines changed

1 file changed

+49
-50
lines changed
 

‎index.js

+49-50
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,62 @@ const SsriOpts = figgyPudding({
2424
strict: {default: false}
2525
})
2626

27-
class Transform extends MiniPass {
27+
class IntegrityStream extends MiniPass {
2828
constructor (opts) {
2929
super()
3030
this.size = 0
31-
this.transform = opts.transform
31+
this.opts = opts
32+
// For verification
33+
this.sri = opts.integrity && parse(opts.integrity, opts)
34+
this.goodSri = this.sri && Object.keys(this.sri).length
35+
this.algorithm = this.goodSri && this.sri.pickAlgorithm(opts)
36+
this.digests = this.goodSri && this.sri[this.algorithm]
37+
// Calculating stream
38+
this.algorithms = Array.from(
39+
new Set(opts.algorithms.concat(this.algorithm ? [this.algorithm] : []))
40+
)
41+
this.hashes = this.algorithms.map(crypto.createHash)
42+
this.onEnd = this.onEnd.bind(this)
43+
}
44+
emit (ev, data) {
45+
if (ev === 'end') this.onEnd()
46+
return super.emit(ev, data)
3247
}
3348
write (data) {
3449
this.size += data.length
35-
this.transform(data)
50+
this.hashes.forEach(h => h.update(data))
3651
super.write(data)
3752
}
53+
onEnd () {
54+
const optString = (this.opts.options && this.opts.options.length)
55+
? `?${this.opts.options.join('?')}`
56+
: ''
57+
const newSri = parse(this.hashes.map((h, i) => {
58+
return `${this.algorithms[i]}-${h.digest('base64')}${optString}`
59+
}).join(' '), this.opts)
60+
// Integrity verification mode
61+
const match = this.goodSri && newSri.match(this.sri, this.opts)
62+
if (typeof this.opts.size === 'number' && this.size !== this.opts.size) {
63+
const err = new Error(`stream size mismatch when checking ${this.sri}.\n Wanted: ${this.opts.size}\n Found: ${this.size}`)
64+
err.code = 'EBADSIZE'
65+
err.found = this.size
66+
err.expected = this.opts.size
67+
err.sri = this.sri
68+
this.emit('error', err)
69+
} else if (this.opts.integrity && !match) {
70+
const err = new Error(`${this.sri} integrity checksum failed when using ${this.algorithm}: wanted ${this.digests} but got ${newSri}. (${this.size} bytes)`)
71+
err.code = 'EINTEGRITY'
72+
err.found = newSri
73+
err.expected = this.digests
74+
err.algorithm = this.algorithm
75+
err.sri = this.sri
76+
this.emit('error', err)
77+
} else {
78+
this.emit('size', this.size)
79+
this.emit('integrity', newSri)
80+
match && this.emit('verified', match)
81+
}
82+
}
3883
}
3984

4085
class Hash {
@@ -303,53 +348,7 @@ function checkStream (stream, sri, opts) {
303348

304349
module.exports.integrityStream = integrityStream
305350
function integrityStream (opts) {
306-
opts = SsriOpts(opts)
307-
// For verification
308-
const sri = opts.integrity && parse(opts.integrity, opts)
309-
const goodSri = sri && Object.keys(sri).length
310-
const algorithm = goodSri && sri.pickAlgorithm(opts)
311-
const digests = goodSri && sri[algorithm]
312-
// Calculating stream
313-
const algorithms = Array.from(
314-
new Set(opts.algorithms.concat(algorithm ? [algorithm] : []))
315-
)
316-
const hashes = algorithms.map(crypto.createHash)
317-
const stream = new Transform({
318-
transform (chunk) { hashes.forEach(h => h.update(chunk)) }
319-
})
320-
321-
stream.on('end', () => {
322-
const optString = (opts.options && opts.options.length)
323-
? `?${opts.options.join('?')}`
324-
: ''
325-
const newSri = parse(hashes.map((h, i) => {
326-
return `${algorithms[i]}-${h.digest('base64')}${optString}`
327-
}).join(' '), opts)
328-
// Integrity verification mode
329-
const match = goodSri && newSri.match(sri, opts)
330-
const streamSize = stream.size
331-
if (typeof opts.size === 'number' && streamSize !== opts.size) {
332-
const err = new Error(`stream size mismatch when checking ${sri}.\n Wanted: ${opts.size}\n Found: ${streamSize}`)
333-
err.code = 'EBADSIZE'
334-
err.found = streamSize
335-
err.expected = opts.size
336-
err.sri = sri
337-
stream.emit('error', err)
338-
} else if (opts.integrity && !match) {
339-
const err = new Error(`${sri} integrity checksum failed when using ${algorithm}: wanted ${digests} but got ${newSri}. (${streamSize} bytes)`)
340-
err.code = 'EINTEGRITY'
341-
err.found = newSri
342-
err.expected = digests
343-
err.algorithm = algorithm
344-
err.sri = sri
345-
stream.emit('error', err)
346-
} else {
347-
stream.emit('size', streamSize)
348-
stream.emit('integrity', newSri)
349-
match && stream.emit('verified', match)
350-
}
351-
})
352-
return stream
351+
return new IntegrityStream(SsriOpts(opts))
353352
}
354353

355354
module.exports.create = createIntegrity

0 commit comments

Comments
 (0)
Please sign in to comment.