Skip to content

Commit 6e6877d

Browse files
authored
fix: remove spread of defaultOpts (#72)
1 parent 61d92a1 commit 6e6877d

File tree

1 file changed

+25
-60
lines changed

1 file changed

+25
-60
lines changed

lib/index.js

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const crypto = require('crypto')
44
const MiniPass = require('minipass')
55

66
const SPEC_ALGORITHMS = ['sha256', 'sha384', 'sha512']
7+
const DEFAULT_ALGORITHMS = ['sha512']
78

89
// TODO: this should really be a hardcoded list of algorithms we support,
910
// rather than [a-z0-9].
@@ -12,21 +13,7 @@ const SRI_REGEX = /^([a-z0-9]+)-([^?]+)([?\S*]*)$/
1213
const STRICT_SRI_REGEX = /^([a-z0-9]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)?$/
1314
const VCHAR_REGEX = /^[\x21-\x7E]+$/
1415

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('?')}` : ''
3017

3118
const _onEnd = Symbol('_onEnd')
3219
const _getOptions = Symbol('_getOptions')
@@ -44,27 +31,21 @@ class IntegrityStream extends MiniPass {
4431
this[_getOptions]()
4532

4633
// options used for calculating stream. can't be changed.
47-
const { algorithms = defaultOpts.algorithms } = opts
34+
const algorithms = opts?.algorithms || DEFAULT_ALGORITHMS
4835
this.algorithms = Array.from(
4936
new Set(algorithms.concat(this.algorithm ? [this.algorithm] : []))
5037
)
5138
this.hashes = this.algorithms.map(crypto.createHash)
5239
}
5340

5441
[_getOptions] () {
55-
const {
56-
integrity,
57-
size,
58-
options,
59-
} = { ...defaultOpts, ...this.opts }
60-
6142
// 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
6445
this.goodSri = this.sri ? !!Object.keys(this.sri).length : false
6546
this.algorithm = this.goodSri ? this.sri.pickAlgorithm(this.opts) : null
6647
this.digests = this.goodSri ? this.sri[this.algorithm] : null
67-
this.optString = getOptString(options)
48+
this.optString = getOptString(this.opts?.options)
6849
}
6950

7051
on (ev, handler) {
@@ -141,8 +122,7 @@ class Hash {
141122
}
142123

143124
constructor (hash, opts) {
144-
opts = ssriOpts(opts)
145-
const strict = !!opts.strict
125+
const strict = opts?.strict
146126
this.source = hash.trim()
147127

148128
// set default values so that we make V8 happy to
@@ -161,7 +141,7 @@ class Hash {
161141
if (!match) {
162142
return
163143
}
164-
if (strict && !SPEC_ALGORITHMS.some(a => a === match[1])) {
144+
if (strict && !SPEC_ALGORITHMS.includes(match[1])) {
165145
return
166146
}
167147
this.algorithm = match[1]
@@ -182,14 +162,13 @@ class Hash {
182162
}
183163

184164
toString (opts) {
185-
opts = ssriOpts(opts)
186-
if (opts.strict) {
165+
if (opts?.strict) {
187166
// Strict mode enforces the standard as close to the foot of the
188167
// letter as it can.
189168
if (!(
190169
// The spec has very restricted productions for algorithms.
191170
// https://www.w3.org/TR/CSP2/#source-list-syntax
192-
SPEC_ALGORITHMS.some(x => x === this.algorithm) &&
171+
SPEC_ALGORITHMS.includes(this.algorithm) &&
193172
// Usually, if someone insists on using a "different" base64, we
194173
// leave it as-is, since there's multiple standards, and the
195174
// specified is not a URL-safe variant.
@@ -203,10 +182,7 @@ class Hash {
203182
return ''
204183
}
205184
}
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)}`
210186
}
211187
}
212188

@@ -224,9 +200,8 @@ class Integrity {
224200
}
225201

