Reverted the update
Some checks failed
Auto Maintenance Cycle / pre-commit Autoupdate (push) Failing after 31s
Some checks failed
Auto Maintenance Cycle / pre-commit Autoupdate (push) Failing after 31s
This commit is contained in:
242
node_modules/undici/lib/fetch/util.js
generated
vendored
242
node_modules/undici/lib/fetch/util.js
generated
vendored
@ -7,18 +7,14 @@ const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
|
||||
const assert = require('assert')
|
||||
const { isUint8Array } = require('util/types')
|
||||
|
||||
let supportedHashes = []
|
||||
|
||||
// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable
|
||||
/** @type {import('crypto')|undefined} */
|
||||
let crypto
|
||||
|
||||
try {
|
||||
crypto = require('crypto')
|
||||
const possibleRelevantHashes = ['sha256', 'sha384', 'sha512']
|
||||
supportedHashes = crypto.getHashes().filter((hash) => possibleRelevantHashes.includes(hash))
|
||||
/* c8 ignore next 3 */
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
function responseURL (response) {
|
||||
@ -107,57 +103,52 @@ function isValidReasonPhrase (statusText) {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://tools.ietf.org/html/rfc7230#section-3.2.6
|
||||
* @param {number} c
|
||||
*/
|
||||
function isTokenCharCode (c) {
|
||||
switch (c) {
|
||||
case 0x22:
|
||||
case 0x28:
|
||||
case 0x29:
|
||||
case 0x2c:
|
||||
case 0x2f:
|
||||
case 0x3a:
|
||||
case 0x3b:
|
||||
case 0x3c:
|
||||
case 0x3d:
|
||||
case 0x3e:
|
||||
case 0x3f:
|
||||
case 0x40:
|
||||
case 0x5b:
|
||||
case 0x5c:
|
||||
case 0x5d:
|
||||
case 0x7b:
|
||||
case 0x7d:
|
||||
// DQUOTE and "(),/:;<=>?@[\]{}"
|
||||
return false
|
||||
default:
|
||||
// VCHAR %x21-7E
|
||||
return c >= 0x21 && c <= 0x7e
|
||||
}
|
||||
function isTokenChar (c) {
|
||||
return !(
|
||||
c >= 0x7f ||
|
||||
c <= 0x20 ||
|
||||
c === '(' ||
|
||||
c === ')' ||
|
||||
c === '<' ||
|
||||
c === '>' ||
|
||||
c === '@' ||
|
||||
c === ',' ||
|
||||
c === ';' ||
|
||||
c === ':' ||
|
||||
c === '\\' ||
|
||||
c === '"' ||
|
||||
c === '/' ||
|
||||
c === '[' ||
|
||||
c === ']' ||
|
||||
c === '?' ||
|
||||
c === '=' ||
|
||||
c === '{' ||
|
||||
c === '}'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} characters
|
||||
*/
|
||||
// See RFC 7230, Section 3.2.6.
|
||||
// https://github.com/chromium/chromium/blob/d7da0240cae77824d1eda25745c4022757499131/third_party/blink/renderer/platform/network/http_parsers.cc#L321
|
||||
function isValidHTTPToken (characters) {
|
||||
if (characters.length === 0) {
|
||||
if (!characters || typeof characters !== 'string') {
|
||||
return false
|
||||
}
|
||||
for (let i = 0; i < characters.length; ++i) {
|
||||
if (!isTokenCharCode(characters.charCodeAt(i))) {
|
||||
const c = characters.charCodeAt(i)
|
||||
if (c > 0x7f || !isTokenChar(c)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://fetch.spec.whatwg.org/#header-name
|
||||
* @param {string} potentialValue
|
||||
*/
|
||||
// https://fetch.spec.whatwg.org/#header-name
|
||||
// https://github.com/chromium/chromium/blob/b3d37e6f94f87d59e44662d6078f6a12de845d17/net/http/http_util.cc#L342
|
||||
function isValidHeaderName (potentialValue) {
|
||||
if (potentialValue.length === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
return isValidHTTPToken(potentialValue)
|
||||
}
|
||||
|
||||
@ -546,56 +537,66 @@ function bytesMatch (bytes, metadataList) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 3. If response is not eligible for integrity validation, return false.
|
||||
// TODO
|
||||
|
||||
// 4. If parsedMetadata is the empty set, return true.
|
||||
// 3. If parsedMetadata is the empty set, return true.
|
||||
if (parsedMetadata.length === 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 5. Let metadata be the result of getting the strongest
|
||||
// 4. Let metadata be the result of getting the strongest
|
||||
// metadata from parsedMetadata.
|
||||
const strongest = getStrongestMetadata(parsedMetadata)
|
||||
const metadata = filterMetadataListByAlgorithm(parsedMetadata, strongest)
|
||||
const list = parsedMetadata.sort((c, d) => d.algo.localeCompare(c.algo))
|
||||
// get the strongest algorithm
|
||||
const strongest = list[0].algo
|
||||
// get all entries that use the strongest algorithm; ignore weaker
|
||||
const metadata = list.filter((item) => item.algo === strongest)
|
||||
|
||||
// 6. For each item in metadata:
|
||||
// 5. For each item in metadata:
|
||||
for (const item of metadata) {
|
||||
// 1. Let algorithm be the alg component of item.
|
||||
const algorithm = item.algo
|
||||
|
||||
// 2. Let expectedValue be the val component of item.
|
||||
const expectedValue = item.hash
|
||||
let expectedValue = item.hash
|
||||
|
||||
// See https://github.com/web-platform-tests/wpt/commit/e4c5cc7a5e48093220528dfdd1c4012dc3837a0e
|
||||
// "be liberal with padding". This is annoying, and it's not even in the spec.
|
||||
|
||||
if (expectedValue.endsWith('==')) {
|
||||
expectedValue = expectedValue.slice(0, -2)
|
||||
}
|
||||
|
||||
// 3. Let actualValue be the result of applying algorithm to bytes.
|
||||
let actualValue = crypto.createHash(algorithm).update(bytes).digest('base64')
|
||||
|
||||
if (actualValue[actualValue.length - 1] === '=') {
|
||||
if (actualValue[actualValue.length - 2] === '=') {
|
||||
actualValue = actualValue.slice(0, -2)
|
||||
} else {
|
||||
actualValue = actualValue.slice(0, -1)
|
||||
}
|
||||
if (actualValue.endsWith('==')) {
|
||||
actualValue = actualValue.slice(0, -2)
|
||||
}
|
||||
|
||||
// 4. If actualValue is a case-sensitive match for expectedValue,
|
||||
// return true.
|
||||
if (compareBase64Mixed(actualValue, expectedValue)) {
|
||||
if (actualValue === expectedValue) {
|
||||
return true
|
||||
}
|
||||
|
||||
let actualBase64URL = crypto.createHash(algorithm).update(bytes).digest('base64url')
|
||||
|
||||
if (actualBase64URL.endsWith('==')) {
|
||||
actualBase64URL = actualBase64URL.slice(0, -2)
|
||||
}
|
||||
|
||||
if (actualBase64URL === expectedValue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Return false.
|
||||
// 6. Return false.
|
||||
return false
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options
|
||||
// https://www.w3.org/TR/CSP2/#source-list-syntax
|
||||
// https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
|
||||
const parseHashWithOptions = /(?<algo>sha256|sha384|sha512)-((?<hash>[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i
|
||||
const parseHashWithOptions = /((?<algo>sha256|sha384|sha512)-(?<hash>[A-z0-9+/]{1}.*={0,2}))( +[\x21-\x7e]?)?/i
|
||||
|
||||
/**
|
||||
* @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
|
||||
@ -609,6 +610,8 @@ function parseMetadata (metadata) {
|
||||
// 2. Let empty be equal to true.
|
||||
let empty = true
|
||||
|
||||
const supportedHashes = crypto.getHashes()
|
||||
|
||||
// 3. For each token returned by splitting metadata on spaces:
|
||||
for (const token of metadata.split(' ')) {
|
||||
// 1. Set empty to false.
|
||||
@ -618,11 +621,7 @@ function parseMetadata (metadata) {
|
||||
const parsedToken = parseHashWithOptions.exec(token)
|
||||
|
||||
// 3. If token does not parse, continue to the next token.
|
||||
if (
|
||||
parsedToken === null ||
|
||||
parsedToken.groups === undefined ||
|
||||
parsedToken.groups.algo === undefined
|
||||
) {
|
||||
if (parsedToken === null || parsedToken.groups === undefined) {
|
||||
// Note: Chromium blocks the request at this point, but Firefox
|
||||
// gives a warning that an invalid integrity was given. The
|
||||
// correct behavior is to ignore these, and subsequently not
|
||||
@ -631,11 +630,11 @@ function parseMetadata (metadata) {
|
||||
}
|
||||
|
||||
// 4. Let algorithm be the hash-algo component of token.
|
||||
const algorithm = parsedToken.groups.algo.toLowerCase()
|
||||
const algorithm = parsedToken.groups.algo
|
||||
|
||||
// 5. If algorithm is a hash function recognized by the user
|
||||
// agent, add the parsed token to result.
|
||||
if (supportedHashes.includes(algorithm)) {
|
||||
if (supportedHashes.includes(algorithm.toLowerCase())) {
|
||||
result.push(parsedToken.groups)
|
||||
}
|
||||
}
|
||||
@ -648,82 +647,6 @@ function parseMetadata (metadata) {
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ algo: 'sha256' | 'sha384' | 'sha512' }[]} metadataList
|
||||
*/
|
||||
function getStrongestMetadata (metadataList) {
|
||||
// Let algorithm be the algo component of the first item in metadataList.
|
||||
// Can be sha256
|
||||
let algorithm = metadataList[0].algo
|
||||
// If the algorithm is sha512, then it is the strongest
|
||||
// and we can return immediately
|
||||
if (algorithm[3] === '5') {
|
||||
return algorithm
|
||||
}
|
||||
|
||||
for (let i = 1; i < metadataList.length; ++i) {
|
||||
const metadata = metadataList[i]
|
||||
// If the algorithm is sha512, then it is the strongest
|
||||
// and we can break the loop immediately
|
||||
if (metadata.algo[3] === '5') {
|
||||
algorithm = 'sha512'
|
||||
break
|
||||
// If the algorithm is sha384, then a potential sha256 or sha384 is ignored
|
||||
} else if (algorithm[3] === '3') {
|
||||
continue
|
||||
// algorithm is sha256, check if algorithm is sha384 and if so, set it as
|
||||
// the strongest
|
||||
} else if (metadata.algo[3] === '3') {
|
||||
algorithm = 'sha384'
|
||||
}
|
||||
}
|
||||
return algorithm
|
||||
}
|
||||
|
||||
function filterMetadataListByAlgorithm (metadataList, algorithm) {
|
||||
if (metadataList.length === 1) {
|
||||
return metadataList
|
||||
}
|
||||
|
||||
let pos = 0
|
||||
for (let i = 0; i < metadataList.length; ++i) {
|
||||
if (metadataList[i].algo === algorithm) {
|
||||
metadataList[pos++] = metadataList[i]
|
||||
}
|
||||
}
|
||||
|
||||
metadataList.length = pos
|
||||
|
||||
return metadataList
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two base64 strings, allowing for base64url
|
||||
* in the second string.
|
||||
*
|
||||
* @param {string} actualValue always base64
|
||||
* @param {string} expectedValue base64 or base64url
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function compareBase64Mixed (actualValue, expectedValue) {
|
||||
if (actualValue.length !== expectedValue.length) {
|
||||
return false
|
||||
}
|
||||
for (let i = 0; i < actualValue.length; ++i) {
|
||||
if (actualValue[i] !== expectedValue[i]) {
|
||||
if (
|
||||
(actualValue[i] === '+' && expectedValue[i] === '-') ||
|
||||
(actualValue[i] === '/' && expectedValue[i] === '_')
|
||||
) {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request
|
||||
function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) {
|
||||
// TODO
|
||||
@ -770,30 +693,11 @@ function isCancelled (fetchParams) {
|
||||
fetchParams.controller.state === 'terminated'
|
||||
}
|
||||
|
||||
const normalizeMethodRecord = {
|
||||
delete: 'DELETE',
|
||||
DELETE: 'DELETE',
|
||||
get: 'GET',
|
||||
GET: 'GET',
|
||||
head: 'HEAD',
|
||||
HEAD: 'HEAD',
|
||||
options: 'OPTIONS',
|
||||
OPTIONS: 'OPTIONS',
|
||||
post: 'POST',
|
||||
POST: 'POST',
|
||||
put: 'PUT',
|
||||
PUT: 'PUT'
|
||||
}
|
||||
|
||||
// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`.
|
||||
Object.setPrototypeOf(normalizeMethodRecord, null)
|
||||
|
||||
/**
|
||||
* @see https://fetch.spec.whatwg.org/#concept-method-normalize
|
||||
* @param {string} method
|
||||
*/
|
||||
// https://fetch.spec.whatwg.org/#concept-method-normalize
|
||||
function normalizeMethod (method) {
|
||||
return normalizeMethodRecord[method.toLowerCase()] ?? method
|
||||
return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method)
|
||||
? method.toUpperCase()
|
||||
: method
|
||||
}
|
||||
|
||||
// https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string
|
||||
@ -1138,7 +1042,5 @@ module.exports = {
|
||||
urlIsLocal,
|
||||
urlHasHttpsScheme,
|
||||
urlIsHttpHttpsScheme,
|
||||
readAllBytes,
|
||||
normalizeMethodRecord,
|
||||
parseMetadata
|
||||
readAllBytes
|
||||
}
|
||||
|
Reference in New Issue
Block a user