mirror of
https://github.com/valitydev/wazuh-kibana-app.git
synced 2024-11-07 10:18:57 +00:00
Merge pull request #1194 from wazuh/3.8-6.6
Update master branch (3.8.2-6.6.0)
This commit is contained in:
commit
84466b6ec6
@ -2,6 +2,11 @@
|
||||
|
||||
All notable changes to the Wazuh app project will be documented in this file.
|
||||
|
||||
## Wazuh v3.8.2 - Kibana v6.6.0 - Revision 419
|
||||
|
||||
### Added
|
||||
|
||||
- Support for Kibana v6.6.0
|
||||
|
||||
## Wazuh v3.8.2 - Kibana v6.5.4 - Revision 418
|
||||
|
||||
|
@ -27,15 +27,15 @@ Visualize and analyze Wazuh alerts stored in Elasticsearch using our Kibana app
|
||||
|
||||
- Wazuh HIDS 3.8.2
|
||||
- Wazuh RESTful API 3.8.2
|
||||
- Kibana 6.5.4
|
||||
- Elasticsearch 6.5.4
|
||||
- Kibana 6.6.0
|
||||
- Elasticsearch 6.6.0
|
||||
|
||||
## Installation
|
||||
|
||||
Install the app
|
||||
|
||||
```
|
||||
sudo -u kibana NODE_OPTIONS="--max-old-space-size=3072" /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.2_6.5.4.zip
|
||||
sudo -u kibana NODE_OPTIONS="--max-old-space-size=3072" /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.2_6.6.0.zip
|
||||
```
|
||||
|
||||
Restart Kibana
|
||||
@ -90,7 +90,7 @@ chown -R kibana:kibana /usr/share/kibana/plugins
|
||||
Install the app
|
||||
|
||||
```
|
||||
sudo -u kibana NODE_OPTIONS="--max-old-space-size=3072" /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.2_6.5.4.zip
|
||||
sudo -u kibana NODE_OPTIONS="--max-old-space-size=3072" /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.2_6.6.0.zip
|
||||
```
|
||||
|
||||
Restart Kibana
|
||||
@ -159,6 +159,7 @@ service kibana restart
|
||||
| 6.5.4 | 3.8.0 | /usr/share/kibana/bin/kibana-plugin install <https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.0_6.5.4.zip> |
|
||||
| 6.5.4 | 3.8.1 | /usr/share/kibana/bin/kibana-plugin install <https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.1_6.5.4.zip> |
|
||||
| 6.5.4 | 3.8.2 | /usr/share/kibana/bin/kibana-plugin install <https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.2_6.5.4.zip> |
|
||||
| 6.6.0 | 3.8.2 | /usr/share/kibana/bin/kibana-plugin install <https://packages.wazuh.com/wazuhapp/wazuhapp-3.8.2_6.5.4.zip> |
|
||||
|
||||
|
||||
## Contribute
|
||||
|
@ -1,13 +1,10 @@
|
||||
{
|
||||
"name": "wazuh",
|
||||
"version": "3.8.2",
|
||||
"revision": "0418",
|
||||
"code": "0418-0",
|
||||
"revision": "0419",
|
||||
"code": "0419-0",
|
||||
"kibana": {
|
||||
"version": "6.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "8.14.0"
|
||||
"version": "6.6.0"
|
||||
},
|
||||
"description": "Wazuh app",
|
||||
"main": "index.js",
|
||||
|
@ -26,7 +26,6 @@ app.directive('wzXmlFileEditor', function() {
|
||||
targetName: '=targetName'
|
||||
},
|
||||
controller($scope, $document, errorHandler, groupHandler) {
|
||||
|
||||
/**
|
||||
* Custom .replace method. Instead of using .replace which
|
||||
* evaluates regular expressions.
|
||||
@ -90,11 +89,14 @@ app.directive('wzXmlFileEditor', function() {
|
||||
return;
|
||||
};
|
||||
|
||||
const autoFormat = (xml) => {
|
||||
const autoFormat = xml => {
|
||||
var reg = /(>)\s*(<)(\/*)/g;
|
||||
var wsexp = / *(.*) +\n/g;
|
||||
var contexp = /(<.+>)(.+\n)/g;
|
||||
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
|
||||
xml = xml
|
||||
.replace(reg, '$1\n$2$3')
|
||||
.replace(wsexp, '$1\n')
|
||||
.replace(contexp, '$1\n$2');
|
||||
var formatted = '';
|
||||
var lines = xml.split('\n');
|
||||
var indent = 0;
|
||||
@ -121,13 +123,19 @@ app.directive('wzXmlFileEditor', function() {
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var ln = lines[i];
|
||||
if (ln.match(/\s*<\?xml/)) {
|
||||
formatted += ln + "\n";
|
||||
formatted += ln + '\n';
|
||||
continue;
|
||||
}
|
||||
var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. <br />
|
||||
var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex. </a>
|
||||
var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that's not <!something>)
|
||||
var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other';
|
||||
var type = single
|
||||
? 'single'
|
||||
: closing
|
||||
? 'closing'
|
||||
: opening
|
||||
? 'opening'
|
||||
: 'other';
|
||||
var fromTo = lastType + '->' + type;
|
||||
lastType = type;
|
||||
var padding = '';
|
||||
@ -137,9 +145,9 @@ app.directive('wzXmlFileEditor', function() {
|
||||
padding += '\t';
|
||||
}
|
||||
if (fromTo == 'opening->closing')
|
||||
formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; // substr removes line break (\n) from prev loop
|
||||
else
|
||||
formatted += padding + ln + '\n';
|
||||
formatted = formatted.substr(0, formatted.length - 1) + ln + '\n';
|
||||
// substr removes line break (\n) from prev loop
|
||||
else formatted += padding + ln + '\n';
|
||||
}
|
||||
return formatted.trim();
|
||||
};
|
||||
@ -150,7 +158,7 @@ app.directive('wzXmlFileEditor', function() {
|
||||
const xml = replaceIllegalXML(text);
|
||||
await groupHandler.sendConfiguration(params.group, xml);
|
||||
errorHandler.info('Success. Group has been updated', '');
|
||||
$scope.$emit('configurationSuccess')
|
||||
$scope.$emit('configurationSuccess');
|
||||
} catch (error) {
|
||||
errorHandler.handle(error, 'Send file error');
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* Find more information about this on the LICENSE file.
|
||||
*/
|
||||
import dateMath from '@kbn/datemath';
|
||||
import dateMath from '@elastic/datemath';
|
||||
|
||||
export class VisHandlers {
|
||||
/**
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { capitalize, isArray, isFunction } from 'lodash';
|
||||
import { capitalize, isArray, isFunction, get } from 'lodash';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import filterTemplate from 'ui/chrome/config/filter.html';
|
||||
import intervalTemplate from 'ui/chrome/config/interval.html';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function KbnTopNavControllerProvider($compile) {
|
||||
return class KbnTopNavController {
|
||||
@ -75,18 +76,25 @@ export function KbnTopNavControllerProvider($compile) {
|
||||
getItem = key => {
|
||||
return this.menuItems.find(i => i.key === key);
|
||||
};
|
||||
handleClick = menuItem => {
|
||||
handleClick = (menuItem, event) => {
|
||||
if (menuItem.disableButton()) {
|
||||
return false;
|
||||
}
|
||||
menuItem.run(menuItem, this);
|
||||
// event will be undefined when method is called from click
|
||||
menuItem.run(menuItem, this, get(event, 'target'));
|
||||
};
|
||||
// apply the defaults to individual options
|
||||
_applyOptDefault(opt = {}) {
|
||||
const optLabel = opt.label ? opt.label : capitalize(opt.key);
|
||||
const defaultedOpt = {
|
||||
label: capitalize(opt.key),
|
||||
label: optLabel,
|
||||
hasFunction: !!opt.run,
|
||||
description: opt.run ? opt.key : `Toggle ${opt.key} view`,
|
||||
description: opt.run
|
||||
? optLabel
|
||||
: i18n.translate('common.ui.topNav.toggleViewAriaLabel', {
|
||||
defaultMessage: 'Toggle {optLabel} view',
|
||||
values: { optLabel }
|
||||
}),
|
||||
run: item => this.toggle(item.key),
|
||||
...opt
|
||||
};
|
||||
|
@ -27,7 +27,6 @@ import 'plugins/kibana/discover/directives/timechart';
|
||||
import 'ui/collapsible_sidebar';
|
||||
import 'plugins/kibana/discover/components/field_chooser/field_chooser';
|
||||
import 'plugins/kibana/discover/controllers/discover';
|
||||
//import 'plugins/kibana/discover/styles/main.less';
|
||||
import 'ui/doc_table/components/table_row';
|
||||
|
||||
// Research added (further checks needed)
|
||||
@ -48,11 +47,13 @@ import 'ui/pager';
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import _ from 'lodash';
|
||||
//import React from 'react';
|
||||
import angular from 'angular';
|
||||
import chrome from 'ui/chrome';
|
||||
import { getSort } from 'ui/doc_table/lib/get_sort';
|
||||
import * as columnActions from 'ui/doc_table/actions/columns';
|
||||
import * as filterActions from 'ui/doc_table/actions/filter';
|
||||
import dateMath from '@kbn/datemath';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import 'ui/doc_table';
|
||||
import 'ui/visualize';
|
||||
import 'ui/fixed_scroll';
|
||||
@ -61,7 +62,6 @@ import 'ui/filters/moment';
|
||||
import 'ui/index_patterns';
|
||||
import 'ui/state_management/app_state';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import 'ui/share';
|
||||
import 'ui/query_bar';
|
||||
import {
|
||||
hasSearchStategyForIndexPattern,
|
||||
@ -73,13 +73,16 @@ import { VislibSeriesResponseHandlerProvider } from 'ui/vis/response_handlers/vi
|
||||
import { DocTitleProvider } from 'ui/doc_title';
|
||||
import PluginsKibanaDiscoverHitSortFnProvider from 'plugins/kibana/discover/_hit_sort_fn';
|
||||
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
|
||||
// No need for this since we are using custom interval options
|
||||
//import { intervalOptions } from 'ui/agg_types/buckets/_interval_options';
|
||||
import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
|
||||
import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery';
|
||||
import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
|
||||
import { FilterManagerProvider } from 'ui/filter_manager';
|
||||
import { visualizationLoader } from 'ui/visualize/loader/visualization_loader';
|
||||
import { getDocLink } from 'ui/documentation_links';
|
||||
import { VisualizeLoaderProvider } from './loader';
|
||||
import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
|
||||
import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing';
|
||||
//import { Inspector } from 'ui/inspector';
|
||||
import { RequestAdapter } from 'ui/inspector/adapters';
|
||||
import {
|
||||
getRequestInspectorStats,
|
||||
@ -117,16 +120,19 @@ function discoverController(
|
||||
Promise,
|
||||
config,
|
||||
courier,
|
||||
$rootScope,
|
||||
$location,
|
||||
kbnUrl,
|
||||
localStorage,
|
||||
breadcrumbState,
|
||||
i18n,
|
||||
// Wazuh requirements from here
|
||||
$rootScope,
|
||||
$location,
|
||||
getAppState,
|
||||
globalState,
|
||||
loadedVisualizations,
|
||||
discoverPendingUpdates
|
||||
) {
|
||||
const visualizeLoader = Private(VisualizeLoaderProvider);
|
||||
let visualizeHandler;
|
||||
const Vis = Private(VisProvider);
|
||||
const docTitle = Private(DocTitleProvider);
|
||||
const HitSortFn = Private(PluginsKibanaDiscoverHitSortFnProvider);
|
||||
@ -136,7 +142,6 @@ function discoverController(
|
||||
const notify = new Notifier({
|
||||
location: 'Discover'
|
||||
});
|
||||
|
||||
const getUnhashableStates = Private(getUnhashableStatesProvider);
|
||||
const shareContextMenuExtensions = Private(
|
||||
ShareContextMenuExtensionsRegistryProvider
|
||||
@ -155,8 +160,8 @@ function discoverController(
|
||||
const to = dateMath.parse(timefilter.getTime().to);
|
||||
|
||||
const totalSeconds = (to - from) / 1000;
|
||||
if (totalSeconds <= 3600) wzInterval = 'm';
|
||||
else if (totalSeconds > 3600 && totalSeconds <= 86400) wzInterval = 'h';
|
||||
if (totalSeconds <= 14401) wzInterval = 'm';
|
||||
else if (totalSeconds > 14401 && totalSeconds <= 86400) wzInterval = 'h';
|
||||
else if (totalSeconds > 86400 && totalSeconds <= 604800) wzInterval = 'd';
|
||||
else if (totalSeconds > 604800 && totalSeconds <= 2419200)
|
||||
wzInterval = 'w';
|
||||
@ -266,14 +271,27 @@ function discoverController(
|
||||
const pageTitleSuffix =
|
||||
savedSearch.id && savedSearch.title ? `: ${savedSearch.title}` : '';
|
||||
docTitle.change(`Discover${pageTitleSuffix}`);
|
||||
const discoverBreadcrumbsTitle = i18n(
|
||||
'kbn.discover.discoverBreadcrumbTitle',
|
||||
{
|
||||
defaultMessage: 'Discover'
|
||||
}
|
||||
);
|
||||
|
||||
if (savedSearch.id && savedSearch.title) {
|
||||
breadcrumbState.set([
|
||||
{ text: 'Discover', href: '#/discover' },
|
||||
chrome.breadcrumbs.set([
|
||||
{
|
||||
text: discoverBreadcrumbsTitle,
|
||||
href: '#/discover'
|
||||
},
|
||||
{ text: savedSearch.title }
|
||||
]);
|
||||
} else {
|
||||
breadcrumbState.set([{ text: 'Discover' }]);
|
||||
chrome.breadcrumbs.set([
|
||||
{
|
||||
text: discoverBreadcrumbsTitle
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
let stateMonitor;
|
||||
@ -381,14 +399,22 @@ function discoverController(
|
||||
$state.sort = getSort.array($state.sort, $scope.indexPattern);
|
||||
|
||||
$scope.getBucketIntervalToolTipText = () => {
|
||||
return `This interval creates ${
|
||||
return i18n('kbn.discover.bucketIntervalTooltip', {
|
||||
// eslint-disable-next-line max-len
|
||||
defaultMessage:
|
||||
'This interval creates {bucketsDescription} to show in the selected time range, so it has been scaled to {bucketIntervalDescription}',
|
||||
values: {
|
||||
bucketsDescription:
|
||||
$scope.bucketInterval.scale > 1
|
||||
? 'buckets that are too large'
|
||||
: 'too many buckets'
|
||||
? i18n('kbn.discover.bucketIntervalTooltip.tooLargeBucketsText', {
|
||||
defaultMessage: 'buckets that are too large'
|
||||
})
|
||||
: i18n('kbn.discover.bucketIntervalTooltip.tooManyBucketsText', {
|
||||
defaultMessage: 'too many buckets'
|
||||
}),
|
||||
bucketIntervalDescription: $scope.bucketInterval.description
|
||||
}
|
||||
to show in the selected time range, so it has been scaled to ${
|
||||
$scope.bucketInterval.description
|
||||
}`;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watchCollection('state.columns', function() {
|
||||
@ -562,52 +588,20 @@ function discoverController(
|
||||
});
|
||||
});
|
||||
|
||||
async function saveDataSource(saveOptions) {
|
||||
await $scope.updateDataSource();
|
||||
|
||||
savedSearch.columns = $scope.state.columns;
|
||||
savedSearch.sort = $scope.state.sort;
|
||||
|
||||
try {
|
||||
const id = await savedSearch.save(saveOptions);
|
||||
$scope.$evalAsync(() => {
|
||||
stateMonitor.setInitialState($state.toJSON());
|
||||
if (id) {
|
||||
toastNotifications.addSuccess({
|
||||
title: `Search '${savedSearch.title}' was saved`,
|
||||
'data-test-subj': 'saveSearchSuccess'
|
||||
});
|
||||
|
||||
if (savedSearch.id !== $route.current.params.id) {
|
||||
kbnUrl.change('/discover/{{id}}', { id: savedSearch.id });
|
||||
} else {
|
||||
// Update defaults so that "reload saved query" functions correctly
|
||||
$state.setDefaults(getStateDefaults());
|
||||
docTitle.change(savedSearch.lastSavedTitle);
|
||||
}
|
||||
}
|
||||
});
|
||||
return { id };
|
||||
} catch (saveError) {
|
||||
toastNotifications.addDanger({
|
||||
title: `Search '${savedSearch.title}' was not saved.`,
|
||||
text: saveError.message
|
||||
});
|
||||
return { error: saveError };
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Wazuh - Removed saveDataSource, it's not needed by our integration //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Wazuh - aux function for checking filters status
|
||||
*/
|
||||
const filtersAreReady = () => {
|
||||
const currentUrlPath = $location.path();
|
||||
if (currentUrlPath && !currentUrlPath.includes('wazuh-discover')) {
|
||||
let filters = queryFilter.getFilters();
|
||||
filters = Array.isArray(filters)
|
||||
? filters.filter(
|
||||
item =>
|
||||
item &&
|
||||
item.$state &&
|
||||
item.$state.store &&
|
||||
item.$state.store === 'appState'
|
||||
item => (((item || {}).$state || {}).store || '') === 'appState'
|
||||
)
|
||||
: [];
|
||||
if (!filters || !filters.length) return false;
|
||||
@ -640,10 +634,6 @@ function discoverController(
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////// WAZUH ///////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// We don't need this cause the auto-complete feature breaks using this //
|
||||
/*if ($state.query.language && $state.query.language !== query.language) {
|
||||
$state.filters = [];
|
||||
}*/
|
||||
// Wazuh filters are not ready yet
|
||||
if (!filtersAreReady()) return;
|
||||
|
||||
@ -695,6 +685,8 @@ function discoverController(
|
||||
sortFn = new HitSortFn(sort[1]);
|
||||
}
|
||||
|
||||
$scope.updateTime();
|
||||
|
||||
if (sort[0] === '_score') {
|
||||
segmented.setMaxSegments(1);
|
||||
}
|
||||
@ -724,9 +716,23 @@ function discoverController(
|
||||
|
||||
if (status.remaining > 0) {
|
||||
const inspectorRequest = inspectorAdapters.requests.start(
|
||||
`Segment ${$scope.fetchStatus.complete}`,
|
||||
i18n(
|
||||
'kbn.discover.inspectorRequest.segmentFetchCompleteStatusTitle',
|
||||
{
|
||||
description: `This request queries Elasticsearch to fetch the data for the search.`
|
||||
defaultMessage: 'Segment {fetchCompleteStatus}',
|
||||
values: {
|
||||
fetchCompleteStatus: $scope.fetchStatus.complete
|
||||
}
|
||||
}
|
||||
),
|
||||
{
|
||||
description: i18n(
|
||||
'kbn.discover.inspectorRequest.segmentFetchCompleteStatusDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'This request queries Elasticsearch to fetch the data for the search.'
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
inspectorRequest.stats(getRequestInspectorStats($scope.searchSource));
|
||||
@ -762,20 +768,8 @@ function discoverController(
|
||||
const tabifiedData = tabifyAggResponse($scope.vis.aggs, merged);
|
||||
$scope.searchSource.rawResponse = merged;
|
||||
Promise.resolve(responseHandler(tabifiedData)).then(resp => {
|
||||
$scope.visData = resp;
|
||||
if (
|
||||
($scope.tabView !== 'panels' ||
|
||||
$location.path().includes('wazuh-discover')) &&
|
||||
$scope.tabView !== 'cluster-monitoring'
|
||||
) {
|
||||
const visEl = $element.find('#discoverHistogram')[0];
|
||||
visualizationLoader.render(
|
||||
visEl,
|
||||
$scope.vis,
|
||||
$scope.visData,
|
||||
$scope.uiState,
|
||||
{ listenOnChange: true }
|
||||
);
|
||||
if (visualizeHandler) {
|
||||
visualizeHandler.render(resp);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -922,10 +916,10 @@ function discoverController(
|
||||
$scope.minimumVisibleRows = $scope.hits;
|
||||
};
|
||||
|
||||
function setupVisualization() {
|
||||
async function setupVisualization() {
|
||||
// If no timefield has been specified we don't create a histogram of messages
|
||||
if (!$scope.opts.timefield) return;
|
||||
|
||||
$state.interval = calcWzInterval() || 'h';
|
||||
const visStateAggs = [
|
||||
{
|
||||
type: 'count',
|
||||
@ -946,18 +940,28 @@ function discoverController(
|
||||
if ($scope.vis) {
|
||||
const visState = $scope.vis.getEnabledState();
|
||||
visState.aggs = visStateAggs;
|
||||
|
||||
$scope.vis.setState(visState);
|
||||
} else {
|
||||
$scope.vis = new Vis($scope.indexPattern, {
|
||||
title: savedSearch.title,
|
||||
return;
|
||||
}
|
||||
|
||||
const visSavedObject = {
|
||||
indexPattern: $scope.indexPattern.id,
|
||||
visState: {
|
||||
type: 'histogram',
|
||||
title: savedSearch.title,
|
||||
params: {
|
||||
addLegend: false,
|
||||
addTimeMarker: true
|
||||
},
|
||||
aggs: visStateAggs
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.vis = new Vis(
|
||||
$scope.searchSource.getField('index'),
|
||||
visSavedObject.visState
|
||||
);
|
||||
visSavedObject.vis = $scope.vis;
|
||||
|
||||
$scope.searchSource.onRequestStart((searchSource, searchRequest) => {
|
||||
return $scope.vis
|
||||
@ -971,23 +975,23 @@ function discoverController(
|
||||
// return $scope.vis.getAggConfig().toDsl(); //
|
||||
///////////////////////////////////////////////////////////
|
||||
const result = $scope.vis.getAggConfig().toDsl();
|
||||
if (
|
||||
result[2] &&
|
||||
result[2].date_histogram &&
|
||||
result[2].date_histogram.interval === '0ms'
|
||||
) {
|
||||
if (((result[2] || {}).date_histogram || {}).interval === '0ms') {
|
||||
result[2].date_histogram.interval = '1d';
|
||||
}
|
||||
return result;
|
||||
///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
});
|
||||
}
|
||||
|
||||
$scope.vis.filters = {
|
||||
timeRange: timefilter.getTime()
|
||||
};
|
||||
$timeout(async () => {
|
||||
const visEl = $element.find('#discoverHistogram')[0];
|
||||
visualizeHandler = await visualizeLoader.embedVisualizationWithSavedObject(
|
||||
visEl,
|
||||
visSavedObject,
|
||||
{
|
||||
autoFetch: false
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function resolveIndexPatternLoading() {
|
||||
@ -1004,23 +1008,47 @@ function discoverController(
|
||||
}
|
||||
|
||||
if (stateVal && !stateValFound) {
|
||||
const warningTitle = `"${stateVal}" is not a configured index pattern ID`;
|
||||
const warningTitle = i18n(
|
||||
'kbn.discover.valueIsNotConfiguredIndexPatternIDWarningTitle',
|
||||
{
|
||||
defaultMessage: '{stateVal} is not a configured index pattern ID',
|
||||
values: {
|
||||
stateVal: `"${stateVal}"`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (ownIndexPattern) {
|
||||
toastNotifications.addWarning({
|
||||
title: warningTitle,
|
||||
text: `Showing the saved index pattern: "${ownIndexPattern.title}" (${
|
||||
ownIndexPattern.id
|
||||
})`
|
||||
text: i18n(
|
||||
'kbn.discover.showingSavedIndexPatternWarningDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Showing the saved index pattern: "{ownIndexPatternTitle}" ({ownIndexPatternId})',
|
||||
values: {
|
||||
ownIndexPatternTitle: ownIndexPattern.title,
|
||||
ownIndexPatternId: ownIndexPattern.id
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
return ownIndexPattern;
|
||||
}
|
||||
|
||||
toastNotifications.addWarning({
|
||||
title: warningTitle,
|
||||
text: `Showing the default index pattern: "${
|
||||
loadedIndexPattern.title
|
||||
}" (${loadedIndexPattern.id})`
|
||||
text: i18n(
|
||||
'kbn.discover.showingDefaultIndexPatternWarningDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Showing the default index pattern: "{loadedIndexPatternTitle}" ({loadedIndexPatternId})',
|
||||
values: {
|
||||
loadedIndexPatternTitle: loadedIndexPattern.title,
|
||||
loadedIndexPatternId: loadedIndexPattern.id
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -18,24 +18,28 @@
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce, forEach } from 'lodash';
|
||||
import * as Rx from 'rxjs';
|
||||
import { share } from 'rxjs/operators';
|
||||
|
||||
import { Inspector } from 'ui/inspector';
|
||||
import { Adapters } from 'ui/inspector/types';
|
||||
import { PersistedState } from 'ui/persisted_state';
|
||||
import { IPrivate } from 'ui/private';
|
||||
import { RenderCompleteHelper } from 'ui/render_complete';
|
||||
import { AppState } from 'ui/state_management/app_state';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { RequestHandlerParams, Vis } from 'ui/vis';
|
||||
import { VisSavedObject, VisualizeLoaderParams, VisualizeUpdateParams } from './types';
|
||||
import { visualizationLoader } from './visualization_loader';
|
||||
import { VisualizeDataLoader } from './visualize_data_loader';
|
||||
|
||||
import { DataAdapter, RequestAdapter } from 'ui/inspector/adapters';
|
||||
|
||||
import { VisSavedObject, VisualizeLoaderParams, VisualizeUpdateParams } from './types';
|
||||
|
||||
interface EmbeddedVisualizeHandlerParams extends VisualizeLoaderParams {
|
||||
Private: IPrivate;
|
||||
queryFilter: any;
|
||||
autoFetch?: boolean;
|
||||
}
|
||||
|
||||
const RENDER_COMPLETE_EVENT = 'render_complete';
|
||||
@ -46,7 +50,15 @@ const LOADING_ATTRIBUTE = 'data-loading';
|
||||
* with the visualization.
|
||||
*/
|
||||
export class EmbeddedVisualizeHandler {
|
||||
/**
|
||||
* This observable will emit every time new data is loaded for the
|
||||
* visualization. The emitted value is the loaded data after it has
|
||||
* been transformed by the visualization's response handler.
|
||||
* This should not be used by any plugin.
|
||||
* @ignore
|
||||
*/
|
||||
public readonly data$: Rx.Observable<any>;
|
||||
public readonly inspectorAdapters: Adapters = {};
|
||||
private vis: Vis;
|
||||
private loaded: boolean = false;
|
||||
private destroyed: boolean = false;
|
||||
@ -54,7 +66,6 @@ export class EmbeddedVisualizeHandler {
|
||||
private listeners = new EventEmitter();
|
||||
private firstRenderComplete: Promise<void>;
|
||||
private renderCompleteHelper: RenderCompleteHelper;
|
||||
//private onRenderCompleteListener: () => void;
|
||||
private shouldForceNextFetch: boolean = false;
|
||||
private debouncedFetchAndRender = debounce(() => {
|
||||
if (this.destroyed) {
|
||||
@ -70,8 +81,10 @@ export class EmbeddedVisualizeHandler {
|
||||
private readonly appState?: AppState;
|
||||
private uiState: PersistedState;
|
||||
private dataLoader: VisualizeDataLoader;
|
||||
|
||||
private dataSubject: Rx.Subject<any>;
|
||||
private actions: any = {};
|
||||
private events$: Rx.Observable<any>;
|
||||
private autoFetch: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly element: HTMLElement,
|
||||
@ -80,7 +93,16 @@ export class EmbeddedVisualizeHandler {
|
||||
) {
|
||||
const { searchSource, vis } = savedObject;
|
||||
|
||||
const { appState, uiState, queryFilter, timeRange, filters, query, Private } = params;
|
||||
const {
|
||||
appState,
|
||||
uiState,
|
||||
queryFilter,
|
||||
timeRange,
|
||||
filters,
|
||||
query,
|
||||
Private,
|
||||
autoFetch,
|
||||
} = params;
|
||||
|
||||
this.dataLoaderParams = {
|
||||
searchSource,
|
||||
@ -93,6 +115,8 @@ export class EmbeddedVisualizeHandler {
|
||||
forceFetch: false,
|
||||
};
|
||||
|
||||
this.autoFetch = !(autoFetch === false);
|
||||
|
||||
// Listen to the first RENDER_COMPLETE_EVENT to resolve this promise
|
||||
this.firstRenderComplete = new Promise(resolve => {
|
||||
this.listeners.once(RENDER_COMPLETE_EVENT, resolve);
|
||||
@ -115,6 +139,26 @@ export class EmbeddedVisualizeHandler {
|
||||
|
||||
this.dataLoader = new VisualizeDataLoader(vis, Private);
|
||||
this.renderCompleteHelper = new RenderCompleteHelper(element);
|
||||
this.inspectorAdapters = this.getActiveInspectorAdapters();
|
||||
this.vis.openInspector = this.openInspector;
|
||||
this.vis.hasInspector = this.hasInspector;
|
||||
|
||||
// init default actions
|
||||
forEach(this.vis.type.events, (event, eventName) => {
|
||||
if (event.disabled || !eventName) {
|
||||
return;
|
||||
} else {
|
||||
this.actions[eventName] = event.defaultAction;
|
||||
}
|
||||
});
|
||||
|
||||
this.vis.eventsSubject = new Rx.Subject();
|
||||
this.events$ = this.vis.eventsSubject.asObservable().pipe(share());
|
||||
this.events$.subscribe(event => {
|
||||
if (this.actions[event.name]) {
|
||||
this.actions[event.name](event.data);
|
||||
}
|
||||
});
|
||||
|
||||
this.dataSubject = new Rx.Subject();
|
||||
this.data$ = this.dataSubject.asObservable().pipe(share());
|
||||
@ -187,14 +231,39 @@ export class EmbeddedVisualizeHandler {
|
||||
return this.element;
|
||||
}
|
||||
|
||||
/**
|
||||
* renders visualization with provided data
|
||||
* @param visData: visualization data
|
||||
*/
|
||||
public render = (visData: any = null) => {
|
||||
return visualizationLoader
|
||||
.render(this.element, this.vis, visData, this.uiState, {
|
||||
listenOnChange: false,
|
||||
})
|
||||
.then(() => {
|
||||
if (!this.loaded) {
|
||||
this.loaded = true;
|
||||
if (this.autoFetch) {
|
||||
this.fetchAndRender();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the inspector for the embedded visualization. This will return an
|
||||
* handler to the inspector to close and interact with it.
|
||||
* @return An inspector session to interact with the opened inspector.
|
||||
*/
|
||||
public openInspector(): ReturnType<typeof Inspector.open> {
|
||||
return this.vis.openInspector();
|
||||
}
|
||||
public openInspector = () => {
|
||||
return Inspector.open(this.inspectorAdapters, {
|
||||
title: this.vis.title,
|
||||
});
|
||||
};
|
||||
|
||||
public hasInspector = () => {
|
||||
return Inspector.isAvailable(this.inspectorAdapters);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a promise, that will resolve (without a value) once the first rendering of
|
||||
@ -229,6 +298,13 @@ export class EmbeddedVisualizeHandler {
|
||||
this.listeners.removeListener(RENDER_COMPLETE_EVENT, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the fetch of new data and renders the chart again.
|
||||
*/
|
||||
public reload = () => {
|
||||
this.fetchAndRender(true);
|
||||
};
|
||||
|
||||
private onRenderCompleteListener = () => {
|
||||
this.listeners.emit(RENDER_COMPLETE_EVENT);
|
||||
this.element.removeAttribute(LOADING_ATTRIBUTE);
|
||||
@ -238,6 +314,41 @@ export class EmbeddedVisualizeHandler {
|
||||
this.fetchAndRender();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an object of all inspectors for this vis object.
|
||||
* This must only be called after this.type has properly be initialized,
|
||||
* since we need to read out data from the the vis type to check which
|
||||
* inspectors are available.
|
||||
*/
|
||||
private getActiveInspectorAdapters = (): Adapters => {
|
||||
const adapters: Adapters = {};
|
||||
const { inspectorAdapters: typeAdapters } = this.vis.type;
|
||||
|
||||
// Add the requests inspector adapters if the vis type explicitly requested it via
|
||||
// inspectorAdapters.requests: true in its definition or if it's using the courier
|
||||
// request handler, since that will automatically log its requests.
|
||||
if ((typeAdapters && typeAdapters.requests) || this.vis.type.requestHandler === 'courier') {
|
||||
adapters.requests = new RequestAdapter();
|
||||
}
|
||||
|
||||
// Add the data inspector adapter if the vis type requested it or if the
|
||||
// vis is using courier, since we know that courier supports logging
|
||||
// its data.
|
||||
if ((typeAdapters && typeAdapters.data) || this.vis.type.requestHandler === 'courier') {
|
||||
adapters.data = new DataAdapter();
|
||||
}
|
||||
|
||||
// Add all inspectors, that are explicitly registered with this vis type
|
||||
if (typeAdapters && typeAdapters.custom) {
|
||||
Object.entries(typeAdapters.custom).forEach(([key, Adapter]) => {
|
||||
adapters[key] = new (Adapter as any)();
|
||||
});
|
||||
}
|
||||
|
||||
return adapters;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches new data and renders the chart. This will happen debounced for a couple
|
||||
* of milliseconds, to bundle fast successive calls into one fetch and render,
|
||||
@ -263,33 +374,14 @@ export class EmbeddedVisualizeHandler {
|
||||
this.fetchAndRender();
|
||||
};
|
||||
|
||||
/**
|
||||
* Force the fetch of new data and renders the chart again.
|
||||
*/
|
||||
private reload = () => {
|
||||
this.fetchAndRender(true);
|
||||
};
|
||||
|
||||
private fetch = (forceFetch: boolean = false) => {
|
||||
this.dataLoaderParams.aggs = this.vis.getAggConfig();
|
||||
this.dataLoaderParams.forceFetch = forceFetch;
|
||||
this.dataLoaderParams.inspectorAdapters = this.inspectorAdapters;
|
||||
|
||||
return this.dataLoader.fetch(this.dataLoaderParams).then(data => {
|
||||
this.dataSubject.next(data);
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
private render = (visData: any = null) => {
|
||||
return visualizationLoader
|
||||
.render(this.element, this.vis, visData, this.uiState, {
|
||||
listenOnChange: false,
|
||||
})
|
||||
.then(() => {
|
||||
if (!this.loaded) {
|
||||
this.loaded = true;
|
||||
this.fetchAndRender();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ export interface TimeRange {
|
||||
to: string;
|
||||
}
|
||||
|
||||
export interface FilterMeta {
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export interface Filter {
|
||||
meta: object;
|
||||
query: object;
|
||||
@ -48,6 +52,9 @@ export interface VisSavedObject {
|
||||
vis: Vis;
|
||||
description?: string;
|
||||
searchSource: SearchSource;
|
||||
title: string;
|
||||
uiStateJSON?: string;
|
||||
destroy: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,11 +73,34 @@ export class VisualizeDataLoader {
|
||||
this.vis.showRequestError = false;
|
||||
|
||||
try {
|
||||
// Vis types that have a `showMetricsAtAllLevels` param (e.g. data table) should tell
|
||||
// tabify whether to return columns for each bucket based on the param value. Vis types
|
||||
// without this param should default to returning all columns if they are hierarchical.
|
||||
const minimalColumns =
|
||||
typeof this.vis.params.showMetricsAtAllLevels !== 'undefined'
|
||||
? !this.vis.params.showMetricsAtAllLevels
|
||||
: !this.vis.isHierarchical();
|
||||
|
||||
let requestHandlerResponse;
|
||||
|
||||
// searchSource is only there for courier request handler
|
||||
const requestHandlerResponse = await this.requestHandler(this.vis, {
|
||||
partialRows: this.vis.params.partialRows || this.vis.type.requiresPartialRows,
|
||||
try {
|
||||
requestHandlerResponse = await this.requestHandler({
|
||||
partialRows: this.vis.type.requiresPartialRows || this.vis.params.showPartialRows,
|
||||
minimalColumns,
|
||||
metricsAtAllLevels: this.vis.isHierarchical(),
|
||||
visParams: this.vis.params,
|
||||
...params,
|
||||
filters: params.filters
|
||||
? params.filters.filter(filter => !filter.meta.disabled)
|
||||
: undefined,
|
||||
});
|
||||
} catch (error) {
|
||||
if(!this.vis || !this.vis.searchSource) {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
// No need to call the response handler when there have been no data nor has been there changes
|
||||
// in the vis-state (response handler does not depend on uiStat
|
||||
@ -91,21 +114,19 @@ export class VisualizeDataLoader {
|
||||
this.previousRequestHandlerResponse = requestHandlerResponse;
|
||||
|
||||
if (!canSkipResponseHandler) {
|
||||
this.visData = await Promise.resolve(
|
||||
this.responseHandler(requestHandlerResponse)
|
||||
);
|
||||
this.visData = await Promise.resolve(this.responseHandler(requestHandlerResponse));
|
||||
}
|
||||
|
||||
return this.visData;
|
||||
} catch (error) {
|
||||
if(typeof ((params || {}).searchSource || {}).cancelQueued === 'function') {
|
||||
params.searchSource.cancelQueued();
|
||||
}
|
||||
|
||||
this.vis.requestError = error;
|
||||
this.vis.showRequestError =
|
||||
error.type && ['NO_OP_SEARCH_STRATEGY', 'UNSUPPORTED_QUERY'].includes(error.type);
|
||||
|
||||
// tslint:disable-next-line
|
||||
console.error(error);
|
||||
|
||||
if (isTermSizeZeroError(error)) {
|
||||
return toastNotifications.addDanger(
|
||||
`Your visualization ('${this.vis.title}') has an error: it has a term ` +
|
||||
@ -113,6 +134,7 @@ export class VisualizeDataLoader {
|
||||
`the error.`
|
||||
);
|
||||
}
|
||||
|
||||
toastNotifications.addDanger({
|
||||
title: 'Error in visualization',
|
||||
text: error.message,
|
||||
|
@ -29,7 +29,7 @@ import { IPrivate } from 'ui/private';
|
||||
import { EmbeddedVisualizeHandler } from './embedded_visualize_handler';
|
||||
import { VisSavedObject, VisualizeLoaderParams } from './types';
|
||||
|
||||
class VisualizeLoader {
|
||||
export class VisualizeLoader {
|
||||
constructor(private readonly savedVisualizations: any, private readonly Private: IPrivate) {}
|
||||
|
||||
/**
|
||||
@ -62,6 +62,11 @@ class VisualizeLoader {
|
||||
* In most of the cases you will need this method, since it allows you to specify
|
||||
* filters, handlers, queries, etc. on the savedObject before rendering.
|
||||
*
|
||||
* We do not encourage you to use this method, since it will most likely be changed
|
||||
* or removed in a future version of Kibana. Rather embed a visualization by its id
|
||||
* via the {@link #embedVisualizationWithId} method.
|
||||
*
|
||||
* @deprecated You should rather embed by id, since this method will be removed in the future.
|
||||
* @param element The DOM element to render the visualization into.
|
||||
* You can alternatively pass a jQuery element instead.
|
||||
* @param savedObj The savedObject as it could be retrieved by the
|
||||
|
@ -419,7 +419,8 @@ visualization {
|
||||
|
||||
kbn-vis visualize,
|
||||
kbn-vis visualization,
|
||||
kbn-vis .vis-container {
|
||||
kbn-vis .vis-container,
|
||||
kbn-vis .visChart__container {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
|
@ -10,15 +10,19 @@
|
||||
<span data-test-subj="discoverCurrentQuery" ng-bind="opts.savedSearch.lastSavedTitle"></span>
|
||||
<span
|
||||
id="reload_saved_search"
|
||||
aria-label="Reload Saved Search"
|
||||
tooltip="Reload Saved Search"
|
||||
aria-label="{{::'kbn.discover.reloadSavedSearchAriaLabel' | i18n: {defaultMessage: 'Reload Saved Search'} }}"
|
||||
tooltip="{{::'kbn.discover.reloadSavedSearchTooltip' | i18n: {defaultMessage: 'Reload Saved Search'} }}"
|
||||
ng-click="resetQuery()"
|
||||
kbn-accessible-click
|
||||
class="kuiIcon fa-undo small"
|
||||
></span>
|
||||
</span>
|
||||
<span data-test-subj="discoverQueryHits" class="kuiLocalBreadcrumb__emphasis">{{(hits || 0) | number:0}}</span>
|
||||
<ng-pluralize count="hits" when="{'1':'hit', 'other':'hits'}"></ng-pluralize>
|
||||
<span
|
||||
i18n-id="kbn.discover.hitsPluralTitle"
|
||||
i18n-default-message="{hits, plural, one {hit} other {hits}}"
|
||||
i18n-values="{ hits }"
|
||||
></span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@ -89,7 +93,10 @@
|
||||
class="dscOverlay"
|
||||
>
|
||||
<div class="euiTitle" >
|
||||
<h2>Searching</h2>
|
||||
<h2
|
||||
i18n-id="kbn.discover.searchingTitle"
|
||||
i18n-default-message="Searching"
|
||||
></h2>
|
||||
</div>
|
||||
<div class="euiSpacer euiSpacer--m"></div>
|
||||
<div ng-show="fetchStatus">{{fetchStatus.complete}}/{{fetchStatus.total}}</div>
|
||||
@ -104,14 +111,25 @@
|
||||
>
|
||||
<span class="kuiButton__inner">
|
||||
<span aria-hidden="true" class="kuiButton__icon kuiIcon fa-chevron-down"></span>
|
||||
<span>Skip to bottom</span>
|
||||
<span
|
||||
i18n-id="kbn.discover.skipToBottomButtonLabel"
|
||||
i18n-default-message="Skip to bottom"
|
||||
></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<section aria-label="Histogram of found documents" class="dscTimechart" ng-if="opts.timefield">
|
||||
<section
|
||||
aria-label="{{::'kbn.discover.histogramOfFoundDocumentsAriaLabel' | i18n: {defaultMessage: 'Histogram of found documents'} }}"
|
||||
class="dscTimechart"
|
||||
ng-if="opts.timefield"
|
||||
>
|
||||
<header class="dscTimechart__header">
|
||||
<div class="small">
|
||||
<span tooltip="To change the time, click the clock icon in the navigation bar">{{timeRange.from | moment}} - {{timeRange.to | moment}}</span>
|
||||
<span
|
||||
tooltip="{{::'kbn.discover.howToChangeTheTimeTooltip' | i18n: {defaultMessage: 'To change the time, click the clock icon in the navigation bar'} }}"
|
||||
>
|
||||
{{timeRange.from | moment}} - {{timeRange.to | moment}}
|
||||
</span>
|
||||
|
||||
—
|
||||
|
||||
@ -129,7 +147,13 @@
|
||||
content="getBucketIntervalToolTipText()"
|
||||
position="'top'"
|
||||
></icon-tip>
|
||||
Scaled to {{ bucketInterval.description }}
|
||||
<span
|
||||
i18n-id="kbn.discover.scaledToDescription"
|
||||
i18n-default-message="Scaled to {bucketIntervalDescription}"
|
||||
i18n-values="{
|
||||
bucketIntervalDescription: bucketInterval.description
|
||||
}"
|
||||
></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@ -137,13 +161,17 @@
|
||||
</header>
|
||||
|
||||
<div id="discoverHistogram"
|
||||
ng-if="vis && rows.length !== 0"
|
||||
ng-show="vis && rows.length !== 0"
|
||||
style="display: flex; height: 200px"
|
||||
>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="dscTable" fixed-scroll aria-label="Documents">
|
||||
<section
|
||||
class="dscTable"
|
||||
fixed-scroll
|
||||
aria-label="{{::'kbn.discover.documentsAriaLabel' | i18n: {defaultMessage: 'Documents'} }}"
|
||||
>
|
||||
<doc-table
|
||||
hits="rows"
|
||||
index-pattern="indexPattern"
|
||||
@ -165,10 +193,24 @@
|
||||
|
||||
<a tabindex="0" id="discoverBottomMarker"></a>
|
||||
|
||||
<div ng-if="rows.length == opts.sampleSize" class="dscTable__footer">
|
||||
These are the first {{opts.sampleSize}} documents matching
|
||||
your search, refine your search to see others.
|
||||
<a kbn-accessible-click ng-click="scrollToTop()">Back to top.</a>
|
||||
<div
|
||||
ng-if="rows.length == opts.sampleSize"
|
||||
class="dscTable__footer"
|
||||
>
|
||||
<span
|
||||
i18n-id="kbn.discover.howToSeeOtherMatchingDocumentsDescription"
|
||||
i18n-default-message="These are the first {sampleSize} documents matching
|
||||
your search, refine your search to see others. "
|
||||
i18n-values="{
|
||||
sampleSize: opts.sampleSize,
|
||||
}"
|
||||
></span>
|
||||
<a
|
||||
kbn-accessible-click
|
||||
ng-click="scrollToTop()"
|
||||
i18n-id="kbn.discover.backToTopLinkText"
|
||||
i18n-default-message="Back to top."
|
||||
></a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -18,7 +18,11 @@
|
||||
></span>
|
||||
</span>
|
||||
<span data-test-subj="discoverQueryHits" class="kuiLocalBreadcrumb__emphasis">{{(hits || 0) | number:0}}</span>
|
||||
<ng-pluralize count="hits" when="{'1':'hit', 'other':'hits'}"></ng-pluralize>
|
||||
<span
|
||||
i18n-id="kbn.discover.hitsPluralTitle"
|
||||
i18n-default-message="{hits, plural, one {hit} other {hits}}"
|
||||
i18n-values="{ hits }"
|
||||
></span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@ -41,7 +45,7 @@
|
||||
index-patterns="[indexPattern]"
|
||||
></filter-bar-w>
|
||||
</div>
|
||||
<div class="row" ng-if="tabView === 'discover'">
|
||||
<div class="row" ng-show="tabView === 'discover'">
|
||||
<div class="col-md-2 sidebar-container collapsible-sidebar" id="discover-sidebar">
|
||||
<disc-field-chooser
|
||||
class="dscFieldChooser"
|
||||
@ -89,7 +93,10 @@
|
||||
class="dscOverlay"
|
||||
>
|
||||
<div class="euiTitle" >
|
||||
<h2>Searching</h2>
|
||||
<h2
|
||||
i18n-id="kbn.discover.searchingTitle"
|
||||
i18n-default-message="Searching"
|
||||
></h2>
|
||||
</div>
|
||||
<div class="euiSpacer euiSpacer--m"></div>
|
||||
<div ng-show="fetchStatus">{{fetchStatus.complete}}/{{fetchStatus.total}}</div>
|
||||
@ -104,14 +111,25 @@
|
||||
>
|
||||
<span class="kuiButton__inner">
|
||||
<span aria-hidden="true" class="kuiButton__icon kuiIcon fa-chevron-down"></span>
|
||||
<span>Skip to bottom</span>
|
||||
<span
|
||||
i18n-id="kbn.discover.skipToBottomButtonLabel"
|
||||
i18n-default-message="Skip to bottom"
|
||||
></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<section aria-label="Histogram of found documents" class="dscTimechart" ng-if="opts.timefield">
|
||||
<section
|
||||
aria-label="{{::'kbn.discover.histogramOfFoundDocumentsAriaLabel' | i18n: {defaultMessage: 'Histogram of found documents'} }}"
|
||||
class="dscTimechart"
|
||||
ng-if="opts.timefield"
|
||||
>
|
||||
<header class="dscTimechart__header">
|
||||
<div class="small">
|
||||
<span tooltip="To change the time, click the clock icon in the navigation bar">{{timeRange.from | moment}} - {{timeRange.to | moment}}</span>
|
||||
<span
|
||||
tooltip="{{::'kbn.discover.howToChangeTheTimeTooltip' | i18n: {defaultMessage: 'To change the time, click the clock icon in the navigation bar'} }}"
|
||||
>
|
||||
{{timeRange.from | moment}} - {{timeRange.to | moment}}
|
||||
</span>
|
||||
|
||||
—
|
||||
|
||||
@ -129,7 +147,13 @@
|
||||
content="getBucketIntervalToolTipText()"
|
||||
position="'top'"
|
||||
></icon-tip>
|
||||
Scaled to {{ bucketInterval.description }}
|
||||
<span
|
||||
i18n-id="kbn.discover.scaledToDescription"
|
||||
i18n-default-message="Scaled to {bucketIntervalDescription}"
|
||||
i18n-values="{
|
||||
bucketIntervalDescription: bucketInterval.description
|
||||
}"
|
||||
></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@ -137,13 +161,18 @@
|
||||
</header>
|
||||
|
||||
<div id="discoverHistogram"
|
||||
ng-if="vis && rows.length !== 0"
|
||||
ng-show="vis && rows.length !== 0"
|
||||
style="display: flex; height: 200px"
|
||||
>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="dscTable" fixed-scroll aria-label="Documents">
|
||||
<section
|
||||
ng-if="tabView === 'discover'"
|
||||
class="dscTable"
|
||||
fixed-scroll
|
||||
aria-label="{{::'kbn.discover.documentsAriaLabel' | i18n: {defaultMessage: 'Documents'} }}"
|
||||
>
|
||||
<doc-table
|
||||
hits="rows"
|
||||
index-pattern="indexPattern"
|
||||
@ -165,10 +194,24 @@
|
||||
|
||||
<a tabindex="0" id="discoverBottomMarker"></a>
|
||||
|
||||
<div ng-if="rows.length == opts.sampleSize" class="dscTable__footer">
|
||||
These are the first {{opts.sampleSize}} documents matching
|
||||
your search, refine your search to see others.
|
||||
<a kbn-accessible-click ng-click="scrollToTop()">Back to top.</a>
|
||||
<div
|
||||
ng-if="rows.length == opts.sampleSize"
|
||||
class="dscTable__footer"
|
||||
>
|
||||
<span
|
||||
i18n-id="kbn.discover.howToSeeOtherMatchingDocumentsDescription"
|
||||
i18n-default-message="These are the first {sampleSize} documents matching
|
||||
your search, refine your search to see others. "
|
||||
i18n-values="{
|
||||
sampleSize: opts.sampleSize,
|
||||
}"
|
||||
></span>
|
||||
<a
|
||||
kbn-accessible-click
|
||||
ng-click="scrollToTop()"
|
||||
i18n-id="kbn.discover.backToTopLinkText"
|
||||
i18n-default-message="Back to top."
|
||||
></a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -17,15 +17,15 @@
|
||||
<kbn-vis vis-id="'Wazuh-App-Overview-General-Authentication-success'"></kbn-vis>
|
||||
</div>
|
||||
|
||||
<div layout="row" layout-align="start stretch" class="height-230" >
|
||||
<md-card flex="40" class="wz-md-card">
|
||||
<div layout="row" layout-align="start stretch" class="height-300" >
|
||||
<md-card flex class="wz-md-card">
|
||||
<md-card-content class="wazuh-column" >
|
||||
<span class="wz-headline-title">Alert level evolution</span>
|
||||
<md-divider class="wz-margin-top-10"></md-divider>
|
||||
<kbn-vis id="Wazuh-App-Overview-General-Alert-level-evolution" vis-id="'Wazuh-App-Overview-General-Alert-level-evolution'"></kbn-vis>
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
<md-card flex="60" class="wz-md-card">
|
||||
<md-card flex class="wz-md-card">
|
||||
<md-card-content class="wazuh-column" >
|
||||
<span class="wz-headline-title">Alerts</span>
|
||||
<md-divider class="wz-margin-top-10"></md-divider>
|
||||
@ -44,12 +44,12 @@
|
||||
</md-card>
|
||||
<md-card flex class="wz-md-card" >
|
||||
<md-card-content class="wazuh-column" >
|
||||
<span class="wz-headline-title">Alerts evolution - Top 5 agents</span>
|
||||
<span class="wz-headline-title">Top 5 rule groups</span>
|
||||
<md-divider class="wz-margin-top-10"></md-divider>
|
||||
<kbn-vis id="Wazuh-App-Overview-General-Alerts-evolution-Top-5-agents" vis-id="'Wazuh-App-Overview-General-Alerts-evolution-Top-5-agents'"></kbn-vis>
|
||||
<kbn-vis id="Wazuh-App-Overview-General-Top-5-rule-groups" vis-id="'Wazuh-App-Overview-General-Top-5-rule-groups'"></kbn-vis>
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
<md-card flex="35" class="wz-md-card">
|
||||
<md-card flex class="wz-md-card">
|
||||
<md-card-content class="wazuh-column" ng-show="octrl.wzMonitoringEnabled" >
|
||||
<span class="wz-headline-title">Agents status</span>
|
||||
<md-divider class="wz-margin-top-10"></md-divider>
|
||||
|
@ -29,7 +29,7 @@ export function ErrorResponse(
|
||||
message = null,
|
||||
code = null,
|
||||
statusCode = null,
|
||||
reply
|
||||
h
|
||||
) {
|
||||
let filteredMessage = '';
|
||||
if (code) {
|
||||
@ -66,13 +66,15 @@ export function ErrorResponse(
|
||||
}
|
||||
}
|
||||
|
||||
return reply({
|
||||
return h
|
||||
.response({
|
||||
message: filteredMessage
|
||||
? `${code ? code : 1000} - ${filteredMessage}`
|
||||
? `${code || 1000} - ${filteredMessage}`
|
||||
: typeof message === 'string'
|
||||
? `${code ? code : 1000} - ${message}`
|
||||
: `${code ? code : 1000} - Unexpected error`,
|
||||
code: code ? code : 1000,
|
||||
statusCode: statusCode ? statusCode : 500
|
||||
}).code(statusCode ? statusCode : 500);
|
||||
? `${code || 1000} - ${message}`
|
||||
: `${code || 1000} - Unexpected error`,
|
||||
code: code || 1000,
|
||||
statusCode: statusCode || 500
|
||||
})
|
||||
.code(statusCode || 500);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ export class WazuhApiElasticCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
return reply(result);
|
||||
return result;
|
||||
} catch (error) {
|
||||
log('GET /elastic/apis', error.message || error);
|
||||
return ErrorResponse(error.message || error, 2001, 500, reply);
|
||||
@ -69,7 +69,7 @@ export class WazuhApiElasticCtrl {
|
||||
try {
|
||||
const data = await this.wzWrapper.deleteWazuhAPIEntriesWithRequest(req);
|
||||
|
||||
return reply(data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
log('DELETE /elastic/apis/{id}', error.message || error);
|
||||
return ErrorResponse(error.message || error, 2002, 500, reply);
|
||||
@ -154,7 +154,7 @@ export class WazuhApiElasticCtrl {
|
||||
settings
|
||||
);
|
||||
|
||||
return reply({ statusCode: 200, message: 'ok', response });
|
||||
return { statusCode: 200, message: 'ok', response };
|
||||
} catch (error) {
|
||||
log('PUT /elastic/api', error.message || error);
|
||||
return ErrorResponse(
|
||||
@ -178,7 +178,7 @@ export class WazuhApiElasticCtrl {
|
||||
doc: { cluster_info: req.payload.cluster_info }
|
||||
});
|
||||
|
||||
return reply({ statusCode: 200, message: 'ok' });
|
||||
return { statusCode: 200, message: 'ok' };
|
||||
} catch (error) {
|
||||
log('PUT /elastic/api-hostname/{id}', error.message || error);
|
||||
return ErrorResponse(
|
||||
@ -216,7 +216,7 @@ export class WazuhApiElasticCtrl {
|
||||
doc: settings
|
||||
});
|
||||
|
||||
return reply({ statusCode: 200, message: 'ok' });
|
||||
return { statusCode: 200, message: 'ok' };
|
||||
} catch (error) {
|
||||
log('PUT /elastic/api-settings', error.message || error);
|
||||
return ErrorResponse(
|
||||
|
@ -110,11 +110,11 @@ export class WazuhApiCtrl {
|
||||
api.cluster_info.node = response.body.data.node;
|
||||
api.cluster_info.cluster = response.body.data.cluster;
|
||||
api.password = '****';
|
||||
return reply({
|
||||
return {
|
||||
statusCode: 200,
|
||||
data: api,
|
||||
idChanged: req.idChanged || null
|
||||
});
|
||||
};
|
||||
} else if (response.body.error) {
|
||||
const tmpMsg =
|
||||
((response || {}).body || {}).message ||
|
||||
@ -131,11 +131,11 @@ export class WazuhApiCtrl {
|
||||
api.cluster_info.manager = managerName;
|
||||
api.password = '****';
|
||||
|
||||
return reply({
|
||||
return {
|
||||
statusCode: 200,
|
||||
data: api,
|
||||
idChanged: req.idChanged || null
|
||||
});
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const tmpMsg =
|
||||
@ -154,10 +154,10 @@ export class WazuhApiCtrl {
|
||||
} catch (error) {
|
||||
if (error.code === 'ECONNREFUSED') {
|
||||
log('POST /api/check-stored-api', error.message || error);
|
||||
return reply({
|
||||
return {
|
||||
statusCode: 200,
|
||||
data: { password: '****', apiIsDown: true }
|
||||
});
|
||||
};
|
||||
} else {
|
||||
// Check if we can connect to a different API
|
||||
if (
|
||||
@ -309,20 +309,20 @@ export class WazuhApiCtrl {
|
||||
);
|
||||
|
||||
if (!response.body.error) {
|
||||
return reply({
|
||||
return {
|
||||
manager: managerName,
|
||||
node: response.body.data.node,
|
||||
cluster: response.body.data.cluster,
|
||||
status: 'enabled'
|
||||
});
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Cluster mode is not active
|
||||
return reply({
|
||||
return {
|
||||
manager: managerName,
|
||||
cluster: 'Disabled',
|
||||
status: 'disabled'
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -351,7 +351,7 @@ export class WazuhApiCtrl {
|
||||
|
||||
if (req.params.requirement === 'all') {
|
||||
if (!req.headers.id) {
|
||||
return reply(pciRequirementsFile);
|
||||
return pciRequirementsFile;
|
||||
}
|
||||
let api = await this.wzWrapper.getWazuhConfigurationById(
|
||||
req.headers.id
|
||||
@ -383,7 +383,7 @@ export class WazuhApiCtrl {
|
||||
if (typeof pciRequirementsFile[item] !== 'undefined')
|
||||
PCIobject[item] = pciRequirementsFile[item];
|
||||
}
|
||||
return reply(PCIobject);
|
||||
return PCIobject;
|
||||
} else {
|
||||
return ErrorResponse(
|
||||
'An error occurred trying to parse PCI DSS requirements',
|
||||
@ -399,12 +399,12 @@ export class WazuhApiCtrl {
|
||||
pci_description = pciRequirementsFile[req.params.requirement];
|
||||
}
|
||||
|
||||
return reply({
|
||||
return {
|
||||
pci: {
|
||||
requirement: req.params.requirement,
|
||||
description: pci_description
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3010, 400, reply);
|
||||
@ -423,7 +423,7 @@ export class WazuhApiCtrl {
|
||||
|
||||
if (req.params.requirement === 'all') {
|
||||
if (!req.headers.id) {
|
||||
return reply(gdprRequirementsFile);
|
||||
return gdprRequirementsFile;
|
||||
}
|
||||
const api = await this.wzWrapper.getWazuhConfigurationById(
|
||||
req.headers.id
|
||||
@ -453,7 +453,7 @@ export class WazuhApiCtrl {
|
||||
(major >= 3 && minor < 2) ||
|
||||
(major >= 3 && minor >= 2 && patch < 3)
|
||||
) {
|
||||
return reply({});
|
||||
return {};
|
||||
}
|
||||
|
||||
if (api.error_code > 1) {
|
||||
@ -482,7 +482,7 @@ export class WazuhApiCtrl {
|
||||
if (typeof gdprRequirementsFile[item] !== 'undefined')
|
||||
GDPRobject[item] = gdprRequirementsFile[item];
|
||||
}
|
||||
return reply(GDPRobject);
|
||||
return GDPRobject;
|
||||
} else {
|
||||
return ErrorResponse(
|
||||
'An error occurred trying to parse GDPR requirements',
|
||||
@ -498,12 +498,12 @@ export class WazuhApiCtrl {
|
||||
gdpr_description = gdprRequirementsFile[req.params.requirement];
|
||||
}
|
||||
|
||||
return reply({
|
||||
return {
|
||||
gdpr: {
|
||||
requirement: req.params.requirement,
|
||||
description: gdpr_description
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3027, 400, reply);
|
||||
@ -564,11 +564,11 @@ export class WazuhApiCtrl {
|
||||
((response || {}).body || {}).data
|
||||
) {
|
||||
cleanKeys(response);
|
||||
return reply(response.body);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
if (((response || {}).body || {}).error && devTools) {
|
||||
return reply(response.body);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
throw ((response || {}).body || {}).error &&
|
||||
@ -576,9 +576,10 @@ export class WazuhApiCtrl {
|
||||
? { message: response.body.message, code: response.body.error }
|
||||
: new Error('Unexpected error fetching data from the Wazuh API');
|
||||
} catch (error) {
|
||||
return devTools
|
||||
? reply({ error: '3013', message: error.message || error })
|
||||
: ErrorResponse(
|
||||
if (devTools) {
|
||||
return { error: '3013', message: error.message || error };
|
||||
} else {
|
||||
return ErrorResponse(
|
||||
error.message || error,
|
||||
`Wazuh API error: ${error.code}` || 3013,
|
||||
500,
|
||||
@ -586,6 +587,7 @@ export class WazuhApiCtrl {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This performs a generic request and returs its response
|
||||
@ -698,12 +700,12 @@ export class WazuhApiCtrl {
|
||||
async fetchAgents(req, reply) {
|
||||
try {
|
||||
const output = await this.monitoringInstance.fetchAgentsExternal();
|
||||
return reply({
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: '0',
|
||||
data: '',
|
||||
output
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3018, 500, reply);
|
||||
}
|
||||
@ -798,7 +800,7 @@ export class WazuhApiCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
return reply(csv).type('text/csv');
|
||||
return reply.response(csv).type('text/csv');
|
||||
} else if (
|
||||
output &&
|
||||
output.body &&
|
||||
@ -947,15 +949,15 @@ export class WazuhApiCtrl {
|
||||
Object.assign(result.lastAgent, lastAgent.items[0]);
|
||||
}
|
||||
|
||||
return reply({ error: 0, result });
|
||||
return { error: 0, result };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3035, 500, reply);
|
||||
}
|
||||
}
|
||||
|
||||
// Get de list of available requests in the API
|
||||
getRequestList(req, reply) {
|
||||
getRequestList() {
|
||||
//Read a static JSON until the api call has implemented
|
||||
return reply(apiRequestList);
|
||||
return apiRequestList;
|
||||
}
|
||||
}
|
||||
|
@ -43,10 +43,10 @@ export class WazuhElasticCtrl {
|
||||
((((data || {}).hits || {}).hits || [])[0] || {})._source || {};
|
||||
|
||||
if (source.installationDate && source.lastRestart) {
|
||||
return reply({
|
||||
return {
|
||||
installationDate: data.hits.hits[0]._source.installationDate,
|
||||
lastRestart: data.hits.hits[0]._source.lastRestart
|
||||
});
|
||||
};
|
||||
} else {
|
||||
throw new Error('Could not fetch .wazuh-version index');
|
||||
}
|
||||
@ -115,16 +115,16 @@ export class WazuhElasticCtrl {
|
||||
});
|
||||
|
||||
return isIncluded && Array.isArray(isIncluded) && isIncluded.length
|
||||
? reply({
|
||||
? {
|
||||
statusCode: 200,
|
||||
status: true,
|
||||
data: `Template found for ${req.params.pattern}`
|
||||
})
|
||||
: reply({
|
||||
}
|
||||
: {
|
||||
statusCode: 200,
|
||||
status: false,
|
||||
data: `No template found for ${req.params.pattern}`
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
log('GET /elastic/template/{pattern}', error.message || error);
|
||||
return ErrorResponse(
|
||||
@ -152,13 +152,13 @@ export class WazuhElasticCtrl {
|
||||
);
|
||||
|
||||
return filtered.length >= 1
|
||||
? reply({ statusCode: 200, status: true, data: 'Index pattern found' })
|
||||
: reply({
|
||||
? { statusCode: 200, status: true, data: 'Index pattern found' }
|
||||
: {
|
||||
statusCode: 500,
|
||||
status: false,
|
||||
error: 10020,
|
||||
message: 'Index pattern not found'
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
log('GET /elastic/index-patterns/{pattern}', error.message || error);
|
||||
return ErrorResponse(
|
||||
@ -218,11 +218,11 @@ export class WazuhElasticCtrl {
|
||||
|
||||
return data.hits.total === 0 ||
|
||||
typeof data.aggregations['2'].buckets[0] === 'undefined'
|
||||
? reply({ statusCode: 200, data: '' })
|
||||
: reply({
|
||||
? { statusCode: 200, data: '' }
|
||||
: {
|
||||
statusCode: 200,
|
||||
data: data.aggregations['2'].buckets[0].key
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 4004, 500, reply);
|
||||
}
|
||||
@ -239,8 +239,8 @@ export class WazuhElasticCtrl {
|
||||
const data = await this.wzWrapper.getWazuhVersionIndexAsSearch();
|
||||
|
||||
return data.hits.total === 0
|
||||
? reply({ statusCode: 200, data: '' })
|
||||
: reply({ statusCode: 200, data: data.hits.hits[0]._source });
|
||||
? { statusCode: 200, data: '' }
|
||||
: { statusCode: 200, data: data.hits.hits[0]._source };
|
||||
} catch (error) {
|
||||
log('GET /elastic/setup', error.message || error);
|
||||
return ErrorResponse(
|
||||
@ -351,12 +351,12 @@ export class WazuhElasticCtrl {
|
||||
item && item.title && !config['ip.ignore'].includes(item.title)
|
||||
);
|
||||
}
|
||||
return reply({
|
||||
return {
|
||||
data:
|
||||
isXpackEnabled && !isSuperUser
|
||||
? await this.filterAllowedIndexPatternList(list, req)
|
||||
: list
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
@ -528,7 +528,7 @@ export class WazuhElasticCtrl {
|
||||
: AgentsVisualizations[tabSufix];
|
||||
|
||||
const raw = await this.buildVisualizationsRaw(file, req.params.pattern);
|
||||
return reply({ acknowledge: true, raw: raw });
|
||||
return { acknowledge: true, raw: raw };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 4007, 500, reply);
|
||||
}
|
||||
@ -573,7 +573,7 @@ export class WazuhElasticCtrl {
|
||||
pattern_name
|
||||
);
|
||||
|
||||
return reply({ acknowledge: true, raw: raw });
|
||||
return { acknowledge: true, raw: raw };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 4009, 500, reply);
|
||||
}
|
||||
@ -596,7 +596,7 @@ export class WazuhElasticCtrl {
|
||||
req.params.pattern
|
||||
);
|
||||
|
||||
return reply({ acknowledge: true, output: output });
|
||||
return { acknowledge: true, output: output };
|
||||
} catch (error) {
|
||||
log('GET /elastic/known-fields/{pattern}', error.message || error);
|
||||
return ErrorResponse(error.message || error, 4008, 500, reply);
|
||||
@ -661,7 +661,7 @@ export class WazuhElasticCtrl {
|
||||
'rule.description'
|
||||
];
|
||||
const data = await this.wzWrapper.searchWazuhAlertsWithPayload(payload);
|
||||
return reply({ alerts: data.hits.hits });
|
||||
return { alerts: data.hits.hits };
|
||||
} catch (error) {
|
||||
log('POST /elastic/alerts', error.message || error);
|
||||
return ErrorResponse(error.message || error, 4010, 500, reply);
|
||||
|
@ -1617,7 +1617,7 @@ export class WazuhReportingCtrl {
|
||||
);
|
||||
pdfDoc.end();
|
||||
}
|
||||
return reply({ error: 0, data: null });
|
||||
return { error: 0, data: null };
|
||||
} catch (error) {
|
||||
// Delete generated file if an error occurred
|
||||
if (
|
||||
@ -1659,7 +1659,7 @@ export class WazuhReportingCtrl {
|
||||
list.push(file);
|
||||
});
|
||||
TimSort.sort(list, sortFunction);
|
||||
return reply({ list: list });
|
||||
return { list: list };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 5031, 500, reply);
|
||||
}
|
||||
@ -1694,7 +1694,7 @@ export class WazuhReportingCtrl {
|
||||
fs.unlinkSync(
|
||||
path.join(__dirname, REPORTING_PATH + '/' + req.params.name)
|
||||
);
|
||||
return reply({ error: 0 });
|
||||
return { error: 0 };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 5032, 500, reply);
|
||||
}
|
||||
|
@ -35,11 +35,11 @@ export class WazuhUtilsCtrl {
|
||||
try {
|
||||
const configFile = getConfiguration();
|
||||
|
||||
return reply({
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: 0,
|
||||
data: configFile || {}
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3019, 500, reply);
|
||||
}
|
||||
@ -54,11 +54,11 @@ export class WazuhUtilsCtrl {
|
||||
async updateConfigurationFile(req, reply) {
|
||||
try {
|
||||
const result = updateConfigurationFile.updateConfiguration(req);
|
||||
return reply({
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: 0,
|
||||
data: result.needRestart
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3021, 500, reply);
|
||||
}
|
||||
@ -74,7 +74,7 @@ export class WazuhUtilsCtrl {
|
||||
try {
|
||||
// RAM in MB
|
||||
const ram = Math.ceil(totalmem() / 1024 / 1024);
|
||||
return reply({ statusCode: 200, error: 0, ram });
|
||||
return { statusCode: 200, error: 0, ram };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3033, 500, reply);
|
||||
}
|
||||
@ -93,13 +93,13 @@ export class WazuhUtilsCtrl {
|
||||
20
|
||||
);
|
||||
return lastLogs && Array.isArray(lastLogs)
|
||||
? reply({
|
||||
? {
|
||||
error: 0,
|
||||
lastLogs: lastLogs.filter(
|
||||
item => typeof item === 'string' && item.length
|
||||
)
|
||||
})
|
||||
: reply({ error: 0, lastLogs: [] });
|
||||
}
|
||||
: { error: 0, lastLogs: [] };
|
||||
} catch (error) {
|
||||
return ErrorResponse(error.message || error, 3036, 500, reply);
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ export default [
|
||||
_source: {
|
||||
title: 'Alert level evolution',
|
||||
visState:
|
||||
'{"title":"Alert level evolution","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"line","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"cardinal"}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"rule.level","size":5,"order":"desc","orderBy":"1"}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"@timestamp","interval":"h","customInterval":"2h","min_doc_count":1,"extended_bounds":{}}}]}',
|
||||
'{"title":"Alert level evolution","type":"area","params":{"type":"area","grid":{"categoryLines":true,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"line","mode":"stacked","data":{"label":"Count","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"cardinal","valueAxis":"ValueAxis-1"}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"@timestamp","timeRange":{"from":"now-15m","to":"now","mode":"quick"},"useNormalizedEsInterval":true,"interval":"auto","time_zone":"Europe/Berlin","drop_partials":false,"customInterval":"2h","min_doc_count":1,"extended_bounds":{}}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"rule.level","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}',
|
||||
uiStateJSON: '{}',
|
||||
description: '',
|
||||
version: 1,
|
||||
@ -209,7 +209,7 @@ export default [
|
||||
_source: {
|
||||
title: 'Alerts',
|
||||
visState:
|
||||
'{"title":"Alerts","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":false,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"@timestamp","interval":"h","customInterval":"2h","min_doc_count":1,"extended_bounds":{}}}]}',
|
||||
'{"title":"Alerts","type":"area","params":{"type":"area","grid":{"categoryLines":true,"style":{"color":"#eee"},"valueAxis":null},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"area","mode":"stacked","data":{"label":"Count","id":"1"},"drawLinesBetweenPoints":true,"showCircles":true,"interpolate":"cardinal","valueAxis":"ValueAxis-1"}],"addTooltip":true,"addLegend":false,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"@timestamp","timeRange":{"from":"now-15m","to":"now","mode":"quick"},"useNormalizedEsInterval":true,"interval":"auto","time_zone":"Europe/Berlin","drop_partials":false,"customInterval":"2h","min_doc_count":1,"extended_bounds":{}}}]}',
|
||||
uiStateJSON:
|
||||
'{"spy":{"mode":{"name":null,"fill":false}},"vis":{"legendOpen":false}}',
|
||||
description: '',
|
||||
@ -226,8 +226,8 @@ export default [
|
||||
_source: {
|
||||
title: 'Top 5 agents',
|
||||
visState:
|
||||
'{"title":"Top 5 Agents","type":"pie","params":{"type":"pie","addTooltip":true,"addLegend":true,"legendPosition":"right","isDonut":true},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"agent.name","size":5,"order":"desc","orderBy":"1"}}]}',
|
||||
uiStateJSON: '{}',
|
||||
'{"title":"overrview-05","type":"pie","params":{"type":"pie","addTooltip":true,"addLegend":false,"legendPosition":"right","isDonut":true,"labels":{"show":true,"values":true,"last_level":true,"truncate":100}},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"agent.name","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}',
|
||||
uiStateJSON: '{"vis":{"legendOpen":false}}',
|
||||
description: '',
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
@ -238,80 +238,12 @@ export default [
|
||||
_type: 'visualization'
|
||||
},
|
||||
{
|
||||
_id: 'Wazuh-App-Overview-General-Alerts-evolution-Top-5-agents',
|
||||
_id: 'Wazuh-App-Overview-General-Top-5-rule-groups',
|
||||
_source: {
|
||||
title: 'Alerts evolution Top 5 agents',
|
||||
title: 'Top 5 rule groups',
|
||||
visState:
|
||||
'{"title":"Alerts evolution Top 5 agents","type":"histogram","params":{"type":"histogram","grid":{"categoryLines":false,"style":{"color":"#eee"}},"categoryAxes":[{"id":"CategoryAxis-1","type":"category","position":"bottom","show":true,"style":{},"scale":{"type":"linear"},"labels":{"show":true,"truncate":100},"title":{}}],"valueAxes":[{"id":"ValueAxis-1","name":"LeftAxis-1","type":"value","position":"left","show":true,"style":{},"scale":{"type":"linear","mode":"normal"},"labels":{"show":true,"rotate":0,"filter":false,"truncate":100},"title":{"text":"Count"}}],"seriesParams":[{"show":"true","type":"histogram","mode":"stacked","data":{"label":"Count","id":"1"},"valueAxis":"ValueAxis-1","drawLinesBetweenPoints":true,"showCircles":true}],"addTooltip":true,"addLegend":true,"legendPosition":"right","times":[],"addTimeMarker":false},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"3","enabled":true,"type":"terms","schema":"group","params":{"field":"agent.name","size":5,"order":"desc","orderBy":"1"}},{"id":"2","enabled":true,"type":"date_histogram","schema":"segment","params":{"field":"@timestamp","interval":"h","customInterval":"2h","min_doc_count":1,"extended_bounds":{}}}]}',
|
||||
uiStateJSON: '{"vis":{"colors":{"ip-10-0-0-157.localdomain":"#64B0C8"}}}',
|
||||
description: '',
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
'{"index":"wazuh-alerts","filter":[],"query":{"query":"","language":"lucene"}}'
|
||||
}
|
||||
},
|
||||
_type: 'visualization'
|
||||
},
|
||||
{
|
||||
_id: 'Wazuh-App-Overview-General-Top-source-user',
|
||||
_source: {
|
||||
title: 'Top source user',
|
||||
visState:
|
||||
'{"title":"Top Source User","type":"table","params":{"perPage":10,"showPartialRows":false,"showMeticsAtAllLevels":false,"sort":{"columnIndex":null,"direction":null},"showTotal":false,"totalFunc":"sum"},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"terms","schema":"bucket","params":{"field":"data.srcuser","size":1,"order":"desc","orderBy":"1","customLabel":"Top source user"}}]}',
|
||||
uiStateJSON:
|
||||
'{"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}}}',
|
||||
description: '',
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
'{"index":"wazuh-alerts","filter":[],"query":{"query":"","language":"lucene"}}'
|
||||
}
|
||||
},
|
||||
_type: 'visualization'
|
||||
},
|
||||
{
|
||||
_id: 'Wazuh-App-Overview-General-Top-source-IP',
|
||||
_source: {
|
||||
title: 'Top source IP',
|
||||
visState:
|
||||
'{"title":"Top Source IP","type":"table","params":{"perPage":10,"showPartialRows":false,"showMeticsAtAllLevels":false,"sort":{"columnIndex":null,"direction":null},"showTotal":false,"totalFunc":"sum"},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{"customLabel":""}},{"id":"2","enabled":true,"type":"terms","schema":"bucket","params":{"field":"data.srcip","size":1,"order":"desc","orderBy":"1","customLabel":"Top source ip"}}]}',
|
||||
uiStateJSON:
|
||||
'{"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}}}',
|
||||
description: '',
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
'{"index":"wazuh-alerts","filter":[],"query":{"query":"","language":"lucene"}}'
|
||||
}
|
||||
},
|
||||
_type: 'visualization'
|
||||
},
|
||||
{
|
||||
_id: 'Wazuh-App-Overview-General-Top-group',
|
||||
_source: {
|
||||
title: 'Top group',
|
||||
visState:
|
||||
'{"title":"Top Group","type":"table","params":{"perPage":10,"showPartialRows":false,"showMeticsAtAllLevels":false,"sort":{"columnIndex":null,"direction":null},"showTotal":false,"totalFunc":"sum"},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"terms","schema":"bucket","params":{"field":"rule.groups","size":1,"order":"desc","orderBy":"1","customLabel":"Top group"}}]}',
|
||||
uiStateJSON:
|
||||
'{"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}}}',
|
||||
description: '',
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
'{"index":"wazuh-alerts","filter":[],"query":{"query":"","language":"lucene"}}'
|
||||
}
|
||||
},
|
||||
_type: 'visualization'
|
||||
},
|
||||
{
|
||||
_id: 'Wazuh-App-Overview-General-Top-PCI-DSS-requirement',
|
||||
_source: {
|
||||
title: 'Top PCI DSS requirement',
|
||||
visState:
|
||||
'{"title":"Top Top PCI DSS","type":"table","params":{"perPage":10,"showPartialRows":false,"showMeticsAtAllLevels":false,"sort":{"columnIndex":null,"direction":null},"showTotal":false,"totalFunc":"sum"},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"terms","schema":"bucket","params":{"field":"rule.pci_dss","size":1,"order":"desc","orderBy":"1","customLabel":"Top PCI DSS"}}]}',
|
||||
uiStateJSON:
|
||||
'{"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}}}',
|
||||
'{"title":"Top 5 rule groups","type":"pie","params":{"type":"pie","addTooltip":true,"addLegend":false,"legendPosition":"right","isDonut":true,"labels":{"show":true,"values":true,"last_level":true,"truncate":100}},"aggs":[{"id":"1","enabled":true,"type":"count","schema":"metric","params":{}},{"id":"2","enabled":true,"type":"terms","schema":"segment","params":{"field":"rule.groups","size":5,"order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"}}]}',
|
||||
uiStateJSON: '{"vis":{"legendOpen":false}}',
|
||||
description: '',
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
|
@ -213,20 +213,15 @@ export class Monitoring {
|
||||
|
||||
if (!response.error && ((response.body || {}).data || {}).totalItems) {
|
||||
await this.checkStatus(api, response.body.data.totalItems);
|
||||
} else {
|
||||
} else if ((response || {}).error) {
|
||||
const msg = ((response || {}).body || {}).message || false;
|
||||
!this.quiet &&
|
||||
log(
|
||||
'[monitoring][checkAndSaveStatus]',
|
||||
const extraLog =
|
||||
msg ||
|
||||
'Wazuh API credentials not found or are not correct. Open the app in your browser and configure it to start monitoring agents.'
|
||||
);
|
||||
'Wazuh API credentials not found or are not correct. Open the app in your browser and configure it to start monitoring agents.';
|
||||
|
||||
!this.quiet && log('[monitoring][checkAndSaveStatus]', extraLog);
|
||||
!this.quiet &&
|
||||
this.server.log(
|
||||
[blueWazuh, 'monitoring', 'error'],
|
||||
msg ||
|
||||
'Wazuh API credentials not found or are not correct. Open the app in your browser and configure it to start monitoring agents.'
|
||||
);
|
||||
this.server.log([blueWazuh, 'monitoring', 'error'], extraLog);
|
||||
}
|
||||
return;
|
||||
} catch (error) {
|
||||
|
Loading…
Reference in New Issue
Block a user