From 3de2cc06ed10dc7eb03b615bfb463f101090f73e Mon Sep 17 00:00:00 2001 From: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com> Date: Fri, 9 Feb 2024 18:15:13 +0100 Subject: [PATCH 1/2] Replace discover Office 365 (#6290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace discover * Add changelog * Stringify geo_point type field --------- Co-authored-by: Julio César Biset <43619595+jbiset@users.noreply.github.com> --- CHANGELOG.md | 2 +- .../common/data-grid/data-grid-service.ts | 312 ++++++++++-------- .../common/modules/modules-defaults.js | 11 +- .../events/office-365-columns.tsx | 22 ++ 4 files changed, 201 insertions(+), 146 deletions(-) create mode 100644 plugins/main/public/components/overview/office-panel/events/office-365-columns.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb3e84d73..8e69f1130e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to the Wazuh app project will be documented in this file. ### Changed -- Removed embedded discover [#6120](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6120) [#6235](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6235) [#6254](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6254) [#6285](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6285) [#6275](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6275) [#6287](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6287) +- Removed embedded discover [#6120](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6120) [#6235](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6235) [#6254](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6254) [#6285](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6285) [#6290](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6290) [#6275](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6275) [#6287](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6287) - Develop logic of a new index for the fim module [#6227](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6227) - Allow editing groups for an agent from Endpoints Summary [#6250](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6250) diff --git a/plugins/main/public/components/common/data-grid/data-grid-service.ts b/plugins/main/public/components/common/data-grid/data-grid-service.ts index 4f9315037a..f1e95f7b1e 100644 --- a/plugins/main/public/components/common/data-grid/data-grid-service.ts +++ b/plugins/main/public/components/common/data-grid/data-grid-service.ts @@ -1,163 +1,187 @@ -import { SearchResponse } from "../../../../../../src/core/server"; +import { SearchResponse } from '../../../../../../src/core/server'; import * as FileSaver from '../../../services/file-saver'; -import { beautifyDate } from "../../agents/vuls/inventory/lib"; -import { SearchParams, search } from "../search-bar/search-bar-service"; -import { IFieldType, IndexPattern } from "../../../../../../src/plugins/data/common"; +import { beautifyDate } from '../../agents/vuls/inventory/lib'; +import { SearchParams, search } from '../search-bar/search-bar-service'; +import { IFieldType } from '../../../../../../src/plugins/data/common'; export const MAX_ENTRIES_PER_QUERY = 10000; import { EuiDataGridColumn } from '@elastic/eui'; -export const parseData = (resultsHits: SearchResponse['hits']['hits']): any[] => { - const data = resultsHits.map((hit) => { - if (!hit) { - return {} - } - const source = hit._source as object; - const data = { - ...source, - _id: hit._id, - _index: hit._index, - _type: hit._type, - _score: hit._score, - }; - return data; - }); +export const parseData = ( + resultsHits: SearchResponse['hits']['hits'], +): any[] => { + const data = resultsHits.map(hit => { + if (!hit) { + return {}; + } + const source = hit._source as object; + const data = { + ...source, + _id: hit._id, + _index: hit._index, + _type: hit._type, + _score: hit._score, + }; return data; -} - + }); + return data; +}; -export const getFieldFormatted = (rowIndex, columnId, indexPattern, rowsParsed) => { - const field = indexPattern.fields.find((field) => field.name === columnId); - let fieldValue = null; - if (columnId.includes('.')) { - // when the column is a nested field. The column could have 2 to n levels - // get dinamically the value of the nested field - const nestedFields = columnId.split('.'); - fieldValue = rowsParsed[rowIndex]; - nestedFields.forEach((field) => { - if (fieldValue) { - fieldValue = fieldValue[field]; - } - }); +export const getFieldFormatted = ( + rowIndex, + columnId, + indexPattern, + rowsParsed, +) => { + const field = indexPattern.fields.find(field => field.name === columnId); + let fieldValue = null; + if (columnId.includes('.')) { + // when the column is a nested field. The column could have 2 to n levels + // get dinamically the value of the nested field + const nestedFields = columnId.split('.'); + fieldValue = rowsParsed[rowIndex]; + nestedFields.forEach(field => { + if (fieldValue) { + fieldValue = fieldValue[field]; + } + }); + } else { + const rowValue = rowsParsed[rowIndex]; + // when not exist the column in the row value then the value is null + if (!rowValue.hasOwnProperty(columnId)) { + fieldValue = null; } else { - const rowValue = rowsParsed[rowIndex]; - // when not exist the column in the row value then the value is null - if(!rowValue.hasOwnProperty(columnId)){ - fieldValue = null; - }else{ - fieldValue = rowValue[columnId]?.formatted || rowValue[columnId]; - } - } - // when fieldValue is null or undefined then return a empty string - if (fieldValue === null || fieldValue === undefined) { - return ''; - } - // if is date field - if (field?.type === 'date') { - // @ts-ignore - fieldValue = beautifyDate(fieldValue); + fieldValue = rowValue[columnId]?.formatted || rowValue[columnId]; } - return fieldValue; -} + } + // when fieldValue is null or undefined then return a empty string + if (fieldValue === null || fieldValue === undefined) { + return ''; + } + // if is date field + if (field?.type === 'date') { + // @ts-ignore + fieldValue = beautifyDate(fieldValue); + } + + // if is geo_point field then convert to string to appear in the Discover table + if (field?.type === 'geo_point') { + // @ts-ignore + fieldValue = JSON.stringify(fieldValue); + } + return fieldValue; +}; // receive search params -export const exportSearchToCSV = async (params: SearchParams): Promise => { - const DEFAULT_MAX_SIZE_PER_CALL = 1000; - const { indexPattern, filters = [], query, sorting, fields, pagination } = params; - // when the pageSize is greater than the default max size per call (10000) - // then we need to paginate the search - const mustPaginateSearch = pagination?.pageSize && pagination?.pageSize > DEFAULT_MAX_SIZE_PER_CALL; - const pageSize = mustPaginateSearch ? DEFAULT_MAX_SIZE_PER_CALL : pagination?.pageSize; - const totalHits = pagination?.pageSize || DEFAULT_MAX_SIZE_PER_CALL; - let pageIndex = params.pagination?.pageIndex || 0; - let hitsCount = 0; - let allHits = []; - let searchResults; - if (mustPaginateSearch) { - // paginate the search - while (hitsCount < totalHits &&  hitsCount < MAX_ENTRIES_PER_QUERY) { - const searchParams = { - indexPattern, - filters, - query, - pagination: { - pageIndex, - pageSize, - }, - sorting, - fields, - }; - searchResults = await search(searchParams); - allHits = allHits.concat(searchResults.hits.hits); - hitsCount = allHits.length; - pageIndex++; - } - } else { - searchResults = await search(params); - allHits = searchResults.hits.hits; +export const exportSearchToCSV = async ( + params: SearchParams, +): Promise => { + const DEFAULT_MAX_SIZE_PER_CALL = 1000; + const { + indexPattern, + filters = [], + query, + sorting, + fields, + pagination, + } = params; + // when the pageSize is greater than the default max size per call (10000) + // then we need to paginate the search + const mustPaginateSearch = + pagination?.pageSize && pagination?.pageSize > DEFAULT_MAX_SIZE_PER_CALL; + const pageSize = mustPaginateSearch + ? DEFAULT_MAX_SIZE_PER_CALL + : pagination?.pageSize; + const totalHits = pagination?.pageSize || DEFAULT_MAX_SIZE_PER_CALL; + let pageIndex = params.pagination?.pageIndex || 0; + let hitsCount = 0; + let allHits = []; + let searchResults; + if (mustPaginateSearch) { + // paginate the search + while (hitsCount < totalHits && hitsCount < MAX_ENTRIES_PER_QUERY) { + const searchParams = { + indexPattern, + filters, + query, + pagination: { + pageIndex, + pageSize, + }, + sorting, + fields, + }; + searchResults = await search(searchParams); + allHits = allHits.concat(searchResults.hits.hits); + hitsCount = allHits.length; + pageIndex++; } - - const resultsFields = fields; - const data = allHits.map((hit) => { - // check if the field type is a date - const dateFields = indexPattern.fields.getByType('date'); - const dateFieldsNames = dateFields.map((field) => field.name); - const flattenHit = indexPattern.flattenHit(hit); - // replace the date fields with the formatted date - dateFieldsNames.forEach((field) => { - if (flattenHit[field]) { - flattenHit[field] = beautifyDate(flattenHit[field]); - } - }); - return flattenHit; + } else { + searchResults = await search(params); + allHits = searchResults.hits.hits; + } + + const resultsFields = fields; + const data = allHits.map(hit => { + // check if the field type is a date + const dateFields = indexPattern.fields.getByType('date'); + const dateFieldsNames = dateFields.map(field => field.name); + const flattenHit = indexPattern.flattenHit(hit); + // replace the date fields with the formatted date + dateFieldsNames.forEach(field => { + if (flattenHit[field]) { + flattenHit[field] = beautifyDate(flattenHit[field]); + } }); + return flattenHit; + }); - if (!resultsFields || resultsFields.length === 0){ - return; - } + if (!resultsFields || resultsFields.length === 0) { + return; + } - if (!data || data.length === 0) - return; + if (!data || data.length === 0) return; - const parsedData = data.map((row) => { - const parsedRow = resultsFields?.map((field) => { - const value = row[field]; - if (value === undefined || value === null) { - return ''; - } - if (typeof value === 'object') { - return JSON.stringify(value); - } - return `"${value}"`; - }); - return parsedRow?.join(','); - }).join('\n'); + const parsedData = data + .map(row => { + const parsedRow = resultsFields?.map(field => { + const value = row[field]; + if (value === undefined || value === null) { + return ''; + } + if (typeof value === 'object') { + return JSON.stringify(value); + } + return `"${value}"`; + }); + return parsedRow?.join(','); + }) + .join('\n'); - // create a csv file using blob - const blobData = new Blob( - [ - `${resultsFields?.join(',')}\n${parsedData}` - ], - { type: 'text/csv' } - ); + // create a csv file using blob + const blobData = new Blob([`${resultsFields?.join(',')}\n${parsedData}`], { + type: 'text/csv', + }); - if (blobData) { - // @ts-ignore - FileSaver?.saveAs(blobData, `events-${new Date().toISOString()}.csv`); - } -} + if (blobData) { + // @ts-ignore + FileSaver?.saveAs(blobData, `events-${new Date().toISOString()}.csv`); + } +}; export const parseColumns = (fields: IFieldType[]): EuiDataGridColumn[] => { - // remove _source field becuase is a object field and is not supported - fields = fields.filter((field) => field.name !== '_source'); - return fields.map((field) => { - return { - ...field, - id: field.name, - display: field.name, - schema: field.type, - actions: { - showHide: true, - }, - }; - }) || []; -} + // remove _source field becuase is a object field and is not supported + fields = fields.filter(field => field.name !== '_source'); + return ( + fields.map(field => { + return { + ...field, + id: field.name, + display: field.name, + schema: field.type, + actions: { + showHide: true, + }, + }; + }) || [] + ); +}; diff --git a/plugins/main/public/components/common/modules/modules-defaults.js b/plugins/main/public/components/common/modules/modules-defaults.js index 67a6b32a6c..41f5391fe3 100644 --- a/plugins/main/public/components/common/modules/modules-defaults.js +++ b/plugins/main/public/components/common/modules/modules-defaults.js @@ -27,6 +27,7 @@ import { vulnerabilitiesColumns } from '../../overview/vulnerabilities/events/vu import { DashboardFim } from '../../overview/fim/dashboard/dashboard'; import { InventoryFim } from '../../overview/fim/inventory/inventory'; import React from 'react'; +import { office365Columns } from '../../overview/office-panel/events/office-365-columns'; import { fileIntegrityMonitoringColumns } from '../../overview/fim/events/file-integrity-monitoring-columns'; import { configurationAssessmentColumns } from '../../agents/sca/events/configuration-assessment-columns'; @@ -151,7 +152,15 @@ export const ModulesDefaults = { buttons: [ButtonModuleExploreAgent], component: withModuleNotForAgent(OfficePanel), }, - { ...EventsTab, component: withModuleNotForAgent(Events) }, + { + ...renderDiscoverTab(DEFAULT_INDEX_PATTERN, office365Columns), + component: withModuleNotForAgent(() => ( + + )), + }, ], availableFor: ['manager'], }, diff --git a/plugins/main/public/components/overview/office-panel/events/office-365-columns.tsx b/plugins/main/public/components/overview/office-panel/events/office-365-columns.tsx new file mode 100644 index 0000000000..6549a4be5d --- /dev/null +++ b/plugins/main/public/components/overview/office-panel/events/office-365-columns.tsx @@ -0,0 +1,22 @@ +import { tDataGridColumn } from '../../../common/data-grid'; + +export const office365Columns: tDataGridColumn[] = [ + { + id: 'data.office365.Subscription', + }, + { + id: 'data.office365.Operation', + }, + { + id: 'data.office365.UserId', + }, + { + id: 'data.office365.ClientIP', + }, + { + id: 'rule.level', + }, + { + id: 'rule.id', + }, +]; From ac505175946cc3c4b64db550e445522d7b300f88 Mon Sep 17 00:00:00 2001 From: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:56:52 +0100 Subject: [PATCH 2/2] Replace discover AWS (#6288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace discover * Update CHANGELOG.md * Fix CHANGELOG * Change styles * Replace hook with wazuhCore hook --------- Co-authored-by: Julio César Biset <43619595+jbiset@users.noreply.github.com> Co-authored-by: jbiset Co-authored-by: Federico Rodriguez --- CHANGELOG.md | 2 +- .../common/doc-viewer/doc-viewer.tsx | 17 ++++++---------- .../public/components/common/hooks/index.ts | 1 - .../common/hooks/useDockedSideNav.tsx | 20 ------------------- .../common/modules/modules-defaults.js | 6 +++++- .../common/wazuh-discover/wz-discover.tsx | 4 ++-- .../events/amazon-web-services-columns.tsx | 16 +++++++++++++++ 7 files changed, 30 insertions(+), 36 deletions(-) delete mode 100644 plugins/main/public/components/common/hooks/useDockedSideNav.tsx create mode 100644 plugins/main/public/components/overview/amazon-web-services/events/amazon-web-services-columns.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e69f1130e..d46e33536d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to the Wazuh app project will be documented in this file. ### Changed -- Removed embedded discover [#6120](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6120) [#6235](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6235) [#6254](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6254) [#6285](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6285) [#6290](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6290) [#6275](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6275) [#6287](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6287) +- Removed embedded discover [#6120](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6120) [#6235](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6235) [#6254](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6254) [#6285](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6285) [#6288](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6288) [#6290](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6290) [#6275](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6275) [#6287](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6287) - Develop logic of a new index for the fim module [#6227](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6227) - Allow editing groups for an agent from Endpoints Summary [#6250](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6250) diff --git a/plugins/main/public/components/common/doc-viewer/doc-viewer.tsx b/plugins/main/public/components/common/doc-viewer/doc-viewer.tsx index c7ce052e16..70315ae2fc 100644 --- a/plugins/main/public/components/common/doc-viewer/doc-viewer.tsx +++ b/plugins/main/public/components/common/doc-viewer/doc-viewer.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import { escapeRegExp } from 'lodash'; import { i18n } from '@osd/i18n'; import { FieldIcon } from '../../../../../../src/plugins/opensearch_dashboards_react/public'; -import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; const COLLAPSE_LINE_LENGTH = 350; const DOT_PREFIX_RE = /(.).+?\./g; @@ -134,15 +134,10 @@ const DocViewer = (props: tDocViewerProps) => { {...fieldIconProps} /> - - - {displayName} - + + + {displayName} + @@ -156,7 +151,7 @@ const DocViewer = (props: tDocViewerProps) => { */ // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={{ __html: value as string }} - style={{ overflowY: 'auto' }} + style={{ overflowY: 'auto', wordBreak: 'break-all' }} /> diff --git a/plugins/main/public/components/common/hooks/index.ts b/plugins/main/public/components/common/hooks/index.ts index a4cd7dbf91..e3ce7584c7 100644 --- a/plugins/main/public/components/common/hooks/index.ts +++ b/plugins/main/public/components/common/hooks/index.ts @@ -28,4 +28,3 @@ export * from './use_async_action_run_on_start'; export { useEsSearch } from './use-es-search'; export { useValueSuggestion, IValueSuggestion } from './use-value-suggestion'; export * from './use-state-storage'; -export * from './useDockedSideNav'; diff --git a/plugins/main/public/components/common/hooks/useDockedSideNav.tsx b/plugins/main/public/components/common/hooks/useDockedSideNav.tsx deleted file mode 100644 index 489536b4d6..0000000000 --- a/plugins/main/public/components/common/hooks/useDockedSideNav.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useEffect, useState } from 'react'; -import { getChrome } from '../../../kibana-services'; - -export const useDockedSideNav = () => { - const [sideNavDocked, setSideNavDocked] = useState(false); - - useEffect(() => { - const isNavDrawerSubscription = getChrome() - .getIsNavDrawerLocked$() - .subscribe((value: boolean) => { - setSideNavDocked(value); - }); - - return () => { - isNavDrawerSubscription.unsubscribe(); - }; - }, []); - - return sideNavDocked; -}; diff --git a/plugins/main/public/components/common/modules/modules-defaults.js b/plugins/main/public/components/common/modules/modules-defaults.js index 41f5391fe3..eacc114770 100644 --- a/plugins/main/public/components/common/modules/modules-defaults.js +++ b/plugins/main/public/components/common/modules/modules-defaults.js @@ -27,6 +27,7 @@ import { vulnerabilitiesColumns } from '../../overview/vulnerabilities/events/vu import { DashboardFim } from '../../overview/fim/dashboard/dashboard'; import { InventoryFim } from '../../overview/fim/inventory/inventory'; import React from 'react'; +import { amazonWebServicesColumns } from '../../overview/amazon-web-services/events/amazon-web-services-columns'; import { office365Columns } from '../../overview/office-panel/events/office-365-columns'; import { fileIntegrityMonitoringColumns } from '../../overview/fim/events/file-integrity-monitoring-columns'; import { configurationAssessmentColumns } from '../../agents/sca/events/configuration-assessment-columns'; @@ -99,7 +100,10 @@ export const ModulesDefaults = { }, aws: { init: 'dashboard', - tabs: [DashboardTab, EventsTab], + tabs: [ + DashboardTab, + renderDiscoverTab(DEFAULT_INDEX_PATTERN, amazonWebServicesColumns), + ], availableFor: ['manager', 'agent'], }, gcp: { diff --git a/plugins/main/public/components/common/wazuh-discover/wz-discover.tsx b/plugins/main/public/components/common/wazuh-discover/wz-discover.tsx index 8b72bb01e4..0eec91a272 100644 --- a/plugins/main/public/components/common/wazuh-discover/wz-discover.tsx +++ b/plugins/main/public/components/common/wazuh-discover/wz-discover.tsx @@ -37,7 +37,7 @@ import useSearchBar from '../search-bar/use-search-bar'; import { search } from '../search-bar'; import { getPlugins } from '../../../kibana-services'; import { histogramChartInput } from './config/histogram-chart'; -import { useDockedSideNav } from '../hooks/useDockedSideNav'; +import { getWazuhCorePlugin } from '../../../kibana-services'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; import './discover.scss'; @@ -60,7 +60,7 @@ const WazuhDiscoverComponent = (props: WazuhDiscoverProps) => { ); const [isSearching, setIsSearching] = useState(false); const [isExporting, setIsExporting] = useState(false); - const sideNavDocked = useDockedSideNav(); + const sideNavDocked = getWazuhCorePlugin().hooks.useDockedSideNav(); const onClickInspectDoc = useMemo( () => (index: number) => { diff --git a/plugins/main/public/components/overview/amazon-web-services/events/amazon-web-services-columns.tsx b/plugins/main/public/components/overview/amazon-web-services/events/amazon-web-services-columns.tsx new file mode 100644 index 0000000000..f8a901f748 --- /dev/null +++ b/plugins/main/public/components/overview/amazon-web-services/events/amazon-web-services-columns.tsx @@ -0,0 +1,16 @@ +import { tDataGridColumn } from '../../../common/data-grid'; + +export const amazonWebServicesColumns: tDataGridColumn[] = [ + { + id: 'data.aws.source', + }, + { + id: 'rule.description', + }, + { + id: 'rule.level', + }, + { + id: 'rule.id', + }, +];