@@ -5,14 +5,21 @@ const { Minipass } = require('minipass')
55
66const SPEC_ALGORITHMS = [ 'sha512' , 'sha384' , 'sha256' ]
77const DEFAULT_ALGORITHMS = [ 'sha512' ]
8+ const NODE_HASHES = crypto . getHashes ( )
89
9- // TODO: this should really be a hardcoded list of algorithms we support,
10- // rather than [a-z0-9].
10+ // TODO: this should really be a hardcoded list of algorithms we support, rather than [a-z0-9].
1111const BASE64_REGEX = / ^ [ a - z 0 - 9 + / ] + (?: = ? = ? ) $ / i
1212const SRI_REGEX = / ^ ( [ a - z 0 - 9 ] + ) - ( [ ^ ? ] + ) ( \? [ ? \S * ] * ) ? $ /
1313const STRICT_SRI_REGEX = / ^ ( [ a - z 0 - 9 ] + ) - ( [ A - Z a - z 0 - 9 + / = ] { 44 , 88 } ) ( \? [ \x21 - \x7E ] * ) ? $ /
1414const VCHAR_REGEX = / ^ [ \x21 - \x7E ] + $ /
1515
16+ // This is a Best Effort™ at a reasonable priority for hash algos
17+ const DEFAULT_PRIORITY = [
18+ 'md5' , 'whirlpool' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' ,
19+ // TODO - it's unclear _which_ of these Node will actually use as its name for the algorithm, so we guesswork it based on the OpenSSL names.
20+ 'sha3' , 'sha3-256' , 'sha3-384' , 'sha3-512' , 'sha3_256' , 'sha3_384' , 'sha3_512' ,
21+ ] . filter ( algo => NODE_HASHES . includes ( algo ) )
22+
1623const getOptString = options => options ?. length ? `?${ options . join ( '?' ) } ` : ''
1724
1825class IntegrityStream extends Minipass {
@@ -99,15 +106,13 @@ class IntegrityStream extends Minipass {
99106 // Integrity verification mode
100107 const match = this . goodSri && newSri . match ( this . sri , this . opts )
101108 if ( typeof this . expectedSize === 'number' && this . size !== this . expectedSize ) {
102- /* eslint-disable-next-line max-len */
103109 const err = new Error ( `stream size mismatch when checking ${ this . sri } .\n Wanted: ${ this . expectedSize } \n Found: ${ this . size } ` )
104110 err . code = 'EBADSIZE'
105111 err . found = this . size
106112 err . expected = this . expectedSize
107113 err . sri = this . sri
108114 this . emit ( 'error' , err )
109115 } else if ( this . sri && ! match ) {
110- /* eslint-disable-next-line max-len */
111116 const err = new Error ( `${ this . sri } integrity checksum failed when using ${ this . algorithm } : wanted ${ this . digests } but got ${ newSri } . (${ this . size } bytes)` )
112117 err . code = 'EINTEGRITY'
113118 err . found = newSri
@@ -137,8 +142,7 @@ class Hash {
137142 const strict = opts ?. strict
138143 this . source = hash . trim ( )
139144
140- // set default values so that we make V8 happy to
141- // always see a familiar object template.
145+ // set default values so that we make V8 happy to always see a familiar object template.
142146 this . digest = ''
143147 this . algorithm = ''
144148 this . options = [ ]
@@ -156,6 +160,9 @@ class Hash {
156160 if ( strict && ! SPEC_ALGORITHMS . includes ( match [ 1 ] ) ) {
157161 return
158162 }
163+ if ( ! NODE_HASHES . includes ( match [ 1 ] ) ) {
164+ return
165+ }
159166 this . algorithm = match [ 1 ]
160167 this . digest = match [ 2 ]
161168
@@ -198,15 +205,12 @@ class Hash {
198205
199206 toString ( opts ) {
200207 if ( opts ?. strict ) {
201- // Strict mode enforces the standard as close to the foot of the
202- // letter as it can.
208+ // Strict mode enforces the standard as close to the foot of the letter as it can.
203209 if ( ! (
204210 // The spec has very restricted productions for algorithms.
205211 // https://www.w3.org/TR/CSP2/#source-list-syntax
206212 SPEC_ALGORITHMS . includes ( this . algorithm ) &&
207- // Usually, if someone insists on using a "different" base64, we
208- // leave it as-is, since there's multiple standards, and the
209- // specified is not a URL-safe variant.
213+ // Usually, if someone insists on using a "different" base64, we leave it as-is, since there are multiple standards, and the specified is not a URL-safe variant.
210214 // https://www.w3.org/TR/CSP2/#base64_value
211215 this . digest . match ( BASE64_REGEX ) &&
212216 // Option syntax is strictly visual chars.
@@ -300,8 +304,7 @@ class Integrity {
300304 return parse ( this , { single : true } ) . hexDigest ( )
301305 }
302306
303- // add additional hashes to an integrity value, but prevent
304- // *changing* an existing integrity hash.
307+ // add additional hashes to an integrity value, but prevent *changing* an existing integrity hash.
305308 merge ( integrity , opts ) {
306309 const other = parse ( integrity , opts )
307310 for ( const algo in other ) {
@@ -323,33 +326,25 @@ class Integrity {
323326 return false
324327 }
325328 const algo = other . pickAlgorithm ( opts , Object . keys ( this ) )
326- return (
327- ! ! algo &&
328- this [ algo ] &&
329- other [ algo ] &&
330- this [ algo ] . find ( hash =>
331- other [ algo ] . find ( otherhash =>
332- hash . digest === otherhash . digest
333- )
329+ return ! ! algo && this [ algo ] . find ( hash =>
330+ other [ algo ] . find ( otherhash =>
331+ hash . digest === otherhash . digest
334332 )
335333 ) || false
336334 }
337335
338- // Pick the highest priority algorithm present, optionally also limited to a
339- // set of hashes found in another integrity. When limiting it may return
340- // nothing.
336+ // Pick the highest priority algorithm present, optionally also limited to a set of hashes found in another integrity.
337+ // When limiting it may return nothing.
341338 pickAlgorithm ( opts , hashes ) {
342339 const pickAlgorithm = opts ?. pickAlgorithm || getPrioritizedHash
343- const keys = Object . keys ( this ) . filter ( k => {
344- if ( hashes ?. length ) {
345- return hashes . includes ( k )
346- }
347- return true
348- } )
340+ let keys = Object . keys ( this )
341+ if ( hashes ?. length ) {
342+ keys = keys . filter ( k => hashes . includes ( k ) )
343+ }
349344 if ( keys . length ) {
350345 return keys . reduce ( ( acc , algo ) => pickAlgorithm ( acc , algo ) || acc )
351346 }
352- // no intersection between this and hashes,
347+ // no intersection between this and hashes
353348 return null
354349 }
355350}
@@ -380,7 +375,7 @@ function _parse (integrity, opts) {
380375 const hash = new Hash ( string , opts )
381376 if ( hash . algorithm && hash . digest ) {
382377 const algo = hash . algorithm
383- if ( ! acc [ algo ] ) {
378+ if ( ! Object . keys ( acc ) . includes ( algo ) ) {
384379 acc [ algo ] = [ ]
385380 }
386381 acc [ algo ] . push ( hash )
@@ -421,9 +416,7 @@ function fromData (data, opts) {
421416 `${ algo } -${ digest } ${ optString } ` ,
422417 opts
423418 )
424- /* istanbul ignore else - it would be VERY strange if the string we
425- * just calculated with an algo did not have an algo or digest.
426- */
419+ // istanbul ignore else - it would be VERY strange if the string we just calculated with an algo did not have an algo or digest.
427420 if ( hash . algorithm && hash . digest ) {
428421 const hashAlgo = hash . algorithm
429422 if ( ! acc [ hashAlgo ] ) {
@@ -473,15 +466,13 @@ function checkData (data, sri, opts) {
473466 if ( match || ! ( opts . error ) ) {
474467 return match
475468 } else if ( typeof opts . size === 'number' && ( data . length !== opts . size ) ) {
476- /* eslint-disable-next-line max-len */
477469 const err = new Error ( `data size mismatch when checking ${ sri } .\n Wanted: ${ opts . size } \n Found: ${ data . length } ` )
478470 err . code = 'EBADSIZE'
479471 err . found = data . length
480472 err . expected = opts . size
481473 err . sri = sri
482474 throw err
483475 } else {
484- /* eslint-disable-next-line max-len */
485476 const err = new Error ( `Integrity checksum failed when using ${ algorithm } : Wanted ${ sri } , but got ${ newSri } . (${ data . length } bytes)` )
486477 err . code = 'EINTEGRITY'
487478 err . found = newSri
@@ -538,20 +529,11 @@ function createIntegrity (opts) {
538529 digest : function ( ) {
539530 const integrity = algorithms . reduce ( ( acc , algo ) => {
540531 const digest = hashes . shift ( ) . digest ( 'base64' )
541- const hash = new Hash (
542- `${ algo } -${ digest } ${ optString } ` ,
543- opts
544- )
545- /* istanbul ignore else - it would be VERY strange if the hash we
546- * just calculated with an algo did not have an algo or digest.
547- */
548- if ( hash . algorithm && hash . digest ) {
549- const hashAlgo = hash . algorithm
550- if ( ! acc [ hashAlgo ] ) {
551- acc [ hashAlgo ] = [ ]
552- }
553- acc [ hashAlgo ] . push ( hash )
532+ const hash = new Hash ( `${ algo } -${ digest } ${ optString } ` , opts )
533+ if ( ! acc [ hash . algorithm ] ) {
534+ acc [ hash . algorithm ] = [ ]
554535 }
536+ acc [ hash . algorithm ] . push ( hash )
555537 return acc
556538 } , new Integrity ( ) )
557539
@@ -560,18 +542,6 @@ function createIntegrity (opts) {
560542 }
561543}
562544
563- const NODE_HASHES = crypto . getHashes ( )
564-
565- // This is a Best Effort™ at a reasonable priority for hash algos
566- const DEFAULT_PRIORITY = [
567- 'md5' , 'whirlpool' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' ,
568- // TODO - it's unclear _which_ of these Node will actually use as its name
569- // for the algorithm, so we guesswork it based on the OpenSSL names.
570- 'sha3' ,
571- 'sha3-256' , 'sha3-384' , 'sha3-512' ,
572- 'sha3_256' , 'sha3_384' , 'sha3_512' ,
573- ] . filter ( algo => NODE_HASHES . includes ( algo ) )
574-
575545function getPrioritizedHash ( algo1 , algo2 ) {
576546 /* eslint-disable-next-line max-len */
577547 return DEFAULT_PRIORITY . indexOf ( algo1 . toLowerCase ( ) ) >= DEFAULT_PRIORITY . indexOf ( algo2 . toLowerCase ( ) )
0 commit comments