diff --git a/NOTICE-3RD-PARTY-CONTENT.md b/NOTICE-3RD-PARTY-CONTENT.md
index 0c67264..9e90f16 100644
--- a/NOTICE-3RD-PARTY-CONTENT.md
+++ b/NOTICE-3RD-PARTY-CONTENT.md
@@ -3,29 +3,338 @@
## JavaScript
| Dependency | Version | License |
|:-----------|:-------:|--------:|
+|@aashutoshrathi/word-wrap|1.2.6|MIT|
|@actions/core|1.10.1|MIT|
-|@cucumber/cucumber|10.3.1|ISC
MIT|
+|@actions/http-client|2.2.0|MIT|
+|@babel/code-frame|7.23.5|MIT|
+|@babel/helper-validator-identifier|7.22.20|MIT|
+|@babel/highlight|7.23.4|MIT|
+|@colors/colors|1.5.0|MIT|
+|@cspotcode/source-map-support|0.8.1|MIT|
+|@cucumber/ci-environment|10.0.0|MIT|
+|@cucumber/cucumber|10.3.1|MIT|
+|@cucumber/cucumber-expressions|17.0.1|MIT|
+|@cucumber/gherkin|26.2.0|MIT|
+|@cucumber/gherkin|27.0.0|MIT|
+|@cucumber/gherkin-streams|5.0.1|MIT|
+|@cucumber/gherkin-utils|8.0.5|MIT|
+|@cucumber/html-formatter|21.2.0|MIT|
+|@cucumber/message-streams|4.0.1|MIT|
+|@cucumber/messages|21.0.1|MIT|
+|@cucumber/messages|22.0.0|MIT|
+|@cucumber/messages|24.0.1|MIT|
|@cucumber/pretty-formatter|1.0.0|MIT|
+|@cucumber/tag-expressions|6.1.0|MIT|
+|@eslint-community/eslint-utils|4.4.0|MIT|
+|@eslint-community/regexpp|4.10.0|MIT|
+|@eslint/eslintrc|2.1.4|MIT|
+|@eslint/js|8.56.0|MIT|
+|@fastify/busboy|2.1.0|MIT|
+|@humanwhocodes/config-array|0.11.14|Apache 2.0|
+|@humanwhocodes/module-importer|1.0.1|Apache 2.0|
+|@humanwhocodes/object-schema|2.0.2|New BSD|
+|@isaacs/cliui|8.0.2|ISC|
+|@jridgewell/resolve-uri|3.1.1|MIT|
+|@jridgewell/sourcemap-codec|1.4.15|MIT|
+|@jridgewell/trace-mapping|0.3.9|MIT|
+|@nodelib/fs.scandir|2.1.5|MIT|
+|@nodelib/fs.stat|2.0.5|MIT|
+|@nodelib/fs.walk|1.2.8|MIT|
+|@pkgjs/parseargs|0.11.0|MIT|
+|@teppeis/multimaps|3.0.0|MIT|
+|@tsconfig/node10|1.0.9|MIT|
+|@tsconfig/node12|1.0.11|MIT|
+|@tsconfig/node14|1.0.3|MIT|
+|@tsconfig/node16|1.0.4|MIT|
|@types/chai|4.3.11|MIT|
|@types/chai-string|1.4.5|MIT|
|@types/cucumber|7.0.0|MIT|
+|@types/json-schema|7.0.15|MIT|
+|@types/lodash|4.14.167|MIT|
|@types/node|18.19.14|MIT|
+|@types/normalize-package-data|2.4.4|MIT|
+|@types/semver|7.5.6|MIT|
+|@types/uuid|8.3.4|MIT|
+|@types/uuid|9.0.1|MIT|
+|@types/uuid|9.0.7|MIT|
|@types/xml2js|0.4.14|MIT|
|@typescript-eslint/eslint-plugin|5.62.0|MIT|
-|@typescript-eslint/parser|5.62.0|unknown|
-|@vercel/ncc|0.34.0|ISC
MIT|
+|@typescript-eslint/parser|5.62.0|Simplified BSD|
+|@typescript-eslint/scope-manager|5.62.0|MIT|
+|@typescript-eslint/type-utils|5.62.0|MIT|
+|@typescript-eslint/types|5.62.0|MIT|
+|@typescript-eslint/typescript-estree|5.62.0|Simplified BSD|
+|@typescript-eslint/utils|5.62.0|MIT|
+|@typescript-eslint/visitor-keys|5.62.0|MIT|
+|@ungap/structured-clone|1.2.0|ISC|
+|@vercel/ncc|0.34.0|MIT|
+|acorn|8.11.3|MIT|
+|acorn-jsx|5.3.2|MIT|
+|acorn-walk|8.3.2|MIT|
+|ajv|6.12.6|MIT|
+|ansi-regex|4.1.1|MIT|
+|ansi-regex|5.0.1|MIT|
+|ansi-regex|6.0.1|MIT|
+|ansi-styles|3.2.1|MIT|
+|ansi-styles|4.3.0|MIT|
+|ansi-styles|5.2.0|MIT|
+|ansi-styles|6.2.1|MIT|
+|any-promise|1.3.0|MIT|
+|arg|4.1.3|MIT|
+|argparse|2.0.1|Python-2.0|
+|array-union|2.1.0|MIT|
+|assertion-error|1.1.0|MIT|
+|assertion-error-formatter|3.0.0|MIT|
+|balanced-match|1.0.2|MIT|
+|brace-expansion|1.1.11|MIT|
+|brace-expansion|2.0.1|MIT|
+|braces|3.0.3|MIT|
+|buffer-from|1.1.2|MIT|
+|callsites|3.1.0|MIT|
+|capital-case|1.0.4|MIT|
|chai|4.4.1|MIT|
|chai-string|1.5.0|MIT|
-|cucumber-console-formatter|1.0.0|MIT|
-|cucumber-tsflow|4.4.1|unknown|
+|chalk|2.4.2|MIT|
+|chalk|4.1.2|MIT|
+|check-error|1.0.3|MIT|
+|class-transformer|0.5.1|MIT|
+|cli-table3|0.6.3|MIT|
+|color-convert|1.9.3|MIT|
+|color-convert|2.0.1|MIT|
+|color-name|1.1.3|MIT|
+|color-name|1.1.4|MIT|
+|commander|10.0.1|MIT|
+|commander|9.1.0|MIT|
+|concat-map|0.0.1|MIT|
+|create-require|1.1.1|MIT|
+|cross-spawn|7.0.3|MIT|
+|cucumber-console-formatter|1.0.0|ISC|
+|cucumber-tsflow|4.4.1|MIT|
+|date-format|4.0.14|MIT|
+|debug|4.3.4|MIT|
+|deep-eql|4.1.3|MIT|
+|deep-is|0.1.4|MIT|
+|diff|4.0.2|New BSD|
+|dir-glob|3.0.1|MIT|
+|doctrine|3.0.0|Apache 2.0|
+|eastasianwidth|0.2.0|MIT|
+|emoji-regex|8.0.0|MIT|
+|emoji-regex|9.2.2|MIT|
+|error-ex|1.3.2|MIT|
+|error-stack-parser|2.1.4|MIT|
+|escape-string-regexp|1.0.5|MIT|
+|escape-string-regexp|4.0.0|MIT|
|eslint|8.56.0|MIT|
-|fs|0.0.1-security|unknown|
-|guid-typescript|1.0.9|unknown|
+|eslint-scope|5.1.1|Simplified BSD|
+|eslint-scope|7.2.2|Simplified BSD|
+|eslint-visitor-keys|3.4.3|Apache 2.0|
+|espree|9.6.1|Simplified BSD|
+|esquery|1.5.0|New BSD|
+|esrecurse|4.3.0|Simplified BSD|
+|estraverse|4.3.0|Simplified BSD|
+|estraverse|5.3.0|Simplified BSD|
+|esutils|2.0.3|Simplified BSD|
+|fast-deep-equal|3.1.3|MIT|
+|fast-glob|3.3.2|MIT|
+|fast-json-stable-stringify|2.1.0|MIT|
+|fast-levenshtein|2.0.6|MIT|
+|fastq|1.17.1|ISC|
+|figures|3.2.0|MIT|
+|file-entry-cache|6.0.1|MIT|
+|fill-range|7.1.1|MIT|
+|find-up|4.1.0|MIT|
+|find-up|5.0.0|MIT|
+|flat-cache|3.2.0|MIT|
+|flatted|3.2.9|ISC|
+|foreground-child|3.1.1|ISC|
+|fs|0.0.1-security|ISC|
+|fs-extra|8.1.0|MIT|
+|fs.realpath|1.0.0|ISC|
+|function-bind|1.1.2|MIT|
+|get-func-name|2.0.2|MIT|
+|glob|10.3.10|ISC|
+|glob|7.2.3|ISC|
+|glob-parent|5.1.2|ISC|
+|glob-parent|6.0.2|ISC|
+|global-dirs|3.0.1|MIT|
+|globals|13.24.0|MIT|
+|globby|11.1.0|MIT|
+|graceful-fs|4.2.11|ISC|
+|graphemer|1.4.0|MIT|
+|guid-typescript|1.0.9|ISC|
|handlebars|4.7.7|MIT|
+|has-ansi|4.0.1|MIT|
+|has-flag|3.0.0|MIT|
+|has-flag|4.0.0|MIT|
+|hasown|2.0.0|MIT|
+|hosted-git-info|2.8.9|ISC|
+|ignore|5.3.1|MIT|
+|import-fresh|3.3.0|MIT|
+|imurmurhash|0.1.4|MIT|
+|indent-string|4.0.0|MIT|
+|inflight|1.0.6|ISC|
+|inherits|2.0.4|ISC|
+|ini|2.0.0|ISC|
+|is-arrayish|0.2.1|MIT|
+|is-core-module|2.13.1|MIT|
+|is-extglob|2.1.1|MIT|
+|is-fullwidth-code-point|3.0.0|MIT|
+|is-glob|4.0.3|MIT|
+|is-installed-globally|0.4.0|MIT|
+|is-number|7.0.0|MIT|
+|is-path-inside|3.0.3|MIT|
+|is-stream|2.0.1|MIT|
+|isexe|2.0.0|ISC|
+|jackspeak|2.3.6|BlueOak-1.0.0|
+|js-tokens|4.0.0|MIT|
+|js-yaml|4.1.0|MIT|
+|json-buffer|3.0.1|MIT|
+|json-parse-even-better-errors|2.3.1|MIT|
+|json-schema-traverse|0.4.1|MIT|
+|json-stable-stringify-without-jsonify|1.0.1|MIT|
+|jsonfile|4.0.0|MIT|
+|keyv|4.5.4|MIT|
+|knuth-shuffle-seeded|1.0.6|Apache 2.0|
+|levn|0.4.1|MIT|
+|lines-and-columns|1.2.4|MIT|
+|locate-path|5.0.0|MIT|
+|locate-path|6.0.0|MIT|
+|lodash.merge|4.6.2|MIT|
+|lodash.mergewith|4.6.2|MIT|
+|log4js|6.9.1|Apache 2.0|
+|loupe|2.3.7|MIT|
+|lower-case|2.0.2|MIT|
+|lru-cache|10.2.0|ISC|
+|lru-cache|6.0.0|ISC|
+|luxon|3.2.1|MIT|
+|make-error|1.3.6|ISC|
+|merge2|1.4.1|MIT|
+|micromatch|4.0.5|MIT|
+|minimatch|3.1.2|ISC|
+|minimatch|9.0.3|ISC|
+|minimist|1.2.8|MIT|
+|minipass|7.0.4|ISC|
+|mkdirp|2.1.6|MIT|
+|ms|2.1.2|MIT|
+|mz|2.7.0|MIT|
+|natural-compare|1.4.0|MIT|
+|natural-compare-lite|1.4.0|MIT|
+|neo-async|2.6.2|MIT|
+|no-case|3.0.4|MIT|
+|normalize-package-data|2.5.0|Simplified BSD|
+|object-assign|4.1.1|MIT|
+|once|1.4.0|ISC|
+|optionator|0.9.3|MIT|
+|p-limit|2.3.0|MIT|
+|p-limit|3.1.0|MIT|
+|p-locate|4.1.0|MIT|
+|p-locate|5.0.0|MIT|
+|p-try|2.2.0|MIT|
+|pad-right|0.2.2|MIT|
+|parent-module|1.0.1|MIT|
+|parse-json|5.2.0|MIT|
+|path-exists|4.0.0|MIT|
+|path-is-absolute|1.0.1|MIT|
+|path-key|3.1.1|MIT|
+|path-parse|1.0.7|MIT|
+|path-scurry|1.10.1|BlueOak-1.0.0|
+|path-type|4.0.0|MIT|
+|pathval|1.1.1|MIT|
+|picomatch|2.3.1|MIT|
+|prelude-ls|1.2.1|MIT|
+|progress|2.0.3|MIT|
+|property-expr|2.0.6|MIT|
+|punycode|2.3.1|MIT|
+|queue-microtask|1.2.3|MIT|
+|read-pkg|5.2.0|MIT|
+|read-pkg-up|7.0.1|MIT|
+|reflect-metadata|0.1.13|Apache 2.0|
+|reflect-metadata|0.2.1|Apache 2.0|
+|regexp-match-indices|1.0.2|Apache 2.0|
+|regexp-tree|0.1.27|MIT|
|renderer|1.0.0|ISC|
+|repeat-string|1.6.1|MIT|
+|resolve|1.22.8|MIT|
+|resolve-from|4.0.0|MIT|
+|resolve-from|5.0.0|MIT|
+|resolve-pkg|2.0.0|MIT|
+|reusify|1.0.4|MIT|
+|rfdc|1.3.1|MIT|
+|rimraf|3.0.2|ISC|
+|run-parallel|1.2.0|MIT|
+|sax|1.3.0|ISC|
+|seed-random|2.2.0|MIT|
+|semver|5.7.2|ISC|
+|semver|7.5.3|ISC|
+|shebang-command|2.0.0|MIT|
+|shebang-regex|3.0.0|MIT|
+|signal-exit|4.1.0|ISC|
+|slash|3.0.0|MIT|
+|source-map|0.6.1|New BSD|
+|source-map-support|0.5.21|MIT|
+|spdx-correct|3.2.0|Apache 2.0|
+|spdx-exceptions|2.4.0|CC-BY-3.0|
+|spdx-expression-parse|3.0.1|MIT|
+|spdx-license-ids|3.0.16|CC0 1.0 Universal|
+|stackframe|1.3.4|MIT|
+|streamroller|3.1.5|MIT|
+|string-argv|0.3.1|MIT|
+|string-width|4.2.3|MIT|
+|string-width|5.1.2|MIT|
+|strip-ansi|6.0.1|MIT|
+|strip-ansi|7.1.0|MIT|
+|strip-json-comments|3.1.1|MIT|
+|supports-color|5.5.0|MIT|
+|supports-color|7.2.0|MIT|
+|supports-color|8.1.1|MIT|
+|supports-preserve-symlinks-flag|1.0.0|MIT|
+|text-table|0.2.0|MIT|
+|thenify|3.3.1|MIT|
+|thenify-all|1.6.0|MIT|
+|tiny-case|1.0.3|MIT|
+|tmp|0.2.1|MIT|
+|to-regex-range|5.0.1|MIT|
+|toposort|2.0.2|MIT|
+|ts-dedent|2.2.0|MIT|
|ts-node|10.9.2|MIT|
+|tslib|1.14.1|BSD Zero Clause License|
+|tslib|2.6.2|BSD Zero Clause License|
+|tsutils|3.21.0|MIT|
+|tunnel|0.0.6|MIT|
+|type-check|0.4.0|MIT|
+|type-detect|4.0.8|MIT|
+|type-fest|0.20.2|(MIT OR CC0-1.0)|
+|type-fest|0.6.0|(MIT OR CC0-1.0)|
+|type-fest|0.8.1|(MIT OR CC0-1.0)|
+|type-fest|2.19.0|(MIT OR CC0-1.0)|
+|type-fest|4.10.2|(MIT OR CC0-1.0)|
|typescript|4.9.5|Apache 2.0|
+|uglify-js|3.17.4|Simplified BSD|
+|underscore|1.13.6|MIT|
+|undici|5.28.4|MIT|
+|undici-types|5.26.5|MIT|
+|universalify|0.1.2|MIT|
+|upper-case-first|2.0.2|MIT|
+|uri-js|4.4.1|Simplified BSD|
+|util-arity|1.1.0|MIT|
+|uuid|8.3.2|MIT|
+|uuid|9.0.0|MIT|
+|uuid|9.0.1|MIT|
+|v8-compile-cache-lib|3.0.1|MIT|
+|validate-npm-package-license|3.0.4|Apache 2.0|
+|which|2.0.2|ISC|
+|wordwrap|1.0.0|MIT|
+|wrap-ansi|7.0.0|MIT|
+|wrap-ansi|8.1.0|MIT|
+|wrappy|1.0.2|ISC|
|xml2js|0.6.2|MIT|
+|xmlbuilder|11.0.1|MIT|
+|xmlbuilder|15.1.1|MIT|
+|yallist|4.0.0|ISC|
+|yaml|2.3.4|ISC|
+|yn|3.1.1|MIT|
+|yocto-queue|0.1.0|MIT|
+|yup|1.2.0|MIT|
## Workflows
| Dependency | Version | License |
|:-----------|:-------:|--------:|
diff --git a/dist/documentation/render/index.js b/dist/documentation/render/index.js
index ed12dba..185d942 100644
--- a/dist/documentation/render/index.js
+++ b/dist/documentation/render/index.js
@@ -18465,6 +18465,132 @@ function onConnectTimeout (socket) {
module.exports = buildConnector
+/***/ }),
+
+/***/ 4462:
+/***/ ((module) => {
+
+"use strict";
+
+
+/** @type {Record} */
+const headerNameLowerCasedRecord = {}
+
+// https://developer.mozilla.org/docs/Web/HTTP/Headers
+const wellknownHeaderNames = [
+ 'Accept',
+ 'Accept-Encoding',
+ 'Accept-Language',
+ 'Accept-Ranges',
+ 'Access-Control-Allow-Credentials',
+ 'Access-Control-Allow-Headers',
+ 'Access-Control-Allow-Methods',
+ 'Access-Control-Allow-Origin',
+ 'Access-Control-Expose-Headers',
+ 'Access-Control-Max-Age',
+ 'Access-Control-Request-Headers',
+ 'Access-Control-Request-Method',
+ 'Age',
+ 'Allow',
+ 'Alt-Svc',
+ 'Alt-Used',
+ 'Authorization',
+ 'Cache-Control',
+ 'Clear-Site-Data',
+ 'Connection',
+ 'Content-Disposition',
+ 'Content-Encoding',
+ 'Content-Language',
+ 'Content-Length',
+ 'Content-Location',
+ 'Content-Range',
+ 'Content-Security-Policy',
+ 'Content-Security-Policy-Report-Only',
+ 'Content-Type',
+ 'Cookie',
+ 'Cross-Origin-Embedder-Policy',
+ 'Cross-Origin-Opener-Policy',
+ 'Cross-Origin-Resource-Policy',
+ 'Date',
+ 'Device-Memory',
+ 'Downlink',
+ 'ECT',
+ 'ETag',
+ 'Expect',
+ 'Expect-CT',
+ 'Expires',
+ 'Forwarded',
+ 'From',
+ 'Host',
+ 'If-Match',
+ 'If-Modified-Since',
+ 'If-None-Match',
+ 'If-Range',
+ 'If-Unmodified-Since',
+ 'Keep-Alive',
+ 'Last-Modified',
+ 'Link',
+ 'Location',
+ 'Max-Forwards',
+ 'Origin',
+ 'Permissions-Policy',
+ 'Pragma',
+ 'Proxy-Authenticate',
+ 'Proxy-Authorization',
+ 'RTT',
+ 'Range',
+ 'Referer',
+ 'Referrer-Policy',
+ 'Refresh',
+ 'Retry-After',
+ 'Sec-WebSocket-Accept',
+ 'Sec-WebSocket-Extensions',
+ 'Sec-WebSocket-Key',
+ 'Sec-WebSocket-Protocol',
+ 'Sec-WebSocket-Version',
+ 'Server',
+ 'Server-Timing',
+ 'Service-Worker-Allowed',
+ 'Service-Worker-Navigation-Preload',
+ 'Set-Cookie',
+ 'SourceMap',
+ 'Strict-Transport-Security',
+ 'Supports-Loading-Mode',
+ 'TE',
+ 'Timing-Allow-Origin',
+ 'Trailer',
+ 'Transfer-Encoding',
+ 'Upgrade',
+ 'Upgrade-Insecure-Requests',
+ 'User-Agent',
+ 'Vary',
+ 'Via',
+ 'WWW-Authenticate',
+ 'X-Content-Type-Options',
+ 'X-DNS-Prefetch-Control',
+ 'X-Frame-Options',
+ 'X-Permitted-Cross-Domain-Policies',
+ 'X-Powered-By',
+ 'X-Requested-With',
+ 'X-XSS-Protection'
+]
+
+for (let i = 0; i < wellknownHeaderNames.length; ++i) {
+ const key = wellknownHeaderNames[i]
+ const lowerCasedKey = key.toLowerCase()
+ headerNameLowerCasedRecord[key] = headerNameLowerCasedRecord[lowerCasedKey] =
+ lowerCasedKey
+}
+
+// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`.
+Object.setPrototypeOf(headerNameLowerCasedRecord, null)
+
+module.exports = {
+ wellknownHeaderNames,
+ headerNameLowerCasedRecord
+}
+
+
/***/ }),
/***/ 8045:
@@ -19297,6 +19423,7 @@ const { InvalidArgumentError } = __nccwpck_require__(8045)
const { Blob } = __nccwpck_require__(4300)
const nodeUtil = __nccwpck_require__(3837)
const { stringify } = __nccwpck_require__(3477)
+const { headerNameLowerCasedRecord } = __nccwpck_require__(4462)
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(v))
@@ -19506,6 +19633,15 @@ function parseKeepAliveTimeout (val) {
return m ? parseInt(m[1], 10) * 1000 : null
}
+/**
+ * Retrieves a header name and returns its lowercase value.
+ * @param {string | Buffer} value Header name
+ * @returns {string}
+ */
+function headerNameToString (value) {
+ return headerNameLowerCasedRecord[value] || value.toLowerCase()
+}
+
function parseHeaders (headers, obj = {}) {
// For H2 support
if (!Array.isArray(headers)) return headers
@@ -19777,6 +19913,7 @@ module.exports = {
isIterable,
isAsyncIterable,
isDestroyed,
+ headerNameToString,
parseRawHeaders,
parseHeaders,
parseKeepAliveTimeout,
@@ -26424,14 +26561,18 @@ const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(3983
const assert = __nccwpck_require__(9491)
const { isUint8Array } = __nccwpck_require__(4978)
+let supportedHashes = []
+
// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable
/** @type {import('crypto')|undefined} */
let crypto
try {
crypto = __nccwpck_require__(6113)
+ const possibleRelevantHashes = ['sha256', 'sha384', 'sha512']
+ supportedHashes = crypto.getHashes().filter((hash) => possibleRelevantHashes.includes(hash))
+/* c8 ignore next 3 */
} catch {
-
}
function responseURL (response) {
@@ -26959,66 +27100,56 @@ function bytesMatch (bytes, metadataList) {
return true
}
- // 3. If parsedMetadata is the empty set, return true.
+ // 3. If response is not eligible for integrity validation, return false.
+ // TODO
+
+ // 4. If parsedMetadata is the empty set, return true.
if (parsedMetadata.length === 0) {
return true
}
- // 4. Let metadata be the result of getting the strongest
+ // 5. Let metadata be the result of getting the strongest
// metadata from parsedMetadata.
- 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)
+ const strongest = getStrongestMetadata(parsedMetadata)
+ const metadata = filterMetadataListByAlgorithm(parsedMetadata, strongest)
- // 5. For each item in metadata:
+ // 6. 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.
- let expectedValue = item.hash
+ const 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.endsWith('==')) {
- actualValue = actualValue.slice(0, -2)
+ if (actualValue[actualValue.length - 1] === '=') {
+ if (actualValue[actualValue.length - 2] === '=') {
+ actualValue = actualValue.slice(0, -2)
+ } else {
+ actualValue = actualValue.slice(0, -1)
+ }
}
// 4. If actualValue is a case-sensitive match for expectedValue,
// return true.
- 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) {
+ if (compareBase64Mixed(actualValue, expectedValue)) {
return true
}
}
- // 6. Return false.
+ // 7. 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 = /((?sha256|sha384|sha512)-(?[A-z0-9+/]{1}.*={0,2}))( +[\x21-\x7e]?)?/i
+const parseHashWithOptions = /(?sha256|sha384|sha512)-((?[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i
/**
* @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
@@ -27032,8 +27163,6 @@ 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.
@@ -27043,7 +27172,11 @@ 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) {
+ if (
+ parsedToken === null ||
+ parsedToken.groups === undefined ||
+ parsedToken.groups.algo === 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
@@ -27052,11 +27185,11 @@ function parseMetadata (metadata) {
}
// 4. Let algorithm be the hash-algo component of token.
- const algorithm = parsedToken.groups.algo
+ const algorithm = parsedToken.groups.algo.toLowerCase()
// 5. If algorithm is a hash function recognized by the user
// agent, add the parsed token to result.
- if (supportedHashes.includes(algorithm.toLowerCase())) {
+ if (supportedHashes.includes(algorithm)) {
result.push(parsedToken.groups)
}
}
@@ -27069,6 +27202,82 @@ 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
@@ -27484,7 +27693,8 @@ module.exports = {
urlHasHttpsScheme,
urlIsHttpHttpsScheme,
readAllBytes,
- normalizeMethodRecord
+ normalizeMethodRecord,
+ parseMetadata
}
@@ -29571,12 +29781,17 @@ function parseLocation (statusCode, headers) {
// https://tools.ietf.org/html/rfc7231#section-6.4.4
function shouldRemoveHeader (header, removeContent, unknownOrigin) {
- return (
- (header.length === 4 && header.toString().toLowerCase() === 'host') ||
- (removeContent && header.toString().toLowerCase().indexOf('content-') === 0) ||
- (unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') ||
- (unknownOrigin && header.length === 6 && header.toString().toLowerCase() === 'cookie')
- )
+ if (header.length === 4) {
+ return util.headerNameToString(header) === 'host'
+ }
+ if (removeContent && util.headerNameToString(header).startsWith('content-')) {
+ return true
+ }
+ if (unknownOrigin && (header.length === 13 || header.length === 6 || header.length === 19)) {
+ const name = util.headerNameToString(header)
+ return name === 'authorization' || name === 'cookie' || name === 'proxy-authorization'
+ }
+ return false
}
// https://tools.ietf.org/html/rfc7231#section-6.4
diff --git a/package-lock.json b/package-lock.json
index 5c997d8..7c489fd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1256,12 +1256,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -1872,10 +1873,11 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -2273,6 +2275,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -3430,6 +3433,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -3595,9 +3599,10 @@
"dev": true
},
"node_modules/undici": {
- "version": "5.28.3",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
- "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
+ "version": "5.28.4",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
+ "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
+ "license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},