Merge pull request #1194 from wazuh/3.8-6.6

Update master branch (3.8.2-6.6.0)
This commit is contained in:
Jesús Ángel 2019-01-31 16:06:22 +01:00 committed by GitHub
commit 84466b6ec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 594 additions and 404 deletions

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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');
}

View File

@ -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 {
/**

View File

@ -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
};

View File

@ -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
}
}
)
});
}

View File

@ -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();
}
});
};
}

View File

@ -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;
}
/**

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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>&nbsp;
</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>
&mdash;
@ -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>

View File

@ -18,7 +18,11 @@
></span>&nbsp;
</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>
&mdash;
@ -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>

View File

@ -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>

View File

@ -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);
}

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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: {

View File

@ -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) {