"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.replaceTemplateFieldFromQuery = exports.replaceTemplateFieldFromMatchFilters = exports.replaceTemplateFieldFromDataProviders = exports.reformatDataProviderWithNewValue = exports.getStringArray = exports.findValueToChangeInQuery = exports.buildTimeRangeFilter = void 0; var _fp = require("lodash/fp"); var _esQuery = require("@kbn/es-query"); var _timeline = require("../../../../common/api/timeline"); var _data_provider = require("../../../timelines/components/timeline/data_providers/data_provider"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ /** * Fields that will be replaced with the template strings from a a saved timeline template. * This is used for the alerts detection engine feature when you save a timeline template * and are the fields you can replace when creating a template. */ const templateFields = ['host.name', 'host.hostname', 'host.domain', 'host.id', 'host.ip', 'client.ip', 'destination.ip', 'server.ip', 'source.ip', 'network.community_id', 'user.name', 'process.name']; /** * This will return an unknown as a string array if it exists from an unknown data type and a string * that represents the path within the data object the same as lodash's "get". If the value is non-existent * we will return an empty array. If it is a non string value then this will log a trace to the console * that it encountered an error and return an empty array. * @param field string of the field to access * @param data The unknown data that is typically a ECS value to get the value * @param localConsole The local console which can be sent in to make this pure (for tests) or use the default console */ const getStringArray = (field, data, localConsole = console) => { var _data$find$values, _data$find; const value = (_data$find$values = (_data$find = data.find(d => d.field === field)) === null || _data$find === void 0 ? void 0 : _data$find.values) !== null && _data$find$values !== void 0 ? _data$find$values : null; if (value == null) { return []; } else if (typeof value === 'string') { return [value]; } else if (Array.isArray(value) && value.every(element => typeof element === 'string')) { return value; } else { localConsole.trace('Data type that is not a string or string array detected:', value, 'when trying to access field:', field, 'from data object of:', data); return []; } }; exports.getStringArray = getStringArray; const findValueToChangeInQuery = (kueryNode, valueToChange = []) => { let localValueToChange = valueToChange; if (kueryNode.function === 'is' && templateFields.includes(kueryNode.arguments[0].value)) { localValueToChange = [...localValueToChange, { field: kueryNode.arguments[0].value, valueToChange: kueryNode.arguments[1].value }]; } return kueryNode.arguments.reduce((addValueToChange, ast) => { if (ast.function === 'is' && templateFields.includes(ast.arguments[0].value)) { return [...addValueToChange, { field: ast.arguments[0].value, valueToChange: ast.arguments[1].value }]; } if (ast.arguments) { return findValueToChangeInQuery(ast, addValueToChange); } return addValueToChange; }, localValueToChange); }; exports.findValueToChangeInQuery = findValueToChangeInQuery; const replaceTemplateFieldFromQuery = (query, eventData, timelineType = _timeline.TimelineType.default) => { if (timelineType === _timeline.TimelineType.default) { if (query.trim() !== '') { const valueToChange = findValueToChangeInQuery((0, _esQuery.fromKueryExpression)(query)); return valueToChange.reduce((newQuery, vtc) => { const newValue = getStringArray(vtc.field, eventData); if (newValue.length) { return newQuery.replace(vtc.valueToChange, newValue[0]); } else { return newQuery; } }, query); } else { return ''; } } return query.trim(); }; exports.replaceTemplateFieldFromQuery = replaceTemplateFieldFromQuery; const replaceTemplateFieldFromMatchFilters = (filters, eventData) => filters.map(filter => { if (filter.meta.type === 'phrase' && filter.meta.key != null && templateFields.includes(filter.meta.key)) { const newValue = getStringArray(filter.meta.key, eventData); if (newValue.length) { filter.meta.params = { query: newValue[0] }; filter.query = { match_phrase: { [filter.meta.key]: newValue[0] } }; } } return filter; }); exports.replaceTemplateFieldFromMatchFilters = replaceTemplateFieldFromMatchFilters; const reformatDataProviderWithNewValue = (dataProvider, eventData, timelineType = _timeline.TimelineType.default) => { // Support for legacy "template-like" timeline behavior that is using hardcoded list of templateFields if (timelineType !== _timeline.TimelineType.template) { if (templateFields.includes(dataProvider.queryMatch.field)) { const newValue = getStringArray(dataProvider.queryMatch.field, eventData); if (newValue.length) { dataProvider.id = dataProvider.id.replace(dataProvider.name, newValue[0]); dataProvider.name = newValue[0]; dataProvider.queryMatch.value = newValue[0]; dataProvider.queryMatch.displayField = undefined; dataProvider.queryMatch.displayValue = undefined; } } dataProvider.type = _data_provider.DataProviderType.default; return dataProvider; } if (timelineType === _timeline.TimelineType.template) { var _dataProvider$type; if (dataProvider.type === _data_provider.DataProviderType.template && dataProvider.queryMatch.operator === ':') { const newValue = getStringArray(dataProvider.queryMatch.field, eventData); if (!newValue.length) { dataProvider.enabled = false; } dataProvider.id = dataProvider.id.replace(dataProvider.name, newValue[0]); dataProvider.name = newValue[0]; dataProvider.queryMatch.value = newValue[0]; dataProvider.queryMatch.displayField = undefined; dataProvider.queryMatch.displayValue = undefined; dataProvider.type = _data_provider.DataProviderType.default; return dataProvider; } dataProvider.type = (_dataProvider$type = dataProvider.type) !== null && _dataProvider$type !== void 0 ? _dataProvider$type : _data_provider.DataProviderType.default; return dataProvider; } return dataProvider; }; exports.reformatDataProviderWithNewValue = reformatDataProviderWithNewValue; const replaceTemplateFieldFromDataProviders = (dataProviders, eventData, timelineType = _timeline.TimelineType.default) => dataProviders.map(dataProvider => { const newDataProvider = reformatDataProviderWithNewValue(dataProvider, eventData, timelineType); if (newDataProvider.and != null && !(0, _fp.isEmpty)(newDataProvider.and)) { newDataProvider.and = newDataProvider.and.map(andDataProvider => reformatDataProviderWithNewValue(andDataProvider, eventData, timelineType)); } return newDataProvider; }); exports.replaceTemplateFieldFromDataProviders = replaceTemplateFieldFromDataProviders; const buildTimeRangeFilter = (from, to) => [{ range: { '@timestamp': { gte: from, lt: to, format: 'strict_date_optional_time' } }, meta: { type: 'range', disabled: false, negate: false, alias: null, key: '@timestamp', params: { gte: from, lt: to, format: 'strict_date_optional_time' } }, $state: { store: _esQuery.FilterStateStore.APP_STATE } }]; exports.buildTimeRangeFilter = buildTimeRangeFilter;