Skip to content

Commit

Permalink
Merge branch '4.9.0' into 6478-remove-discover-implement-embeddable-d…
Browse files Browse the repository at this point in the history
…ashboard-on-threat-hunting-module
  • Loading branch information
asteriscos committed Apr 25, 2024
2 parents e8611aa + d8a6b29 commit 19f48ef
Show file tree
Hide file tree
Showing 11 changed files with 1,509 additions and 5 deletions.
2 changes: 2 additions & 0 deletions plugins/main/common/constants.ts
Expand Up @@ -227,6 +227,8 @@ export const DATA_SOURCE_FILTER_CONTROLLED_PINNED_AGENT = 'pinned-agent';
export const DATA_SOURCE_FILTER_CONTROLLED_CLUSTER_MANAGER = 'cluster-manager';
export const DATA_SOURCE_FILTER_CONTROLLED_VULNERABILITIES_RULE_GROUP =
'vulnerabilities-rule-group';
export const DATA_SOURCE_FILTER_CONTROLLED_VIRUSTOTAL_RULE_GROUP =
'virustotal-rule-group';

// Wazuh links
export const WAZUH_LINK_GITHUB = 'https://github.com/wazuh';
Expand Down
@@ -0,0 +1,24 @@
import { tFilter } from '../../../index';
import { DATA_SOURCE_FILTER_CONTROLLED_VIRUSTOTAL_RULE_GROUP } from '../../../../../../../common/constants';
import { AlertsDataSource } from '../alerts-data-source';

const VIRUSTOTAL_GROUP_KEY = 'rule.groups';
const VIRUSTOTAL_GROUP_VALUE = 'virustotal';

