From 17522738688961c1dc9b3a4c1c7b1eb6615f921a Mon Sep 17 00:00:00 2001 From: operator Date: Mon, 7 Sep 2026 10:27:19 +0900 Subject: [PATCH] main ships two advisories in its runtime tree, so the lockfile moves and the bundle with it `npm audit --omit=dev --audit-level=low` fails on `main` at 597ac757, not only on the open dependency pull requests. Both findings are in the runtime tree, which is the tree that gets bundled into `dist/commitlore.mjs` and installed: fast-uri 3.1.5 high GHSA-5jgf-p345-68v8, GHSA-f65p-4m7j-42xc, GHSA-fph4-wmhf-6fwf, GHSA-jqff-g426-hqxp (reached through ajv, a direct dependency) qs 6.15.3 moderate GHSA-x5fp-wj9c-mxmx, GHSA-4mjr-xmp4-gh2g (reached through @modelcontextprotocol/sdk -> express) This is why every open dependency pull request is red on `audit` while `check` is green: the advisories were published after those branches last ran, and none of the bumps on them touches either package. Fixing them there would have been three copies of this commit. `npm audit fix` without `--force` was enough: fast-uri 3.1.5 -> 3.1.7, qs 6.15.3 -> 6.16.0, nanoid 3.3.16 -> 3.3.18, nine lines of `package-lock.json` and no edit to `package.json`. Both packages are runtime dependencies and therefore bundled, so the canonical build was mandatory rather than a formality -- the artifact digest moves to 469d61aa6502ebdbdd9915e5b962144bb718b782a634cd43cf19a53f8fde5a5e. Record-Id: r-fasturiqsaudit Follows: r-cdebmanifest Provenance: authored Certainty: firm Blast: system Undo: easy Ruled-out: fixing this on each dependency pull request instead | the advisories are on main, so each branch would carry an identical lockfile and dist change and the three would conflict with each other on merge Ruled-out: npm audit fix --force | it also rewrites the dev tree through breaking upgrades, which is the vitest major question and not a security fix; the five remaining advisories are dev-only and outside what CI's --omit=dev gate asserts Limit: an audit is a claim about advisories published at this moment, not about the code; a clean run says nothing about tomorrow's disclosures Verified: npm audit --omit=dev --audit-level=low reports 0 vulnerabilities on this branch; the pinned linux/amd64 build produced the committed dist and artifact:verify exits 0; typecheck and check-engines clean; 3157 tests passed and 4 skipped across 164 files Unverified: CI has not yet run this branch; the runtime effect of qs 6.16.0 inside express is exercised only as far as this repository's suite reaches it --- dist/commitlore.mjs | 535 +++++++++++++++++++++++------- installer/canonical-artifact.json | 6 +- package-lock.json | 18 +- 3 files changed, 421 insertions(+), 138 deletions(-) diff --git a/dist/commitlore.mjs b/dist/commitlore.mjs index a3989cff..fdf5d032 100755 --- a/dist/commitlore.mjs +++ b/dist/commitlore.mjs @@ -3109,9 +3109,28 @@ var require_utils = __commonJS({ "use strict"; var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu); var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u); + var isPort = RegExp.prototype.test.bind(/^\d*$/u); var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu); var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu); - var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu); + var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u); + var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u); + var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u); + var BYTE_HEX = new Array(256); + { + const HEX_DIGITS = "0123456789ABCDEF"; + for (let i = 0; i < 256; i++) { + BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15]; + } + } + function percentEncodeNonAscii(cp) { + if (cp < 2048) { + return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63]; + } + if (cp < 65536) { + return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63]; + } + return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63]; + } function stringArrayToHexStripped(input) { let acc = ""; let code = 0; @@ -3136,91 +3155,105 @@ var require_utils = __commonJS({ } return acc; } + var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/); + var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/); + var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/); var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u); - function consumeIsZone(buffer) { - buffer.length = 0; - return true; - } - function consumeHextets(buffer, address, output) { - if (buffer.length) { - const hex = stringArrayToHexStripped(buffer); - if (hex !== "") { - address.push(hex); - } else { - output.error = true; - return false; + function isZoneIdentifier(zone) { + if (zone.length === 0) return false; + for (let i = 0; i < zone.length; i++) { + if (isZoneCharacter(zone[i])) continue; + if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) { + i += 2; + continue; } - buffer.length = 0; + return false; } return true; } - function getIPV6(input) { - let tokenCount = 0; - const output = { error: false, address: "", zone: "" }; - const address = []; - const buffer = []; - let endipv6Encountered = false; - let endIpv6 = false; - let consume = consumeHextets; - for (let i = 0; i < input.length; i++) { - const cursor = input[i]; - if (cursor === "[" || cursor === "]") { - continue; - } - if (cursor === ":") { - if (endipv6Encountered === true) { - endIpv6 = true; - } - if (!consume(buffer, address, output)) { - break; + function compressIPv6ZeroRun(hextets) { + let bestStart = -1; + let bestLength = 0; + let runStart = -1; + let runLength = 0; + for (let i = 0; i < hextets.length; i++) { + if (hextets[i] === "0") { + if (runStart === -1) runStart = i; + runLength++; + if (runLength > bestLength) { + bestLength = runLength; + bestStart = runStart; } - if (++tokenCount > 7) { - output.error = true; - break; - } - if (i > 0 && input[i - 1] === ":") { - endipv6Encountered = true; - } - address.push(":"); - continue; - } else if (cursor === "%") { - if (!consume(buffer, address, output)) { - break; - } - consume = consumeIsZone; } else { - buffer.push(cursor); + runStart = -1; + runLength = 0; + } + } + if (bestLength < 2) return hextets.join(":"); + const head = hextets.slice(0, bestStart).join(":"); + const tail = hextets.slice(bestStart + bestLength).join(":"); + return head + "::" + tail; + } + function normalizeIPv6Address(input) { + const compression = input.indexOf("::"); + if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0; + const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":"); + const right = compression === -1 ? [] : input.slice(compression + 2).split(":"); + if (compression !== -1) { + if (left.length === 1 && left[0] === "") left.length = 0; + if (right.length === 1 && right[0] === "") right.length = 0; + } + const parts = left.concat(right); + let hextetCount = 0; + for (let i = 0; i < parts.length; i++) { + const part = parts[i]; + if (part === "") return void 0; + if (part.indexOf(".") !== -1) { + if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0; + hextetCount += 2; continue; } + if (!isHextet(part)) return void 0; + parts[i] = parseInt(part, 16).toString(16); + hextetCount++; } - if (buffer.length) { - if (consume === consumeIsZone) { - output.zone = buffer.join(""); - } else if (endIpv6) { - address.push(buffer.join("")); - } else { - address.push(stringArrayToHexStripped(buffer)); - } + if (compression === -1) { + if (hextetCount !== 8) return void 0; + return compressIPv6ZeroRun(parts); } - output.address = address.join(""); - return output; + if (hextetCount >= 8) return void 0; + const expanded = parts.slice(0, left.length); + for (let i = hextetCount; i < 8; i++) expanded.push("0"); + for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]); + return compressIPv6ZeroRun(expanded); } function normalizeIPv6(host) { - if (findToken(host, ":") < 2) { - return { host, isIPV6: false }; - } - const ipv62 = getIPV6(host); - if (!ipv62.error) { - let newHost = ipv62.address; - let escapedHost = ipv62.address; - if (ipv62.zone) { - newHost += "%" + ipv62.zone; - escapedHost += "%25" + ipv62.zone; - } - return { host: newHost, isIPV6: true, escapedHost }; - } else { - return { host, isIPV6: false }; - } + const bracketed = host[0] === "[" && host[host.length - 1] === "]"; + const hasBracket = host[0] === "[" || host[host.length - 1] === "]"; + if (hasBracket && !bracketed) return { host, isIPV6: false, error: true }; + let input = bracketed ? host.slice(1, -1) : host; + if (bracketed && isIPvFuture(input)) { + input = input.toLowerCase(); + return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true }; + } + if (findToken(input, ":") < 2) { + return { host, isIPV6: false, error: bracketed }; + } + let zoneIdentifier = ""; + const zoneSeparator = input.indexOf("%"); + if (zoneSeparator !== -1) { + const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1; + zoneIdentifier = input.slice(zoneSeparator + separatorLength); + if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true }; + input = input.slice(0, zoneSeparator); + } + const address = normalizeIPv6Address(input); + if (address === void 0) return { host, isIPV6: false, error: true }; + return { + host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""), + escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""), + isIPV6: true + }; } function findToken(str, token) { let ind = 0; @@ -3339,7 +3372,8 @@ var require_utils = __commonJS({ function normalizePathEncoding(input) { let output = ""; for (let i = 0; i < input.length; i++) { - if (input[i] === "%" && i + 2 < input.length) { + const ch = input[i]; + if (ch === "%" && i + 2 < input.length) { const hex = input.slice(i + 1, i + 3); if (isHexPair(hex)) { const normalizedHex = hex.toUpperCase(); @@ -3353,10 +3387,152 @@ var require_utils = __commonJS({ continue; } } - if (isPathCharacter(input[i])) { - output += input[i]; + if (isPathCharacter(ch)) { + output += ch; + } else { + const code = input.charCodeAt(i); + if (code < 128) { + output += isEscapeSafe(code) ? ch : BYTE_HEX[code]; + } else if (code < 55296 || code > 57343) { + output += percentEncodeNonAscii(code); + } else if (code <= 56319 && i + 1 < input.length) { + const low = input.charCodeAt(i + 1); + if (low >= 56320 && low <= 57343) { + output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320)); + i++; + } else { + output += percentEncodeNonAscii(65533); + } + } else { + output += percentEncodeNonAscii(65533); + } + } + } + return output; + } + function serializePathEncoding(input, pathNoScheme = false) { + let output = ""; + let firstSegment = pathNoScheme && input[0] !== "/"; + for (let i = 0; i < input.length; i++) { + const ch = input[i]; + if (ch === "%" && i + 2 < input.length) { + const hex = input.slice(i + 1, i + 3); + if (isHexPair(hex)) { + output += "%" + hex.toUpperCase(); + i += 2; + continue; + } + } + if (ch === "/") { + firstSegment = false; + } + if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) { + output += ch; } else { - output += escape(input[i]); + const code = input.charCodeAt(i); + if (code < 128) { + output += BYTE_HEX[code]; + } else if (code < 55296 || code > 57343) { + output += percentEncodeNonAscii(code); + } else if (code <= 56319 && i + 1 < input.length) { + const low = input.charCodeAt(i + 1); + if (low >= 56320 && low <= 57343) { + output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320)); + i++; + } else { + output += percentEncodeNonAscii(65533); + } + } else { + output += percentEncodeNonAscii(65533); + } + } + } + return output; + } + function encodeComponent(input, isAllowed) { + let output = ""; + for (let i = 0; i < input.length; i++) { + const ch = input[i]; + if (ch === "%" && i + 2 < input.length) { + const hex = input.slice(i + 1, i + 3); + if (isHexPair(hex)) { + output += "%" + hex.toUpperCase(); + i += 2; + continue; + } + } + if (isAllowed(ch)) { + output += ch; + } else { + const code = input.charCodeAt(i); + if (code < 128) { + output += BYTE_HEX[code]; + } else if (code < 55296 || code > 57343) { + output += percentEncodeNonAscii(code); + } else if (code <= 56319 && i + 1 < input.length) { + const low = input.charCodeAt(i + 1); + if (low >= 56320 && low <= 57343) { + output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320)); + i++; + } else { + output += percentEncodeNonAscii(65533); + } + } else { + output += percentEncodeNonAscii(65533); + } + } + } + return output; + } + function encodeUserinfo(input) { + return encodeComponent(input, isUserinfoCharacter); + } + function encodeQuery(input) { + return encodeComponent(input, isQueryFragmentCharacter); + } + function encodeFragment(input) { + return encodeComponent(input, isQueryFragmentCharacter); + } + function isEscapeSafe(cp) { + return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95; + } + function normalizeQueryFragmentEncoding(input) { + let output = ""; + for (let i = 0; i < input.length; i++) { + const ch = input[i]; + if (ch === "%" && i + 2 < input.length) { + const hex = input.slice(i + 1, i + 3); + if (isHexPair(hex)) { + const normalizedHex = hex.toUpperCase(); + const decoded = String.fromCharCode(parseInt(normalizedHex, 16)); + if (isUnreserved(decoded)) { + output += decoded; + } else { + output += "%" + normalizedHex; + } + i += 2; + continue; + } + } + if (isQueryFragmentCharacter(ch)) { + output += ch; + } else { + const code = input.charCodeAt(i); + if (code < 128) { + output += isEscapeSafe(code) ? ch : BYTE_HEX[code]; + } else if (code < 55296 || code > 57343) { + output += percentEncodeNonAscii(code); + } else if (code <= 56319 && i + 1 < input.length) { + const low = input.charCodeAt(i + 1); + if (low >= 56320 && low <= 57343) { + output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320)); + i++; + } else { + output += percentEncodeNonAscii(65533); + } + } else { + output += percentEncodeNonAscii(65533); + } } } return output; @@ -3379,14 +3555,18 @@ var require_utils = __commonJS({ function recomposeAuthority(component) { const uriTokens = []; if (component.userinfo !== void 0) { - uriTokens.push(component.userinfo); + uriTokens.push(encodeUserinfo(component.userinfo)); uriTokens.push("@"); } if (component.host !== void 0) { - let host = unescape(component.host); + let host = component.host; if (!isIPv4(host)) { - const ipV6res = normalizeIPv6(host); - if (ipV6res.isIPV6 === true) { + let ipV6res = normalizeIPv6(host); + if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) { + host = normalizePercentEncoding(host, true); + ipV6res = normalizeIPv6(host); + } + if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) { host = `[${ipV6res.escapedHost}]`; } else { host = reescapeHostDelimiters(host, false); @@ -3395,8 +3575,12 @@ var require_utils = __commonJS({ uriTokens.push(host); } if (typeof component.port === "number" || typeof component.port === "string") { + const port = String(component.port); + if (!isPort(port)) { + throw new TypeError("URI port is malformed."); + } uriTokens.push(":"); - uriTokens.push(String(component.port)); + uriTokens.push(port); } return uriTokens.length ? uriTokens.join("") : void 0; } @@ -3406,6 +3590,11 @@ var require_utils = __commonJS({ reescapeHostDelimiters, normalizePercentEncoding, normalizePathEncoding, + serializePathEncoding, + normalizeQueryFragmentEncoding, + encodeUserinfo, + encodeQuery, + encodeFragment, escapePreservingEscapes, removeDotSegments, isIPv4, @@ -3421,7 +3610,7 @@ var require_schemes = __commonJS({ "node_modules/fast-uri/lib/schemes.js"(exports, module) { "use strict"; var { isUUID } = require_utils(); - var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu; + var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu; var supportedSchemeNames = ( /** @type {const} */ [ @@ -3482,9 +3671,10 @@ var require_schemes = __commonJS({ wsComponent.secure = void 0; } if (wsComponent.resourceName) { - const [path2, query] = wsComponent.resourceName.split("?"); + const queryIndex = wsComponent.resourceName.indexOf("?"); + const path2 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex); wsComponent.path = path2 && path2 !== "/" ? path2 : void 0; - wsComponent.query = query; + wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1); wsComponent.resourceName = void 0; } wsComponent.fragment = void 0; @@ -3496,7 +3686,7 @@ var require_schemes = __commonJS({ return urnComponent; } const matches = urnComponent.path.match(URN_REG); - if (matches) { + if (matches && matches[0] === urnComponent.path) { const scheme = options.scheme || urnComponent.scheme || "urn"; urnComponent.nid = matches[1].toLowerCase(); urnComponent.nss = matches[2]; @@ -3630,8 +3820,17 @@ var require_schemes = __commonJS({ var require_fast_uri = __commonJS({ "node_modules/fast-uri/index.js"(exports, module) { "use strict"; - var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils(); + var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils(); var { SCHEMES, getSchemeHandler } = require_schemes(); + var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u; + var MALFORMED_SCHEME_ERROR = "URI scheme is malformed."; + function decodeValidScheme(scheme) { + const decodedScheme = unescape(String(scheme)); + if (!VALID_SCHEME.test(decodedScheme)) { + throw new TypeError(MALFORMED_SCHEME_ERROR); + } + return decodedScheme; + } function normalize2(uri, options) { if (typeof uri === "string") { uri = /** @type {T} */ @@ -3644,12 +3843,34 @@ var require_fast_uri = __commonJS({ } function resolve23(baseURI, relativeURI, options) { const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" }; - const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions); - const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions); - if (baseMalformed || relativeMalformed) { + const { + parsed: baseParsed, + malformedAuthorityOrPort: baseMalformed, + malformedPercentEncoding: baseMalformedPercentEncoding, + malformedSchemeSpecific: baseMalformedSchemeSpecific, + malformedHost: baseMalformedHost, + malformedScheme: baseMalformedScheme + } = parseWithStatus(baseURI, schemelessOptions); + const { + parsed: relativeParsed, + malformedAuthorityOrPort: relativeMalformed, + malformedPercentEncoding: relativeMalformedPercentEncoding, + malformedSchemeSpecific: relativeMalformedSchemeSpecific, + malformedHost: relativeMalformedHost, + malformedScheme: relativeMalformedScheme + } = parseWithStatus(relativeURI, schemelessOptions); + if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) { throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed."); } const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true); + const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme); + const resolvedHost = resolved.host; + const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6); + canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP); + const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost); + if (resolved.error && !encodedASCIIHost) { + throw new Error(resolved.error); + } schemelessOptions.skipEscape = true; return serialize(resolved, schemelessOptions); } @@ -3709,7 +3930,7 @@ var require_fast_uri = __commonJS({ function equal(uriA, uriB, options) { const normalizedA = normalizeComparableURI(uriA, options); const normalizedB = normalizeComparableURI(uriB, options); - return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase(); + return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB; } function serialize(cmpts, opts) { const component = { @@ -3730,19 +3951,22 @@ var require_fast_uri = __commonJS({ }; const options = Object.assign({}, opts); const uriTokens = []; + if (component.scheme) { + component.scheme = decodeValidScheme(component.scheme); + } const schemeHandler = getSchemeHandler(options.scheme || component.scheme); if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options); + const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0; + const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority; if (component.path !== void 0) { if (!options.skipEscape) { - component.path = escapePreservingEscapes(component.path); - if (component.scheme !== void 0) { - component.path = component.path.split("%3A").join(":"); - } + component.path = serializePathEncoding(component.path, pathNoScheme); } else { component.path = normalizePercentEncoding(component.path); } } if (options.reference !== "suffix" && component.scheme) { + component.scheme = decodeValidScheme(component.scheme); uriTokens.push(component.scheme, ":"); } const authority = recomposeAuthority(component); @@ -3760,16 +3984,19 @@ var require_fast_uri = __commonJS({ if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) { s = removeDotSegments(s); } + if (pathNoScheme) { + s = serializePathEncoding(s, true); + } if (authority === void 0 && s[0] === "/" && s[1] === "/") { s = "/%2F" + s.slice(2); } uriTokens.push(s); } if (component.query !== void 0) { - uriTokens.push("?", component.query); + uriTokens.push("?", encodeQuery(component.query)); } if (component.fragment !== void 0) { - uriTokens.push("#", component.fragment); + uriTokens.push("#", encodeFragment(component.fragment)); } return uriTokens.join(""); } @@ -3785,6 +4012,35 @@ var require_fast_uri = __commonJS({ } return void 0; } + function hasMalformedPercentEncoding(component) { + if (component === void 0) return false; + let percent = component.indexOf("%"); + while (percent !== -1) { + if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) { + return true; + } + percent = component.indexOf("%", percent + 3); + } + return false; + } + function isIPLiteral(host) { + return host[0] === "[" && host[host.length - 1] === "]"; + } + function hasMalformedComponentPercentEncoding(matches) { + const host = matches[4]; + return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]); + } + function canonicalizeHost(parsed, options, schemeHandler, isIP) { + if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) { + try { + parsed.host = new URL("http://" + parsed.host).hostname; + } catch (e) { + parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e; + return true; + } + } + return false; + } function parseWithStatus(uri, opts) { const options = Object.assign({}, opts); const parsed = { @@ -3797,6 +4053,11 @@ var require_fast_uri = __commonJS({ fragment: void 0 }; let malformedAuthorityOrPort = false; + let malformedPercentEncoding = false; + let malformedSchemeSpecific = false; + let malformedHost = false; + let malformedIPLiteral = false; + let malformedScheme = false; let isIP = false; if (options.reference === "suffix") { if (options.scheme) { @@ -3833,6 +4094,19 @@ var require_fast_uri = __commonJS({ parsed.path = matches[6] || ""; parsed.query = matches[7]; parsed.fragment = matches[8]; + if (parsed.scheme !== void 0) { + const decodedScheme = unescape(parsed.scheme); + if (VALID_SCHEME.test(decodedScheme)) { + parsed.scheme = decodedScheme.toLowerCase(); + } else { + parsed.error = parsed.error || MALFORMED_SCHEME_ERROR; + malformedScheme = true; + } + } + malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches); + if (malformedPercentEncoding) { + parsed.error = parsed.error || "URI contains malformed percent-encoding."; + } if (isNaN(parsed.port)) { parsed.port = matches[5]; } @@ -3844,9 +4118,16 @@ var require_fast_uri = __commonJS({ if (parsed.host) { const ipv4result = isIPv4(parsed.host); if (ipv4result === false) { + const bracketedIPLiteral = isIPLiteral(parsed.host); + const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1; const ipv6result = normalizeIPv6(parsed.host); - parsed.host = ipv6result.host.toLowerCase(); - isIP = ipv6result.isIPV6; + isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true; + malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true); + parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase(); + if (malformedIPLiteral) { + parsed.error = parsed.error || "URI host is malformed."; + malformedAuthorityOrPort = true; + } } else { isIP = true; } @@ -3864,42 +4145,36 @@ var require_fast_uri = __commonJS({ parsed.error = parsed.error || "URI is not a " + options.reference + " reference."; } const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme); - if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) { - if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) { - try { - parsed.host = new URL("http://" + parsed.host).hostname; - } catch (e) { - parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e; - } - } + if (!malformedIPLiteral) { + malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP); } if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) { if (uri.indexOf("%") !== -1) { - if (parsed.scheme !== void 0) { - parsed.scheme = unescape(parsed.scheme); - } - if (parsed.host !== void 0) { - parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP); + if (parsed.host !== void 0 && !malformedIPLiteral) { + const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true); + parsed.host = reescapeHostDelimiters(host, isIP); } } if (parsed.path) { parsed.path = normalizePathEncoding(parsed.path); } + if (parsed.query) { + parsed.query = normalizeQueryFragmentEncoding(parsed.query); + } if (parsed.fragment) { - try { - parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment)); - } catch { - parsed.error = parsed.error || "URI malformed"; - } + parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment); } } if (schemeHandler && schemeHandler.parse) { schemeHandler.parse(parsed, options); + if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) { + malformedSchemeSpecific = true; + } } } else { parsed.error = parsed.error || "URI can not be parsed."; } - return { parsed, malformedAuthorityOrPort }; + return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme }; } function parse4(uri, opts) { return parseWithStatus(uri, opts).parsed; @@ -3908,20 +4183,28 @@ var require_fast_uri = __commonJS({ return normalizeStringWithStatus(uri, opts).normalized; } function normalizeStringWithStatus(uri, opts) { - const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts); + const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts); return { - normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts), - malformedAuthorityOrPort + normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts), + malformedAuthorityOrPort, + malformedPercentEncoding, + malformedSchemeSpecific, + malformedHost, + malformedScheme }; } function normalizeComparableURI(uri, opts) { - if (typeof uri === "string") { - const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts); - return malformedAuthorityOrPort ? void 0 : normalized; + if (typeof uri !== "string" && typeof uri !== "object") { + return void 0; } - if (typeof uri === "object") { - return serialize(uri, opts); + let value; + try { + value = typeof uri === "string" ? uri : serialize(uri, opts); + } catch { + return void 0; } + const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts); + return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized; } var fastUri = { SCHEMES, diff --git a/installer/canonical-artifact.json b/installer/canonical-artifact.json index 900cad39..306c3851 100644 --- a/installer/canonical-artifact.json +++ b/installer/canonical-artifact.json @@ -15,10 +15,10 @@ "tsconfig.json", "src" ], - "sha256": "fcedf58190a9ff4f3485c8615527dad7b8c91c8a0f8de9cc73f07e7a81bc14e1" + "sha256": "c939c152715ab8f01eea0888e26f73435db53c82931c4741b28ad162ad73619c" }, "artifact": { - "sha256": "e8183a8fd3171c20b92c6234fc7ef0826cf4853d71471d421485b2bd71fc88fe", + "sha256": "469d61aa6502ebdbdd9915e5b962144bb718b782a634cd43cf19a53f8fde5a5e", "files": [ { "path": "dist/cli.d.ts", @@ -622,7 +622,7 @@ }, { "path": "dist/commitlore.mjs", - "sha256": "747b697be3a13db12a12844d0739f419cac4a569dc176aac8ada298cba4fae32" + "sha256": "24b845a7ee9b7a65f2b335f0a299a6d623a7131cdb54f8e664ec6a4b838cacde" }, { "path": "dist/core/agent-configs.d.ts", diff --git a/package-lock.json b/package-lock.json index 969db0d6..6f80c690 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1538,9 +1538,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", "funding": [ { "type": "github", @@ -1897,9 +1897,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -2070,9 +2070,9 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1",