226202
toString (opts) {
227-
opts = ssriOpts(opts)
228-
let sep = opts.sep || ' '
229-
if (opts.strict) {
203+
let sep = opts?.sep || ' '
204+
if (opts?.strict) {
230205
// Entries must be separated by whitespace, according to spec.
231206
sep = sep.replace(/\S+/g, ' ')
232207
}
@@ -238,7 +213,6 @@ class Integrity {
238213
}
239214

240215
concat (integrity, opts) {
241-
opts = ssriOpts(opts)
242216
const other = typeof integrity === 'string'
243217
? integrity
244218
: stringify(integrity, opts)
@@ -252,7 +226,6 @@ class Integrity {
252226
// add additional hashes to an integrity value, but prevent
253227
// *changing* an existing integrity hash.
254228
merge (integrity, opts) {
255-
opts = ssriOpts(opts)
256229
const other = parse(integrity, opts)
257230
for (const algo in other) {
258231
if (this[algo]) {
@@ -268,7 +241,6 @@ class Integrity {
268241
}
269242

270243
match (integrity, opts) {
271-
opts = ssriOpts(opts)
272244
const other = parse(integrity, opts)
273245
if (!other) {
274246
return false
@@ -286,8 +258,7 @@ class Integrity {
286258
}
287259

288260
pickAlgorithm (opts) {
289-
opts = ssriOpts(opts)
290-
const pickAlgorithm = opts.pickAlgorithm
261+
const pickAlgorithm = opts?.pickAlgorithm || getPrioritizedHash
291262
const keys = Object.keys(this)
292263
return keys.reduce((acc, algo) => {
293264
return pickAlgorithm(acc, algo) || acc
@@ -300,7 +271,6 @@ function parse (sri, opts) {
300271
if (!sri) {
301272
return null
302273
}
303-
opts = ssriOpts(opts)
304274
if (typeof sri === 'string') {
305275
return _parse(sri, opts)
306276
} else if (sri.algorithm && sri.digest) {
@@ -315,7 +285,7 @@ function parse (sri, opts) {
315285
function _parse (integrity, opts) {
316286
// 3.4.3. Parse metadata
317287
// https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
318-
if (opts.single) {
288+
if (opts?.single) {
319289
return new Hash(integrity, opts)
320290
}
321291
const hashes = integrity.trim().split(/\s+/).reduce((acc, string) => {
@@ -334,7 +304,6 @@ function _parse (integrity, opts) {
334304

335305
module.exports.stringify = stringify
336306
function stringify (obj, opts) {
337-
opts = ssriOpts(opts)
338307
if (obj.algorithm && obj.digest) {
339308
return Hash.prototype.toString.call(obj, opts)
340309
} else if (typeof obj === 'string') {
@@ -346,8 +315,7 @@ function stringify (obj, opts) {
346315

347316
module.exports.fromHex = fromHex
348317
function fromHex (hexDigest, algorithm, opts) {
349-
opts = ssriOpts(opts)
350-
const optString = getOptString(opts.options)
318+
const optString = getOptString(opts?.options)
351319
return parse(
352320
`${algorithm}-${
353321
Buffer.from(hexDigest, 'hex').toString('base64')
@@ -357,9 +325,8 @@ function fromHex (hexDigest, algorithm, opts) {
357325

358326
module.exports.fromData = fromData
359327
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)
363330
return algorithms.reduce((acc, algo) => {
364331
const digest = crypto.createHash(algo).update(data).digest('base64')
365332
const hash = new Hash(
@@ -382,7 +349,6 @@ function fromData (data, opts) {
382349

383350
module.exports.fromStream = fromStream
384351
function fromStream (stream, opts) {
385-
opts = ssriOpts(opts)
386352
const istream = integrityStream(opts)
387353
return new Promise((resolve, reject) => {
388354
stream.pipe(istream)
@@ -399,10 +365,9 @@ function fromStream (stream, opts) {
399365

400366
module.exports.checkData = checkData
401367
function checkData (data, sri, opts) {
402-
opts = ssriOpts(opts)
403368
sri = parse(sri, opts)
404369
if (!sri || !Object.keys(sri).length) {
405-
if (opts.error) {
370+
if (opts?.error) {
406371
throw Object.assign(
407372
new Error('No valid integrity hashes to check against'), {
408373
code: 'EINTEGRITY',
@@ -416,7 +381,8 @@ function checkData (data, sri, opts) {
416381
const digest = crypto.createHash(algorithm).update(data).digest('base64')
417382
const newSri = parse({ algorithm, digest })
418383
const match = newSri.match(sri, opts)
419-
if (match || !opts.error) {
384+
opts = opts || Object.create(null)
385+
if (match || !(opts.error)) {
420386
return match
421387
} else if (typeof opts.size === 'number' && (data.length !== opts.size)) {
422388
/* eslint-disable-next-line max-len */
@@ -440,7 +406,7 @@ function checkData (data, sri, opts) {
440406

441407
module.exports.checkStream = checkStream
442408
function checkStream (stream, sri, opts) {
443-
opts = ssriOpts(opts)
409+
opts = opts || Object.create(null)
444410
opts.integrity = sri
445411
sri = parse(sri, opts)
446412
if (!sri || !Object.keys(sri).length) {
@@ -465,15 +431,14 @@ function checkStream (stream, sri, opts) {
465431
}
466432

467433
module.exports.integrityStream = integrityStream
468-
function integrityStream (opts = {}) {
434+
function integrityStream (opts = Object.create(null)) {
469435
return new IntegrityStream(opts)
470436
}
471437

472438
module.exports.create = createIntegrity
473439
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)
477442

478443
const hashes = algorithms.map(crypto.createHash)
479444

0 commit comments

Comments
 (0)