Skip to content

Commit d97613f

Browse files
authored
fix: parseHashWithOptions regex (#2561)
1 parent 35b049b commit d97613f

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

lib/fetch/util.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ function bytesMatch (bytes, metadataList) {
584584
// https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options
585585
// https://www.w3.org/TR/CSP2/#source-list-syntax
586586
// https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
587-
const parseHashWithOptions = /((?<algo>sha256|sha384|sha512)-(?<hash>[A-z0-9+/]{1}.*={0,2}))( +[\x21-\x7e]?)?/i
587+
const parseHashWithOptions = /(?<algo>sha256|sha384|sha512)-(?<hash>[A-Za-z0-9+/]+={0,2}(?=\s|$))( +[!-~]*)?/i
588588

589589
/**
590590
* @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
@@ -1213,5 +1213,6 @@ module.exports = {
12131213
readAllBytes,
12141214
normalizeMethodRecord,
12151215
simpleRangeHeaderValue,
1216-
buildContentRange
1216+
buildContentRange,
1217+
parseMetadata
12171218
}

test/fetch/util.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { test } = t
55

66
const util = require('../../lib/fetch/util')
77
const { HeadersList } = require('../../lib/fetch/headers')
8+
const { createHash } = require('crypto')
89

910
test('responseURL', (t) => {
1011
t.plan(2)
@@ -279,3 +280,78 @@ test('setRequestReferrerPolicyOnRedirect', nested => {
279280
t.equal(request.referrerPolicy, initial)
280281
})
281282
})
283+
284+
test('parseMetadata', t => {
285+
t.test('should parse valid metadata with option', t => {
286+
const body = 'Hello world!'
287+
const hash256 = createHash('sha256').update(body).digest('base64')
288+
const hash384 = createHash('sha384').update(body).digest('base64')
289+
const hash512 = createHash('sha512').update(body).digest('base64')
290+
291+
const validMetadata = `sha256-${hash256} !@ sha384-${hash384} !@ sha512-${hash512} !@`
292+
const result = util.parseMetadata(validMetadata)
293+
294+
t.same(result, [
295+
{ algo: 'sha256', hash: hash256 },
296+
{ algo: 'sha384', hash: hash384 },
297+
{ algo: 'sha512', hash: hash512 }
298+
])
299+
300+
t.end()
301+
})
302+
303+
t.test('should parse valid metadata with non ASCII chars option', t => {
304+
const body = 'Hello world!'
305+
const hash256 = createHash('sha256').update(body).digest('base64')
306+
const hash384 = createHash('sha384').update(body).digest('base64')
307+
const hash512 = createHash('sha512').update(body).digest('base64')
308+
309+
const validMetadata = `sha256-${hash256} !© sha384-${hash384} !€ sha512-${hash512} !µ`
310+
const result = util.parseMetadata(validMetadata)
311+
312+
t.same(result, [
313+
{ algo: 'sha256', hash: hash256 },
314+
{ algo: 'sha384', hash: hash384 },
315+
{ algo: 'sha512', hash: hash512 }
316+
])
317+
318+
t.end()
319+
})
320+
321+
t.test('should parse valid metadata without option', t => {
322+
const body = 'Hello world!'
323+
const hash256 = createHash('sha256').update(body).digest('base64')
324+
const hash384 = createHash('sha384').update(body).digest('base64')
325+
const hash512 = createHash('sha512').update(body).digest('base64')
326+
327+
const validMetadata = `sha256-${hash256} sha384-${hash384} sha512-${hash512}`
328+
const result = util.parseMetadata(validMetadata)
329+
330+
t.same(result, [
331+
{ algo: 'sha256', hash: hash256 },
332+
{ algo: 'sha384', hash: hash384 },
333+
{ algo: 'sha512', hash: hash512 }
334+
])
335+
336+
t.end()
337+
})
338+
339+
t.test('should ignore invalid metadata with invalid base64 chars', t => {
340+
const body = 'Hello world!'
341+
const hash256 = createHash('sha256').update(body).digest('base64')
342+
const invalidHash384 = 'zifp5hE1Xl5LQQqQz[]Bq/iaq9Wb6jVb//T7EfTmbXD2aEP5c2ZdJr9YTDfcTE1ZH+'
343+
const hash512 = createHash('sha512').update(body).digest('base64')
344+
345+
const validMetadata = `sha256-${hash256} sha384-${invalidHash384} sha512-${hash512}`
346+
const result = util.parseMetadata(validMetadata)
347+
348+
t.same(result, [
349+
{ algo: 'sha256', hash: hash256 },
350+
{ algo: 'sha512', hash: hash512 }
351+
])
352+
353+
t.end()
354+
})
355+
356+
t.end()
357+
})

0 commit comments

Comments
 (0)