2019-09-06 08:43:21 +02:00
|
|
|
/*
|
|
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
|
|
* or more contributor license agreements. Licensed under the Elastic License;
|
|
|
|
* you may not use this file except in compliance with the Elastic License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { i18n } from '@kbn/i18n';
|
2019-12-17 15:13:44 +01:00
|
|
|
import { tryCatch, map, mapNullable, getOrElse } from 'fp-ts/lib/Option';
|
2021-01-19 19:40:49 +01:00
|
|
|
import url from 'url';
|
2019-09-06 08:43:21 +02:00
|
|
|
import { curry } from 'lodash';
|
2019-09-06 22:40:51 +02:00
|
|
|
import { pipe } from 'fp-ts/lib/pipeable';
|
2019-09-06 08:43:21 +02:00
|
|
|
|
2021-01-28 19:44:25 +01:00
|
|
|
import { ActionsConfig } from './config';
|
2020-03-20 15:49:37 +01:00
|
|
|
import { ActionTypeDisabledError } from './lib';
|
2021-01-28 19:44:25 +01:00
|
|
|
import { ProxySettings } from './types';
|
2019-10-08 02:48:20 +02:00
|
|
|
|
2020-08-25 01:25:05 +02:00
|
|
|
export enum AllowedHosts {
|
2019-09-06 08:43:21 +02:00
|
|
|
Any = '*',
|
|
|
|
}
|
|
|
|
|
2019-12-17 15:13:44 +01:00
|
|
|
export enum EnabledActionTypes {
|
|
|
|
Any = '*',
|
|
|
|
}
|
|
|
|
|
2020-08-25 01:25:05 +02:00
|
|
|
enum AllowListingField {
|
2021-01-19 19:40:49 +01:00
|
|
|
URL = 'url',
|
2019-09-06 08:43:21 +02:00
|
|
|
hostname = 'hostname',
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface ActionsConfigurationUtilities {
|
2020-08-25 01:25:05 +02:00
|
|
|
isHostnameAllowed: (hostname: string) => boolean;
|
|
|
|
isUriAllowed: (uri: string) => boolean;
|
2019-12-17 15:13:44 +01:00
|
|
|
isActionTypeEnabled: (actionType: string) => boolean;
|
2020-08-25 01:25:05 +02:00
|
|
|
ensureHostnameAllowed: (hostname: string) => void;
|
|
|
|
ensureUriAllowed: (uri: string) => void;
|
2019-12-17 15:13:44 +01:00
|
|
|
ensureActionTypeEnabled: (actionType: string) => void;
|
2021-01-28 19:44:25 +01:00
|
|
|
isRejectUnauthorizedCertificatesEnabled: () => boolean;
|
|
|
|
getProxySettings: () => undefined | ProxySettings;
|
2019-09-06 08:43:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-25 01:25:05 +02:00
|
|
|
function allowListErrorMessage(field: AllowListingField, value: string) {
|
|
|
|
return i18n.translate('xpack.actions.urlAllowedHostsConfigurationError', {
|
2019-12-17 15:13:44 +01:00
|
|
|
defaultMessage:
|
2020-08-25 01:25:05 +02:00
|
|
|
'target {field} "{value}" is not added to the Kibana config xpack.actions.allowedHosts',
|
2019-09-06 08:43:21 +02:00
|
|
|
values: {
|
|
|
|
value,
|
|
|
|
field,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-17 15:13:44 +01:00
|
|
|
function disabledActionTypeErrorMessage(actionType: string) {
|
|
|
|
return i18n.translate('xpack.actions.disabledActionTypeError', {
|
|
|
|
defaultMessage:
|
|
|
|
'action type "{actionType}" is not enabled in the Kibana config xpack.actions.enabledActionTypes',
|
|
|
|
values: {
|
|
|
|
actionType,
|
|
|
|
},
|
|
|
|
});
|
2019-09-06 08:43:21 +02:00
|
|
|
}
|
|
|
|
|
2021-01-28 19:44:25 +01:00
|
|
|
function isAllowed({ allowedHosts }: ActionsConfig, hostname: string | null): boolean {
|
2020-08-25 01:25:05 +02:00
|
|
|
const allowed = new Set(allowedHosts);
|
|
|
|
if (allowed.has(AllowedHosts.Any)) return true;
|
2021-01-19 19:40:49 +01:00
|
|
|
if (hostname && allowed.has(hostname)) return true;
|
2019-12-17 15:13:44 +01:00
|
|
|
return false;
|
2019-09-06 08:43:21 +02:00
|
|
|
}
|
|
|
|
|
2021-01-28 19:44:25 +01:00
|
|
|
function isHostnameAllowedInUri(config: ActionsConfig, uri: string): boolean {
|
2019-09-06 22:40:51 +02:00
|
|
|
return pipe(
|
2021-01-19 19:40:49 +01:00
|
|
|
tryCatch(() => url.parse(uri)),
|
|
|
|
map((parsedUrl) => parsedUrl.hostname),
|
2020-08-25 01:25:05 +02:00
|
|
|
mapNullable((hostname) => isAllowed(config, hostname)),
|
2019-10-14 22:20:50 +02:00
|
|
|
getOrElse<boolean>(() => false)
|
2019-09-06 22:40:51 +02:00
|
|
|
);
|
2019-09-06 08:43:21 +02:00
|
|
|
}
|
|
|
|
|
2019-12-17 15:13:44 +01:00
|
|
|
function isActionTypeEnabledInConfig(
|
2021-01-28 19:44:25 +01:00
|
|
|
{ enabledActionTypes }: ActionsConfig,
|
2019-12-17 15:13:44 +01:00
|
|
|
actionType: string
|
|
|
|
): boolean {
|
|
|
|
const enabled = new Set(enabledActionTypes);
|
|
|
|
if (enabled.has(EnabledActionTypes.Any)) return true;
|
|
|
|
if (enabled.has(actionType)) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-28 19:44:25 +01:00
|
|
|
function getProxySettingsFromConfig(config: ActionsConfig): undefined | ProxySettings {
|
|
|
|
if (!config.proxyUrl) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
proxyUrl: config.proxyUrl,
|
|
|
|
proxyHeaders: config.proxyHeaders,
|
|
|
|
proxyRejectUnauthorizedCertificates: config.proxyRejectUnauthorizedCertificates,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-09-06 08:43:21 +02:00
|
|
|
export function getActionsConfigurationUtilities(
|
2021-01-28 19:44:25 +01:00
|
|
|
config: ActionsConfig
|
2019-09-06 08:43:21 +02:00
|
|
|
): ActionsConfigurationUtilities {
|
2020-08-25 01:25:05 +02:00
|
|
|
const isHostnameAllowed = curry(isAllowed)(config);
|
|
|
|
const isUriAllowed = curry(isHostnameAllowedInUri)(config);
|
2019-12-17 15:13:44 +01:00
|
|
|
const isActionTypeEnabled = curry(isActionTypeEnabledInConfig)(config);
|
2019-09-06 08:43:21 +02:00
|
|
|
return {
|
2020-08-25 01:25:05 +02:00
|
|
|
isHostnameAllowed,
|
|
|
|
isUriAllowed,
|
2019-12-17 15:13:44 +01:00
|
|
|
isActionTypeEnabled,
|
2021-01-28 19:44:25 +01:00
|
|
|
getProxySettings: () => getProxySettingsFromConfig(config),
|
|
|
|
isRejectUnauthorizedCertificatesEnabled: () => config.rejectUnauthorized,
|
2020-08-25 01:25:05 +02:00
|
|
|
ensureUriAllowed(uri: string) {
|
|
|
|
if (!isUriAllowed(uri)) {
|
2021-01-19 19:40:49 +01:00
|
|
|
throw new Error(allowListErrorMessage(AllowListingField.URL, uri));
|
2019-09-06 08:43:21 +02:00
|
|
|
}
|
|
|
|
},
|
2020-08-25 01:25:05 +02:00
|
|
|
ensureHostnameAllowed(hostname: string) {
|
|
|
|
if (!isHostnameAllowed(hostname)) {
|
|
|
|
throw new Error(allowListErrorMessage(AllowListingField.hostname, hostname));
|
2019-09-06 08:43:21 +02:00
|
|
|
}
|
|
|
|
},
|
2019-12-17 15:13:44 +01:00
|
|
|
ensureActionTypeEnabled(actionType: string) {
|
|
|
|
if (!isActionTypeEnabled(actionType)) {
|
2020-03-20 15:49:37 +01:00
|
|
|
throw new ActionTypeDisabledError(disabledActionTypeErrorMessage(actionType), 'config');
|
2019-12-17 15:13:44 +01:00
|
|
|
}
|
|
|
|
},
|
2019-09-06 08:43:21 +02:00
|
|
|
};
|
|
|
|
}
|