1
1
'use strict'
2
2
3
3
const crypto = require ( 'crypto' )
4
+ const figgyPudding = require ( 'figgy-pudding' )
4
5
const Transform = require ( 'stream' ) . Transform
5
6
6
7
const SPEC_ALGORITHMS = [ 'sha256' , 'sha384' , 'sha512' ]
@@ -10,10 +11,24 @@ const SRI_REGEX = /^([^-]+)-([^?]+)([?\S*]*)$/
10
11
const STRICT_SRI_REGEX = / ^ ( [ ^ - ] + ) - ( [ A - Z a - z 0 - 9 + / = ] { 44 , 88 } ) ( \? [ \x21 - \x7E ] * ) * $ /
11
12
const VCHAR_REGEX = / ^ [ \x21 - \x7E ] + $ /
12
13
14
+ const SsriOpts = figgyPudding ( {
15
+ algorithms : { default : [ 'sha512' ] } ,
16
+ error : { default : false } ,
17
+ integrity : { } ,
18
+ options : { default : [ ] } ,
19
+ pickAlgorithm : { default : ( ) => getPrioritizedHash } ,
20
+ Promise : { default : ( ) => Promise } ,
21
+ sep : { default : ' ' } ,
22
+ single : { default : false } ,
23
+ size : { } ,
24
+ strict : { default : false }
25
+ } )
26
+
13
27
class Hash {
14
28
get isHash ( ) { return true }
15
29
constructor ( hash , opts ) {
16
- const strict = ! ! ( opts && opts . strict )
30
+ opts = SsriOpts ( opts )
31
+ const strict = ! ! opts . strict
17
32
this . source = hash . trim ( )
18
33
// 3.1. Integrity metadata (called "Hash" by ssri)
19
34
// https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description
@@ -37,7 +52,8 @@ class Hash {
37
52
return this . toString ( )
38
53
}
39
54
toString ( opts ) {
40
- if ( opts && opts . strict ) {
55
+ opts = SsriOpts ( opts )
56
+ if ( opts . strict ) {
41
57
// Strict mode enforces the standard as close to the foot of the
42
58
// letter as it can.
43
59
if ( ! (
@@ -70,7 +86,7 @@ class Integrity {
70
86
return this . toString ( )
71
87
}
72
88
toString ( opts ) {
73
- opts = opts || { }
89
+ opts = SsriOpts ( opts )
74
90
let sep = opts . sep || ' '
75
91
if ( opts . strict ) {
76
92
// Entries must be separated by whitespace, according to spec.
@@ -83,6 +99,7 @@ class Integrity {
83
99
} ) . filter ( x => x . length ) . join ( sep )
84
100
}
85
101
concat ( integrity , opts ) {
102
+ opts = SsriOpts ( opts )
86
103
const other = typeof integrity === 'string'
87
104
? integrity
88
105
: stringify ( integrity , opts )
@@ -92,6 +109,7 @@ class Integrity {
92
109
return parse ( this , { single : true } ) . hexDigest ( )
93
110
}
94
111
match ( integrity , opts ) {
112
+ opts = SsriOpts ( opts )
95
113
const other = parse ( integrity , opts )
96
114
const algo = other . pickAlgorithm ( opts )
97
115
return (
@@ -105,7 +123,8 @@ class Integrity {
105
123
) || false
106
124
}
107
125
pickAlgorithm ( opts ) {
108
- const pickAlgorithm = ( opts && opts . pickAlgorithm ) || getPrioritizedHash
126
+ opts = SsriOpts ( opts )
127
+ const pickAlgorithm = opts . pickAlgorithm
109
128
const keys = Object . keys ( this )
110
129
if ( ! keys . length ) {
111
130
throw new Error ( `No algorithms available for ${
@@ -120,7 +139,7 @@ class Integrity {
120
139
121
140
module . exports . parse = parse
122
141
function parse ( sri , opts ) {
123
- opts = opts || { }
142
+ opts = SsriOpts ( opts )
124
143
if ( typeof sri === 'string' ) {
125
144
return _parse ( sri , opts )
126
145
} else if ( sri . algorithm && sri . digest ) {
@@ -151,6 +170,7 @@ function _parse (integrity, opts) {
151
170
152
171
module . exports . stringify = stringify
153
172
function stringify ( obj , opts ) {
173
+ opts = SsriOpts ( opts )
154
174
if ( obj . algorithm && obj . digest ) {
155
175
return Hash . prototype . toString . call ( obj , opts )
156
176
} else if ( typeof obj === 'string' ) {
@@ -162,7 +182,8 @@ function stringify (obj, opts) {
162
182
163
183
module . exports . fromHex = fromHex
164
184
function fromHex ( hexDigest , algorithm , opts ) {
165
- const optString = ( opts && opts . options && opts . options . length )
185
+ opts = SsriOpts ( opts )
186
+ const optString = opts . options && opts . options . length
166
187
? `?${ opts . options . join ( '?' ) } `
167
188
: ''
168
189
return parse (
@@ -174,8 +195,8 @@ function fromHex (hexDigest, algorithm, opts) {
174
195
175
196
module . exports . fromData = fromData
176
197
function fromData ( data , opts ) {
177
- opts = opts || { }
178
- const algorithms = opts . algorithms || [ 'sha512' ]
198
+ opts = SsriOpts ( opts )
199
+ const algorithms = opts . algorithms
179
200
const optString = opts . options && opts . options . length
180
201
? `?${ opts . options . join ( '?' ) } `
181
202
: ''
@@ -196,7 +217,7 @@ function fromData (data, opts) {
196
217
197
218
module . exports . fromStream = fromStream
198
219
function fromStream ( stream , opts ) {
199
- opts = opts || { }
220
+ opts = SsriOpts ( opts )
200
221
const P = opts . Promise || Promise
201
222
const istream = integrityStream ( opts )
202
223
return new P ( ( resolve , reject ) => {
@@ -212,7 +233,7 @@ function fromStream (stream, opts) {
212
233
213
234
module . exports . checkData = checkData
214
235
function checkData ( data , sri , opts ) {
215
- opts = opts || { }
236
+ opts = SsriOpts ( opts )
216
237
sri = parse ( sri , opts )
217
238
if ( ! Object . keys ( sri ) . length ) {
218
239
if ( opts . error ) {
@@ -251,9 +272,9 @@ function checkData (data, sri, opts) {
251
272
252
273
module . exports . checkStream = checkStream
253
274
function checkStream ( stream , sri , opts ) {
254
- opts = opts || { }
275
+ opts = SsriOpts ( opts )
255
276
const P = opts . Promise || Promise
256
- const checker = integrityStream ( Object . assign ( { } , opts , {
277
+ const checker = integrityStream ( opts . concat ( {
257
278
integrity : sri
258
279
} ) )
259
280
return new P ( ( resolve , reject ) => {
@@ -269,18 +290,15 @@ function checkStream (stream, sri, opts) {
269
290
270
291
module . exports . integrityStream = integrityStream
271
292
function integrityStream ( opts ) {
272
- opts = opts || { }
293
+ opts = SsriOpts ( opts )
273
294
// For verification
274
295
const sri = opts . integrity && parse ( opts . integrity , opts )
275
296
const goodSri = sri && Object . keys ( sri ) . length
276
297
const algorithm = goodSri && sri . pickAlgorithm ( opts )
277
298
const digests = goodSri && sri [ algorithm ]
278
299
// Calculating stream
279
300
const algorithms = Array . from (
280
- new Set (
281
- ( opts . algorithms || [ 'sha512' ] )
282
- . concat ( algorithm ? [ algorithm ] : [ ] )
283
- )
301
+ new Set ( opts . algorithms . concat ( algorithm ? [ algorithm ] : [ ] ) )
284
302
)
285
303
const hashes = algorithms . map ( crypto . createHash )
286
304
let streamSize = 0
@@ -325,9 +343,9 @@ function integrityStream (opts) {
325
343
326
344
module . exports . create = createIntegrity
327
345
function createIntegrity ( opts ) {
328
- opts = opts || { }
329
- const algorithms = opts . algorithms || [ 'sha512' ]
330
- const optString = opts . options && opts . options . length
346
+ opts = SsriOpts ( opts )
347
+ const algorithms = opts . algorithms
348
+ const optString = opts . options . length
331
349
? `?${ opts . options . join ( '?' ) } `
332
350
: ''
333
351
0 commit comments