mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-14 08:36:26 +00:00
b8e36daa87
Co-authored-by: Renovate Bot <bot@renovateapp.com> Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
146 lines
4 KiB
TypeScript
146 lines
4 KiB
TypeScript
import merge from 'deepmerge';
|
|
import { logger } from '../logger';
|
|
import { HostRule } from '../types';
|
|
import { clone } from './clone';
|
|
import * as sanitize from './sanitize';
|
|
import { parseUrl, validateUrl } from './url';
|
|
|
|
let hostRules: HostRule[] = [];
|
|
|
|
const legacyHostFields = ['hostName', 'domainName', 'baseUrl'];
|
|
|
|
export function add(params: HostRule): void {
|
|
const rule = clone(params);
|
|
const matchedFields = legacyHostFields.filter((field) => rule[field]);
|
|
if (matchedFields.length) {
|
|
if (rule.matchHost || matchedFields.length > 1) {
|
|
throw new Error(
|
|
`hostRules cannot contain more than one host-matching field - use "matchHost" only.`
|
|
);
|
|
}
|
|
const field = matchedFields[0];
|
|
logger.warn({ field }, 'Legacy hostRules field needs migrating');
|
|
rule.matchHost = rule[field];
|
|
delete rule[field];
|
|
}
|
|
|
|
const confidentialFields = ['password', 'token'];
|
|
if (rule.matchHost) {
|
|
const parsedUrl = parseUrl(rule.matchHost);
|
|
rule.resolvedHost = parsedUrl?.hostname || rule.matchHost;
|
|
confidentialFields.forEach((field) => {
|
|
if (rule[field]) {
|
|
logger.debug(
|
|
`Adding ${field} authentication for ${rule.matchHost} to hostRules`
|
|
);
|
|
}
|
|
});
|
|
}
|
|
confidentialFields.forEach((field) => {
|
|
const secret = rule[field];
|
|
if (secret && secret.length > 3) {
|
|
sanitize.add(secret);
|
|
}
|
|
});
|
|
if (rule.username && rule.password) {
|
|
const secret = Buffer.from(`${rule.username}:${rule.password}`).toString(
|
|
'base64'
|
|
);
|
|
sanitize.add(secret);
|
|
}
|
|
hostRules.push(rule);
|
|
}
|
|
|
|
export interface HostRuleSearch {
|
|
hostType?: string;
|
|
url?: string;
|
|
}
|
|
|
|
function isEmptyRule(rule: HostRule): boolean {
|
|
return !rule.hostType && !rule.resolvedHost;
|
|
}
|
|
|
|
function isHostTypeRule(rule: HostRule): boolean {
|
|
return rule.hostType && !rule.resolvedHost;
|
|
}
|
|
|
|
function isHostOnlyRule(rule: HostRule): boolean {
|
|
return !rule.hostType && !!rule.matchHost;
|
|
}
|
|
|
|
function isMultiRule(rule: HostRule): boolean {
|
|
return rule.hostType && !!rule.resolvedHost;
|
|
}
|
|
|
|
function matchesHostType(rule: HostRule, search: HostRuleSearch): boolean {
|
|
return rule.hostType === search.hostType;
|
|
}
|
|
|
|
function matchesHost(rule: HostRule, search: HostRuleSearch): boolean {
|
|
if (validateUrl(rule.matchHost)) {
|
|
return search.url.startsWith(rule.matchHost);
|
|
}
|
|
const parsedUrl = parseUrl(search.url);
|
|
if (!parsedUrl?.hostname) {
|
|
return false;
|
|
}
|
|
const { hostname } = parsedUrl;
|
|
return hostname === rule.matchHost || hostname.endsWith(`.${rule.matchHost}`);
|
|
}
|
|
|
|
export function find(search: HostRuleSearch): HostRule {
|
|
if (!(search.hostType || search.url)) {
|
|
logger.warn({ search }, 'Invalid hostRules search');
|
|
return {};
|
|
}
|
|
let res = {} as any as HostRule;
|
|
// First, apply empty rule matches
|
|
hostRules
|
|
.filter((rule) => isEmptyRule(rule))
|
|
.forEach((rule) => {
|
|
res = merge(res, rule);
|
|
});
|
|
// Next, find hostType-only matches
|
|
hostRules
|
|
.filter((rule) => isHostTypeRule(rule) && matchesHostType(rule, search))
|
|
.forEach((rule) => {
|
|
res = merge(res, rule);
|
|
});
|
|
hostRules
|
|
.filter((rule) => isHostOnlyRule(rule) && matchesHost(rule, search))
|
|
.forEach((rule) => {
|
|
res = merge(res, rule);
|
|
});
|
|
// Finally, find combination matches
|
|
hostRules
|
|
.filter(
|
|
(rule) =>
|
|
isMultiRule(rule) &&
|
|
matchesHostType(rule, search) &&
|
|
matchesHost(rule, search)
|
|
)
|
|
.forEach((rule) => {
|
|
res = merge(res, rule);
|
|
});
|
|
delete res.hostType;
|
|
delete res.resolvedHost;
|
|
delete res.matchHost;
|
|
return res;
|
|
}
|
|
|
|
export function hosts({ hostType }: { hostType: string }): string[] {
|
|
return hostRules
|
|
.filter((rule) => rule.hostType === hostType)
|
|
.map((rule) => rule.resolvedHost)
|
|
.filter(Boolean);
|
|
}
|
|
|
|
export function findAll({ hostType }: { hostType: string }): HostRule[] {
|
|
return hostRules.filter((rule) => rule.hostType === hostType);
|
|
}
|
|
|
|
export function clear(): void {
|
|
logger.debug('Clearing hostRules');
|
|
hostRules = [];
|
|
sanitize.clear();
|
|
}
|