UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

130 lines (129 loc) 4.59 kB
import { toBase64 } from "./string.js"; import { addSecretForSanitizing, clearRepoSanitizedSecretsList } from "./sanitize.js"; import { logger } from "../logger/index.js"; import { clone } from "./clone.js"; import { isHttpUrl, massageHostUrl, parseUrl } from "./url.js"; import { isFalsy, isString, isTruthy, isUndefined } from "@sindresorhus/is"; //#region lib/util/host-rules.ts let hostRules = []; function migrateRule(rule) { const cloned = clone(rule); delete cloned.hostName; delete cloned.domainName; delete cloned.baseUrl; const result = cloned; const { matchHost } = result; const { hostName, domainName, baseUrl } = rule; const hostValues = [ matchHost, hostName, domainName, baseUrl ].filter(Boolean); if (hostValues.length === 1) { const [matchHost] = hostValues; result.matchHost = matchHost; } else if (hostValues.length > 1) throw new Error(`hostRules cannot contain more than one host-matching field - use "matchHost" only.`); return result; } function add(params) { const rule = migrateRule(params); const confidentialFields = ["password", "token"]; if (rule.matchHost) { rule.matchHost = massageHostUrl(rule.matchHost); rule.resolvedHost = parseUrl(rule.matchHost)?.hostname ?? rule.matchHost; confidentialFields.forEach((field) => { if (rule[field]) logger.debug(`Adding ${field} authentication for ${rule.matchHost} (hostType=${rule.hostType}) to hostRules`); }); } confidentialFields.forEach((field) => { const secret = rule[field]; if (isString(secret) && secret.length > 3) addSecretForSanitizing(secret); }); if (rule.username && rule.password) addSecretForSanitizing(toBase64(`${rule.username}:${rule.password}`)); hostRules.push(rule); } function matchesHost(url, matchHost) { const parsedUrl = parseUrl(url); if (!parsedUrl) return false; const parsedMatchHost = parseUrl(matchHost); if (isHttpUrl(parsedUrl) && isHttpUrl(parsedMatchHost)) return parsedUrl.href.startsWith(parsedMatchHost.href); const { hostname } = parsedUrl; if (!hostname) return false; if (hostname === matchHost) return true; const topLevelSuffix = matchHost.startsWith(".") ? matchHost : `.${matchHost}`; return hostname.endsWith(topLevelSuffix); } function fromShorterToLongerMatchHost(a, b) { if (!a.matchHost || !b.matchHost) return 0; return a.matchHost.length - b.matchHost.length; } function hostRuleRank({ hostType, matchHost, readOnly }) { if ((hostType || readOnly) && matchHost) return 3; if (matchHost) return 2; if (hostType) return 1; return 0; } function fromLowerToHigherRank(a, b) { return hostRuleRank(a) - hostRuleRank(b); } function find(search) { if ([search.hostType, search.url].every(isFalsy)) { logger.warn({ search }, "Invalid hostRules search"); return {}; } const sortedRules = hostRules.sort(fromShorterToLongerMatchHost).sort(fromLowerToHigherRank); const matchedRules = []; for (const rule of sortedRules) { let hostTypeMatch = true; let hostMatch = true; let readOnlyMatch = true; if (rule.hostType) { hostTypeMatch = false; // v8 ignore else -- TODO: add test #40625 if (search.hostType === rule.hostType) hostTypeMatch = true; } if (rule.matchHost && rule.resolvedHost) { hostMatch = false; if (search.url) hostMatch = matchesHost(search.url, rule.matchHost); } if (!isUndefined(rule.readOnly)) { readOnlyMatch = false; // v8 ignore else -- TODO: add test #40625 if (search.readOnly === rule.readOnly) { readOnlyMatch = true; hostTypeMatch = true; } } if (hostTypeMatch && readOnlyMatch && hostMatch) matchedRules.push(clone(rule)); } const res = Object.assign({}, ...matchedRules); delete res.hostType; delete res.resolvedHost; delete res.matchHost; delete res.readOnly; return res; } function hosts({ hostType }) { return hostRules.filter((rule) => rule.hostType === hostType).map((rule) => rule.resolvedHost).filter(isTruthy); } function hostType({ url }) { return hostRules.filter((rule) => rule.matchHost && matchesHost(url, rule.matchHost)).sort(fromShorterToLongerMatchHost).map((rule) => rule.hostType).filter(isTruthy).pop() ?? null; } function findAll({ hostType }) { return hostRules.filter((rule) => rule.hostType === hostType); } /** * @returns a deep copy of all known host rules without any filtering */ function getAll() { return clone(hostRules); } function clear() { logger.debug("Clearing hostRules"); hostRules = []; clearRepoSanitizedSecretsList(); } //#endregion export { add, clear, find, findAll, getAll, hostType, hosts, matchesHost, migrateRule }; //# sourceMappingURL=host-rules.js.map