@@ -24,17 +24,62 @@ const SsriOpts = figgyPudding({
24
24
strict : { default : false }
25
25
} )
26
26
27
- class Transform extends MiniPass {
27
+ class IntegrityStream extends MiniPass {
28
28
constructor ( opts ) {
29
29
super ( )
30
30
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 )
32
47
}
33
48
write ( data ) {
34
49
this . size += data . length
35
- this . transform ( data )
50
+ this . hashes . forEach ( h => h . update ( data ) )
36
51
super . write ( data )
37
52
}
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
+ }
38
83
}
39
84
40
85
class Hash {
@@ -303,53 +348,7 @@ function checkStream (stream, sri, opts) {
303
348
304
349
module . exports . integrityStream = integrityStream
305
350
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 ) )
353
352
}
354
353
355
354
module . exports . create = createIntegrity
0 commit comments