export class AlertsVirustotalDataSource extends AlertsDataSource {
constructor(id: string, title: string) {
super(id, title);
}

getRuleGroupsFilter() {
return super.getRuleGroupsFilter(
VIRUSTOTAL_GROUP_KEY,
VIRUSTOTAL_GROUP_VALUE,
DATA_SOURCE_FILTER_CONTROLLED_VIRUSTOTAL_RULE_GROUP,
);
}

getFixedFilters(): tFilter[] {
return [...this.getRuleGroupsFilter(), ...super.getFixedFilters()];
}
}
@@ -0,0 +1 @@
export * from './alerts-virustotal-data-source';
@@ -1,3 +1,4 @@
export * from './alerts-vulnerabilities';
export * from './alerts-data-source-repository';
export * from './alerts-data-source';
export * from './alerts-data-source';
export * from './alerts-virustotal';
15 changes: 12 additions & 3 deletions plugins/main/public/components/common/modules/modules-defaults.tsx
Expand Up @@ -28,6 +28,7 @@ import {
import { threatHuntingColumns } from '../wazuh-discover/config/data-grid-columns';
import { vulnerabilitiesColumns } from '../../overview/vulnerabilities/events/vulnerabilities-columns';
import { DashboardThreatHunting } from '../../overview/threat-hunting/dashboard/dashboard';
import { DashboardVirustotal } from '../../overview/virustotal/dashboard/dashboard';
import React from 'react';
import { dockerColumns } from '../../overview/docker/events/docker-columns';
import { googleCloudColumns } from '../../overview/google-cloud/events/google-cloud-columns';
Expand All @@ -48,6 +49,7 @@ import { WAZUH_VULNERABILITIES_PATTERN } from '../../../../common/constants';
import {
AlertsDataSource,
AlertsVulnerabilitiesDataSource,
AlertsVirustotalDataSource,
} from '../data-source';

const ALERTS_INDEX_PATTERN = 'wazuh-alerts-*';
Expand Down Expand Up @@ -254,10 +256,17 @@ export const ModulesDefaults = {
availableFor: ['manager', 'agent'],
},
virustotal: {
init: 'dashboard',
tabs: [
DashboardTab,
renderDiscoverTab(DEFAULT_INDEX_PATTERN, virustotalColumns),
{
id: 'dashboard',
name: 'Dashboard',
buttons: [ButtonModuleExploreAgent, ButtonModuleGenerateReport],
component: DashboardVirustotal,
},
renderDiscoverTab({
tableColumns: virustotalColumns,
DataSource: AlertsVirustotalDataSource,
}),
],
availableFor: ['manager', 'agent'],
},
Expand Down
Expand Up @@ -2,6 +2,8 @@ import { getAngularModule, getDataPlugin } from '../../../kibana-services';
import { AppState } from '../../../react-services/app-state';
import { FilterHandler } from '../../../utils/filter-handler';
import { VULNERABILITY_IMPLICIT_CLUSTER_MODE_FILTER } from '../../../../common/constants';
import { useFilterManager } from '../hooks';
import { FilterStateStore } from '../../../../../../src/plugins/data/common';

export class ModulesHelper {
static async getDiscoverScope() {
Expand Down
@@ -0,0 +1,163 @@
import React, { useState, useEffect } from 'react';
import { getPlugins } from '../../../../kibana-services';
import { ViewMode } from '../../../../../../../src/plugins/embeddable/public';
import { SearchResponse } from '../../../../../../../src/core/server';
import { IndexPattern } from '../../../../../../../src/plugins/data/common';
import { getDashboardPanels } from './dashboard_panels';
import { I18nProvider } from '@osd/i18n/react';
import useSearchBar from '../../../common/search-bar/use-search-bar';
import { getKPIsPanel } from './dashboard_panels_kpis';
import {
ErrorFactory,
ErrorHandler,
HttpError,
} from '../../../../react-services/error-management';
import { withErrorBoundary } from '../../../common/hocs/error-boundary/with-error-boundary';
import { SampleDataWarning } from '../../../visualize/components/sample-data-warning';
import {
AlertsDataSourceRepository,
PatternDataSource,
tParsedIndexPattern,
useDataSource,
} from '../../../common/data-source';
import { LoadingSpinner } from '../../../common/loading-spinner/loading-spinner';
import { DiscoverNoResults } from '../../../common/no-results/no-results';
import { AlertsVirustotalDataSource } from '../../../common/data-source/pattern/alerts/alerts-virustotal/alerts-virustotal-data-source';
import './virustotal_dashboard.scss';

const plugins = getPlugins();

const SearchBar = getPlugins().data.ui.SearchBar;

const DashboardByRenderer = plugins.dashboard.DashboardContainerByValueRenderer;
const DashboardVT: React.FC = () => {
const {
filters,
dataSource,
fetchFilters,
isLoading: isDataSourceLoading,
fetchData,
setFilters,
} = useDataSource<tParsedIndexPattern, PatternDataSource>({
DataSource: AlertsVirustotalDataSource,
repository: new AlertsDataSourceRepository(),
});

const [results, setResults] = useState<SearchResponse>({} as SearchResponse);

const { searchBarProps } = useSearchBar({
indexPattern: dataSource?.indexPattern as IndexPattern,
filters,
setFilters,
});
const { query, dateRangeFrom, dateRangeTo } = searchBarProps;

useEffect(() => {
if (isDataSourceLoading) {
return;
}
fetchData({
query,
dateRange: {
from: dateRangeFrom,
to: dateRangeTo,
},
})
.then(results => {
setResults(results);
})
.catch(error => {
const searchError = ErrorFactory.create(HttpError, {
error,
message: 'Error fetching alerts',
});
ErrorHandler.handleError(searchError);
});
}, [
isDataSourceLoading,
JSON.stringify(fetchFilters),
JSON.stringify(query),
dateRangeFrom,
dateRangeTo,
]);

return (
<I18nProvider>
<>
{isDataSourceLoading && !dataSource ? (
<LoadingSpinner />
) : (
<div className='wz-search-bar hide-filter-control'>
<SearchBar
appName='virustotal-searchbar'
{...searchBarProps}
showDatePicker={true}
showQueryInput={true}
showQueryBar={true}
showSaveQuery={true}
/>
</div>
)}
{!isDataSourceLoading && dataSource && results?.hits?.total > 0 ? (
<SampleDataWarning />
) : null}
{dataSource && results?.hits?.total === 0 ? (
<DiscoverNoResults />
) : null}
{!isDataSourceLoading && dataSource && results?.hits?.total > 0 ? (
<div className='virustotal-dashboard-responsive'>
<DashboardByRenderer
input={{
viewMode: ViewMode.VIEW,
panels: getKPIsPanel(dataSource?.id),
isFullScreenMode: false,
filters: fetchFilters ?? [],
useMargins: true,
id: 'kpis-virustotal-dashboard-tab',
timeRange: {
from: dateRangeFrom,
to: dateRangeTo,
},
title: 'KPIs Virustotal dashboard',
description: 'KPIs Dashboard of the Virustotal',
query: query,
refreshConfig: {
pause: false,
value: 15,
},
hidePanelTitles: true,
}}
/>
<DashboardByRenderer
input={{
viewMode: ViewMode.VIEW,
panels: getDashboardPanels(
dataSource?.id,
dataSource.getPinnedAgentFilter().length > 0,
),
isFullScreenMode: false,
filters: fetchFilters ?? [],
useMargins: true,
id: 'virustotal-dashboard-tab',
timeRange: {
from: dateRangeFrom,
to: dateRangeTo,
},
title: 'Virustotal dashboard',
description: 'Dashboard of the Virustotal',
query: query,
refreshConfig: {
pause: false,
value: 15,
},
hidePanelTitles: false,
}}
/>
</div>
) : null}
</>
</I18nProvider>
);
};

export const DashboardVirustotal = withErrorBoundary(DashboardVT);

0 comments on commit 19f48ef

Please sign in to comment.