2019-05-18 05:49:53 +00:00
|
|
|
import URL from 'url';
|
2019-05-24 15:40:39 +00:00
|
|
|
import merge from 'deepmerge';
|
2019-07-15 09:04:05 +00:00
|
|
|
import { logger } from '../logger';
|
2020-03-02 11:06:16 +00:00
|
|
|
import { HostRule } from '../types';
|
2021-05-01 16:19:38 +00:00
|
|
|
import { clone } from './clone';
|
2020-05-01 16:03:48 +00:00
|
|
|
import * as sanitize from './sanitize';
|
2019-05-24 15:40:39 +00:00
|
|
|
|
|
|
|
let hostRules: HostRule[] = [];
|
|
|
|
|
2021-05-01 21:18:14 +00:00
|
|
|
const matchFields = ['hostName', 'domainName', 'baseUrl'];
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
export function add(params: HostRule): void {
|
2021-05-01 21:18:14 +00:00
|
|
|
const matchedFields = matchFields.filter((field) => params[field]);
|
|
|
|
if (matchedFields.length > 1) {
|
|
|
|
throw new Error(
|
|
|
|
`hostRules cannot contain more than one host-matching field. Found: [${matchedFields.join(
|
|
|
|
', '
|
|
|
|
)}]`
|
|
|
|
);
|
2018-07-06 05:26:36 +00:00
|
|
|
}
|
2019-09-07 12:51:00 +00:00
|
|
|
const confidentialFields = ['password', 'token'];
|
2021-05-01 16:19:38 +00:00
|
|
|
let resolvedHost = params.baseUrl || params.hostName || params.domainName;
|
2021-05-01 11:07:46 +00:00
|
|
|
if (resolvedHost) {
|
2021-05-01 16:19:38 +00:00
|
|
|
resolvedHost = URL.parse(resolvedHost).hostname || resolvedHost;
|
2021-04-20 08:52:38 +00:00
|
|
|
confidentialFields.forEach((field) => {
|
|
|
|
if (params[field]) {
|
|
|
|
logger.debug(
|
2021-05-01 11:07:46 +00:00
|
|
|
`Adding ${field} authentication for ${resolvedHost} to hostRules`
|
2021-04-20 08:52:38 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-04-12 16:09:36 +00:00
|
|
|
confidentialFields.forEach((field) => {
|
2019-09-07 12:51:00 +00:00
|
|
|
const secret = params[field];
|
2020-03-17 11:15:22 +00:00
|
|
|
if (secret && secret.length > 3) {
|
|
|
|
sanitize.add(secret);
|
|
|
|
}
|
2019-09-07 12:51:00 +00:00
|
|
|
});
|
|
|
|
if (params.username && params.password) {
|
|
|
|
const secret = Buffer.from(
|
|
|
|
`${params.username}:${params.password}`
|
|
|
|
).toString('base64');
|
2019-09-12 10:48:31 +00:00
|
|
|
sanitize.add(secret);
|
2019-09-07 12:51:00 +00:00
|
|
|
}
|
2021-05-01 16:19:38 +00:00
|
|
|
const hostRule = clone(params);
|
|
|
|
if (resolvedHost) {
|
|
|
|
hostRule.resolvedHost = resolvedHost;
|
|
|
|
}
|
|
|
|
hostRules.push(hostRule);
|
2019-05-24 15:40:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface HostRuleSearch {
|
|
|
|
hostType?: string;
|
2019-07-17 08:14:56 +00:00
|
|
|
url?: string;
|
2019-05-24 15:40:39 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function isEmptyRule(rule: HostRule): boolean {
|
2019-05-24 15:40:39 +00:00
|
|
|
return !rule.hostType && !rule.domainName && !rule.hostName && !rule.baseUrl;
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function isHostTypeRule(rule: HostRule): boolean {
|
2019-05-24 15:40:39 +00:00
|
|
|
return rule.hostType && !rule.domainName && !rule.hostName && !rule.baseUrl;
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function isDomainNameRule(rule: HostRule): boolean {
|
|
|
|
return !rule.hostType && !!rule.domainName;
|
2019-05-24 15:40:39 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function isHostNameRule(rule: HostRule): boolean {
|
|
|
|
return !rule.hostType && !!rule.hostName;
|
2019-05-24 15:40:39 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function isBaseUrlRule(rule: HostRule): boolean {
|
|
|
|
return !rule.hostType && !!rule.baseUrl;
|
2019-05-24 15:40:39 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function isMultiRule(rule: HostRule): boolean {
|
|
|
|
return rule.hostType && !!(rule.domainName || rule.hostName || rule.baseUrl);
|
2019-05-24 15:40:39 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function matchesHostType(rule: HostRule, search: HostRuleSearch): boolean {
|
2019-05-24 15:40:39 +00:00
|
|
|
return rule.hostType === search.hostType;
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function matchesDomainName(rule: HostRule, search: HostRuleSearch): boolean {
|
2019-07-11 14:24:45 +00:00
|
|
|
const hostname = search.url && URL.parse(search.url).hostname;
|
2019-05-24 15:40:39 +00:00
|
|
|
return (
|
|
|
|
search.url &&
|
|
|
|
rule.domainName &&
|
2019-07-11 14:24:45 +00:00
|
|
|
hostname &&
|
|
|
|
hostname.endsWith(rule.domainName)
|
2019-05-24 15:40:39 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function matchesHostName(rule: HostRule, search: HostRuleSearch): boolean {
|
2019-05-24 15:40:39 +00:00
|
|
|
return (
|
|
|
|
search.url &&
|
|
|
|
rule.hostName &&
|
|
|
|
URL.parse(search.url).hostname === rule.hostName
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
function matchesBaseUrl(rule: HostRule, search: HostRuleSearch): boolean {
|
2019-05-24 15:40:39 +00:00
|
|
|
return search.url && rule.baseUrl && search.url.startsWith(rule.baseUrl);
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
export function find(search: HostRuleSearch): HostRule {
|
2019-05-24 15:40:39 +00:00
|
|
|
if (!(search.hostType || search.url)) {
|
|
|
|
logger.warn({ search }, 'Invalid hostRules search');
|
2019-05-25 05:49:26 +00:00
|
|
|
return {};
|
2018-09-13 04:48:08 +00:00
|
|
|
}
|
2019-05-24 15:40:39 +00:00
|
|
|
let res = ({} as any) as HostRule;
|
|
|
|
// First, apply empty rule matches
|
|
|
|
hostRules
|
2020-04-12 16:09:36 +00:00
|
|
|
.filter((rule) => isEmptyRule(rule))
|
|
|
|
.forEach((rule) => {
|
2019-05-24 15:40:39 +00:00
|
|
|
res = merge(res, rule);
|
|
|
|
});
|
|
|
|
// Next, find hostType-only matches
|
|
|
|
hostRules
|
2020-04-12 16:09:36 +00:00
|
|
|
.filter((rule) => isHostTypeRule(rule) && matchesHostType(rule, search))
|
|
|
|
.forEach((rule) => {
|
2019-05-24 15:40:39 +00:00
|
|
|
res = merge(res, rule);
|
|
|
|
});
|
|
|
|
// Next, find domainName-only matches
|
|
|
|
hostRules
|
2020-04-12 16:09:36 +00:00
|
|
|
.filter((rule) => isDomainNameRule(rule) && matchesDomainName(rule, search))
|
|
|
|
.forEach((rule) => {
|
2019-05-24 15:40:39 +00:00
|
|
|
res = merge(res, rule);
|
|
|
|
});
|
|
|
|
// Next, find hostName-only matches
|
|
|
|
hostRules
|
2020-04-12 16:09:36 +00:00
|
|
|
.filter((rule) => isHostNameRule(rule) && matchesHostName(rule, search))
|
|
|
|
.forEach((rule) => {
|
2019-05-24 15:40:39 +00:00
|
|
|
res = merge(res, rule);
|
|
|
|
});
|
|
|
|
// Next, find baseUrl-only matches
|
|
|
|
hostRules
|
2020-04-12 16:09:36 +00:00
|
|
|
.filter((rule) => isBaseUrlRule(rule) && matchesBaseUrl(rule, search))
|
|
|
|
.forEach((rule) => {
|
2019-05-24 15:40:39 +00:00
|
|
|
res = merge(res, rule);
|
|
|
|
});
|
|
|
|
// Finally, find combination matches
|
|
|
|
hostRules
|
|
|
|
.filter(
|
2020-04-12 16:09:36 +00:00
|
|
|
(rule) =>
|
2019-05-24 15:40:39 +00:00
|
|
|
isMultiRule(rule) &&
|
|
|
|
matchesHostType(rule, search) &&
|
|
|
|
(matchesDomainName(rule, search) ||
|
|
|
|
matchesHostName(rule, search) ||
|
|
|
|
matchesBaseUrl(rule, search))
|
|
|
|
)
|
2020-04-12 16:09:36 +00:00
|
|
|
.forEach((rule) => {
|
2019-05-24 15:40:39 +00:00
|
|
|
res = merge(res, rule);
|
|
|
|
});
|
|
|
|
delete res.hostType;
|
|
|
|
delete res.domainName;
|
|
|
|
delete res.hostName;
|
|
|
|
delete res.baseUrl;
|
2021-05-01 16:19:38 +00:00
|
|
|
delete res.resolvedHost;
|
2019-05-24 15:40:39 +00:00
|
|
|
return res;
|
2018-07-06 05:26:36 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
export function hosts({ hostType }: { hostType: string }): string[] {
|
2019-05-24 15:40:39 +00:00
|
|
|
return hostRules
|
2020-04-12 16:09:36 +00:00
|
|
|
.filter((rule) => rule.hostType === hostType)
|
|
|
|
.map((rule) => {
|
2020-03-17 11:15:22 +00:00
|
|
|
if (rule.hostName) {
|
|
|
|
return rule.hostName;
|
|
|
|
}
|
|
|
|
if (rule.baseUrl) {
|
|
|
|
return URL.parse(rule.baseUrl).hostname;
|
|
|
|
}
|
2019-05-24 15:40:39 +00:00
|
|
|
return null;
|
|
|
|
})
|
|
|
|
.filter(Boolean);
|
2018-07-06 05:26:36 +00:00
|
|
|
}
|
|
|
|
|
2020-02-11 13:37:35 +00:00
|
|
|
export function findAll({ hostType }: { hostType: string }): HostRule[] {
|
2020-04-12 16:09:36 +00:00
|
|
|
return hostRules.filter((rule) => rule.hostType === hostType);
|
2020-02-11 13:37:35 +00:00
|
|
|
}
|
|
|
|
|
2019-11-24 07:43:24 +00:00
|
|
|
export function clear(): void {
|
2021-04-20 08:52:38 +00:00
|
|
|
logger.debug('Clearing hostRules');
|
2019-05-24 15:40:39 +00:00
|
|
|
hostRules = [];
|
2019-09-12 10:48:31 +00:00
|
|
|
sanitize.clear();
|
2018-07-06 05:26:36 +00:00
|
|
|
}
|