@@ -4,6 +4,7 @@ const crypto = require('crypto')
4
4
const MiniPass = require ( 'minipass' )
5
5
6
6
const SPEC_ALGORITHMS = [ 'sha256' , 'sha384' , 'sha512' ]
7
+ const DEFAULT_ALGORITHMS = [ 'sha512' ]
7
8
8
9
// TODO: this should really be a hardcoded list of algorithms we support,
9
10
// rather than [a-z0-9].
@@ -12,21 +13,7 @@ const SRI_REGEX = /^([a-z0-9]+)-([^?]+)([?\S*]*)$/
12
13
const STRICT_SRI_REGEX = / ^ ( [ a - z 0 - 9 ] + ) - ( [ A - Z a - z 0 - 9 + / = ] { 44 , 88 } ) ( \? [ \x21 - \x7E ] * ) ? $ /
13
14
const VCHAR_REGEX = / ^ [ \x21 - \x7E ] + $ /
14
15
15
- const defaultOpts = {
16
- algorithms : [ 'sha512' ] ,
17
- error : false ,
18
- options : [ ] ,
19
- pickAlgorithm : getPrioritizedHash ,
20
- sep : ' ' ,
21
- single : false ,
22
- strict : false ,
23
- }
24
-
25
- const ssriOpts = ( opts = { } ) => ( { ...defaultOpts , ...opts } )
26
-
27
- const getOptString = options => ! options || ! options . length
28
- ? ''
29
- : `?${ options . join ( '?' ) } `
16
+ const getOptString = options => options ?. length ? `?${ options . join ( '?' ) } ` : ''
30
17
31
18
const _onEnd = Symbol ( '_onEnd' )
32
19
const _getOptions = Symbol ( '_getOptions' )
@@ -44,27 +31,21 @@ class IntegrityStream extends MiniPass {
44
31
this [ _getOptions ] ( )
45
32
46
33
// options used for calculating stream. can't be changed.
47
- const { algorithms = defaultOpts . algorithms } = opts
34
+ const algorithms = opts ? .algorithms || DEFAULT_ALGORITHMS
48
35
this . algorithms = Array . from (
49
36
new Set ( algorithms . concat ( this . algorithm ? [ this . algorithm ] : [ ] ) )
50
37
)
51
38
this . hashes = this . algorithms . map ( crypto . createHash )
52
39
}
53
40
54
41
[ _getOptions ] ( ) {
55
- const {
56
- integrity,
57
- size,
58
- options,
59
- } = { ...defaultOpts , ...this . opts }
60
-
61
42
// For verification
62
- this . sri = integrity ? parse ( integrity , this . opts ) : null
63
- this . expectedSize = size
43
+ this . sri = this . opts ?. integrity ? parse ( this . opts ?. integrity , this . opts ) : null
44
+ this . expectedSize = this . opts ?. size
64
45
this . goodSri = this . sri ? ! ! Object . keys ( this . sri ) . length : false
65
46
this . algorithm = this . goodSri ? this . sri . pickAlgorithm ( this . opts ) : null
66
47
this . digests = this . goodSri ? this . sri [ this . algorithm ] : null
67
- this . optString = getOptString ( options )
48
+ this . optString = getOptString ( this . opts ?. options )
68
49
}
69
50
70
51
on ( ev , handler ) {
@@ -141,8 +122,7 @@ class Hash {
141
122
}
142
123
143
124
constructor ( hash , opts ) {
144
- opts = ssriOpts ( opts )
145
- const strict = ! ! opts . strict
125
+ const strict = opts ?. strict
146
126
this . source = hash . trim ( )
147
127
148
128
// set default values so that we make V8 happy to
@@ -161,7 +141,7 @@ class Hash {
161
141
if ( ! match ) {
162
142
return
163
143
}
164
- if ( strict && ! SPEC_ALGORITHMS . some ( a => a === match [ 1 ] ) ) {
144
+ if ( strict && ! SPEC_ALGORITHMS . includes ( match [ 1 ] ) ) {
165
145
return
166
146
}
167
147
this . algorithm = match [ 1 ]
@@ -182,14 +162,13 @@ class Hash {
182
162
}
183
163
184
164
toString ( opts ) {
185
- opts = ssriOpts ( opts )
186
- if ( opts . strict ) {
165
+ if ( opts ?. strict ) {
187
166
// Strict mode enforces the standard as close to the foot of the
188
167
// letter as it can.
189
168
if ( ! (
190
169
// The spec has very restricted productions for algorithms.
191
170
// https://www.w3.org/TR/CSP2/#source-list-syntax
192
- SPEC_ALGORITHMS . some ( x => x === this . algorithm ) &&
171
+ SPEC_ALGORITHMS . includes ( this . algorithm ) &&
193
172
// Usually, if someone insists on using a "different" base64, we
194
173
// leave it as-is, since there's multiple standards, and the
195
174
// specified is not a URL-safe variant.
@@ -203,10 +182,7 @@ class Hash {
203
182
return ''
204
183
}
205
184
}
206
- const options = this . options && this . options . length
207
- ? `?${ this . options . join ( '?' ) } `
208
- : ''
209
- return `${ this . algorithm } -${ this . digest } ${ options } `
185
+ return `${ this . algorithm } -${ this . digest } ${ getOptString ( this . options ) } `
210
186
}
211
187
}
212
188
@@ -224,9 +200,8 @@ class Integrity {
224
200
}
225
201
226
202
toString ( opts ) {
227
- opts = ssriOpts ( opts )
228
- let sep = opts . sep || ' '
229
- if ( opts . strict ) {
203
+ let sep = opts ?. sep || ' '
204
+ if ( opts ?. strict ) {
230
205
// Entries must be separated by whitespace, according to spec.
231
206
sep = sep . replace ( / \S + / g, ' ' )
232
207
}
@@ -238,7 +213,6 @@ class Integrity {
238
213
}
239
214
240
215
concat ( integrity , opts ) {
241
- opts = ssriOpts ( opts )
242
216
const other = typeof integrity === 'string'
243
217
? integrity
244
218
: stringify ( integrity , opts )
@@ -252,7 +226,6 @@ class Integrity {
252
226
// add additional hashes to an integrity value, but prevent
253
227
// *changing* an existing integrity hash.
254
228
merge ( integrity , opts ) {
255
- opts = ssriOpts ( opts )
256
229
const other = parse ( integrity , opts )
257
230
for ( const algo in other ) {
258
231
if ( this [ algo ] ) {
@@ -268,7 +241,6 @@ class Integrity {
268
241
}
269
242
270
243
match ( integrity , opts ) {
271
- opts = ssriOpts ( opts )
272
244
const other = parse ( integrity , opts )
273
245
if ( ! other ) {
274
246
return false
@@ -286,8 +258,7 @@ class Integrity {
286
258
}
287
259
288
260
pickAlgorithm ( opts ) {
289
- opts = ssriOpts ( opts )
290
- const pickAlgorithm = opts . pickAlgorithm
261
+ const pickAlgorithm = opts ?. pickAlgorithm || getPrioritizedHash
291
262
const keys = Object . keys ( this )
292
263
return keys . reduce ( ( acc , algo ) => {
293
264
return pickAlgorithm ( acc , algo ) || acc
@@ -300,7 +271,6 @@ function parse (sri, opts) {
300
271
if ( ! sri ) {
301
272
return null
302
273
}
303
- opts = ssriOpts ( opts )
304
274
if ( typeof sri === 'string' ) {
305
275
return _parse ( sri , opts )
306
276
} else if ( sri . algorithm && sri . digest ) {
@@ -315,7 +285,7 @@ function parse (sri, opts) {
315
285
function _parse ( integrity , opts ) {
316
286
// 3.4.3. Parse metadata
317
287
// https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
318
- if ( opts . single ) {
288
+ if ( opts ? .single ) {
319
289
return new Hash ( integrity , opts )
320
290
}
321
291
const hashes = integrity . trim ( ) . split ( / \s + / ) . reduce ( ( acc , string ) => {
@@ -334,7 +304,6 @@ function _parse (integrity, opts) {
334
304
335
305
module . exports . stringify = stringify
336
306
function stringify ( obj , opts ) {
337
- opts = ssriOpts ( opts )
338
307
if ( obj . algorithm && obj . digest ) {
339
308
return Hash . prototype . toString . call ( obj , opts )
340
309
} else if ( typeof obj === 'string' ) {
@@ -346,8 +315,7 @@ function stringify (obj, opts) {
346
315
347
316
module . exports . fromHex = fromHex
348
317
function fromHex ( hexDigest , algorithm , opts ) {
349
- opts = ssriOpts ( opts )
350
- const optString = getOptString ( opts . options )
318
+ const optString = getOptString ( opts ?. options )
351
319
return parse (
352
320
`${ algorithm } -${
353
321
Buffer . from ( hexDigest , 'hex' ) . toString ( 'base64' )
@@ -357,9 +325,8 @@ function fromHex (hexDigest, algorithm, opts) {
357
325
358
326
module . exports . fromData = fromData
359
327
function fromData ( data , opts ) {
360
- opts = ssriOpts ( opts )
361
- const algorithms = opts . algorithms
362
- const optString = getOptString ( opts . options )
328
+ const algorithms = opts ?. algorithms || DEFAULT_ALGORITHMS
329
+ const optString = getOptString ( opts ?. options )
363
330
return algorithms . reduce ( ( acc , algo ) => {
364
331
const digest = crypto . createHash ( algo ) . update ( data ) . digest ( 'base64' )
365
332
const hash = new Hash (
@@ -382,7 +349,6 @@ function fromData (data, opts) {
382
349
383
350
module . exports . fromStream = fromStream
384
351
function fromStream ( stream , opts ) {
385
- opts = ssriOpts ( opts )
386
352
const istream = integrityStream ( opts )
387
353
return new Promise ( ( resolve , reject ) => {
388
354
stream . pipe ( istream )
@@ -399,10 +365,9 @@ function fromStream (stream, opts) {
399
365
400
366
module . exports . checkData = checkData
401
367
function checkData ( data , sri , opts ) {
402
- opts = ssriOpts ( opts )
403
368
sri = parse ( sri , opts )
404
369
if ( ! sri || ! Object . keys ( sri ) . length ) {
405
- if ( opts . error ) {
370
+ if ( opts ? .error ) {
406
371
throw Object . assign (
407
372
new Error ( 'No valid integrity hashes to check against' ) , {
408
373
code : 'EINTEGRITY' ,
@@ -416,7 +381,8 @@ function checkData (data, sri, opts) {
416
381
const digest = crypto . createHash ( algorithm ) . update ( data ) . digest ( 'base64' )
417
382
const newSri = parse ( { algorithm, digest } )
418
383
const match = newSri . match ( sri , opts )
419
- if ( match || ! opts . error ) {
384
+ opts = opts || Object . create ( null )
385
+ if ( match || ! ( opts . error ) ) {
420
386
return match
421
387
} else if ( typeof opts . size === 'number' && ( data . length !== opts . size ) ) {
422
388
/* eslint-disable-next-line max-len */
@@ -440,7 +406,7 @@ function checkData (data, sri, opts) {
440
406
441
407
module . exports . checkStream = checkStream
442
408
function checkStream ( stream , sri , opts ) {
443
- opts = ssriOpts ( opts )
409
+ opts = opts || Object . create ( null )
444
410
opts . integrity = sri
445
411
sri = parse ( sri , opts )
446
412
if ( ! sri || ! Object . keys ( sri ) . length ) {
@@ -465,15 +431,14 @@ function checkStream (stream, sri, opts) {
465
431
}
466
432
467
433
module . exports . integrityStream = integrityStream
468
- function integrityStream ( opts = { } ) {
434
+ function integrityStream ( opts = Object . create ( null ) ) {
469
435
return new IntegrityStream ( opts )
470
436
}
471
437
472
438
module . exports . create = createIntegrity
473
439
function createIntegrity ( opts ) {
474
- opts = ssriOpts ( opts )
475
- const algorithms = opts . algorithms
476
- const optString = getOptString ( opts . options )
440
+ const algorithms = opts ?. algorithms || DEFAULT_ALGORITHMS
441
+ const optString = getOptString ( opts ?. options )
477
442
478
443
const hashes = algorithms . map ( crypto . createHash )
479
444
0 commit comments