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" },