Skip to content

Commit ae6f554

Browse files
authored
fix: add support for integrity option to Fetch (#1596)
* Test case for fetch() integrity option. * Implement matchRequestIntegrity * Add test to cover encoded body * Speed up integrity test completion * Fix trailing spaces
1 parent deed628 commit ae6f554

File tree

3 files changed

+77
-26
lines changed

3 files changed

+77
-26
lines changed

lib/fetch/util.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { performance } = require('perf_hooks')
55
const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
66
const assert = require('assert')
77
const { isUint8Array } = require('util/types')
8+
const { createHash } = require('crypto')
89

910
let File
1011

@@ -341,7 +342,8 @@ function determineRequestsReferrer (request) {
341342
}
342343

343344
function matchRequestIntegrity (request, bytes) {
344-
return false
345+
const [algo, expectedHashValue] = request.integrity.split('-', 2)
346+
return createHash(algo).update(bytes).digest('hex') === expectedHashValue
345347
}
346348

347349
// https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request

test/fetch/client-fetch.js

-25
Original file line numberDiff line numberDiff line change
@@ -536,28 +536,3 @@ test('Receiving non-Latin1 headers', async (t) => {
536536
t.same(lengths, [30, 34, 94, 104, 90])
537537
t.end()
538538
})
539-
540-
// https://github.com/nodejs/undici/issues/1594
541-
// TODO(@KhafraDev): this test fails because of an integrity-mismatch check
542-
// that hasn't been implemented when this comment was written. Enable this
543-
// check once a resource's integrity is checked.
544-
// test('with RequestInit.integrity set', async (t) => {
545-
// const body = 'Hello world'
546-
// const hash = require('crypto').createHash('sha256').update(body).digest('hex')
547-
//
548-
// const server = createServer((req, res) => {
549-
// res.write(body)
550-
// res.end()
551-
// }).listen(0)
552-
//
553-
// t.teardown(server.close.bind(server))
554-
// await once(server, 'listening')
555-
//
556-
// const response = await fetch(`http://localhost:${server.address().port}`, {
557-
// integrity: `sha256-${hash}`
558-
// })
559-
//
560-
// const ab = await response.arrayBuffer()
561-
//
562-
// t.same(new Uint8Array(ab), new TextEncoder().encode(body))
563-
// })

test/fetch/integrity.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
'use strict'
2+
3+
const { test } = require('tap')
4+
const { createServer } = require('http')
5+
const { createHash } = require('crypto')
6+
const { gzipSync } = require('zlib')
7+
const { fetch, setGlobalDispatcher, Agent } = require('../..')
8+
9+
setGlobalDispatcher(new Agent({
10+
keepAliveTimeout: 1,
11+
keepAliveMaxTimeout: 1
12+
}))
13+
14+
test('request with correct integrity checksum', (t) => {
15+
const body = 'Hello world!'
16+
const hash = createHash('sha256').update(body).digest('hex')
17+
18+
const server = createServer((req, res) => {
19+
res.end(body)
20+
})
21+
22+
t.teardown(server.close.bind(server))
23+
24+
server.listen(0, async () => {
25+
const response = await fetch(`http://localhost:${server.address().port}`, {
26+
integrity: `sha256-${hash}`
27+
})
28+
t.strictSame(body, await response.text())
29+
t.end()
30+
})
31+
})
32+
33+
test('request with wrong integrity checksum', (t) => {
34+
const body = 'Hello world!'
35+
const hash = 'c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51b'
36+
37+
const server = createServer((req, res) => {
38+
res.end(body)
39+
})
40+
41+
t.teardown(server.close.bind(server))
42+
43+
server.listen(0, () => {
44+
fetch(`http://localhost:${server.address().port}`, {
45+
integrity: `sha256-${hash}`
46+
}).then(response => {
47+
t.fail('fetch did not fail')
48+
}).catch((err) => {
49+
t.equal(err.cause.message, 'integrity mismatch')
50+
}).finally(() => {
51+
t.end()
52+
})
53+
})
54+
})
55+
56+
test('request with integrity checksum on encoded body', (t) => {
57+
const body = 'Hello world!'
58+
const hash = createHash('sha256').update(body).digest('hex')
59+
60+
const server = createServer((req, res) => {
61+
res.setHeader('content-encoding', 'gzip')
62+
res.end(gzipSync(body))
63+
})
64+
65+
t.teardown(server.close.bind(server))
66+
67+
server.listen(0, async () => {
68+
const response = await fetch(`http://localhost:${server.address().port}`, {
69+
integrity: `sha256-${hash}`
70+
})
71+
t.strictSame(body, await response.text())
72+
t.end()
73+
})
74+
})

0 commit comments

Comments
 (0)