{(section === 'groups' && ) ||
(section === 'status' && ) ||
- (section === 'reporting' && ) ||
(section === 'statistics' && ) ||
(section === 'logs' && ) ||
(section === 'configuration' && (
diff --git a/plugins/main/public/controllers/management/components/management/reporting/__snapshots__/reporting-main.test.tsx.snap b/plugins/main/public/controllers/management/components/management/reporting/__snapshots__/reporting-main.test.tsx.snap
deleted file mode 100644
index 5941b82a4a..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/__snapshots__/reporting-main.test.tsx.snap
+++ /dev/null
@@ -1,7 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Reporting component renders correctly to match the snapshot 1`] = `
-
-
-
-`;
diff --git a/plugins/main/public/controllers/management/components/management/reporting/reporting-main.js b/plugins/main/public/controllers/management/components/management/reporting/reporting-main.js
deleted file mode 100644
index 8d64ac9915..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/reporting-main.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Wazuh app - React component for reporting
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- */
-import React, { Component } from 'react';
-
-import WzReduxProvider from '../../../../../redux/wz-redux-provider';
-//Wazuh groups overview
-import WzReportingOverview from './reporting-overview';
-import { compose } from 'redux';
-import {
- withGlobalBreadcrumb,
- withReduxProvider,
-} from '../../../../../components/common/hocs';
-import { reporting } from '../../../../../utils/applications';
-
-class WzReporting extends Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- render() {
- return (
-
-
-
- );
- }
-}
-
-export default compose(
- withReduxProvider,
- withGlobalBreadcrumb(props => {
- return [{ text: reporting.breadcrumbLabel }];
- }),
-)(WzReporting);
diff --git a/plugins/main/public/controllers/management/components/management/reporting/reporting-main.test.tsx b/plugins/main/public/controllers/management/components/management/reporting/reporting-main.test.tsx
deleted file mode 100644
index 25bb567001..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/reporting-main.test.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Wazuh app - React test for Reporting component.
- *
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- *
- */
-
-import React from 'react';
-import { shallow } from 'enzyme';
-import WzReporting from './reporting-main';
-
-jest.mock('../../../../../kibana-services', () => ({
- getAngularModule: jest.fn(),
- getHttp: () => ({
- basePath: {
- prepend: (str) => str,
- },
- }),
-}));
-
-describe('Reporting component', () => {
- it('renders correctly to match the snapshot', () => {
- const wrapper = shallow();
- expect(wrapper).toMatchSnapshot();
- });
-});
diff --git a/plugins/main/public/controllers/management/components/management/reporting/reporting-overview.js b/plugins/main/public/controllers/management/components/management/reporting/reporting-overview.js
deleted file mode 100644
index aa093b0d1a..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/reporting-overview.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Wazuh app - React component for building the reporting view
- *
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- */
-import React, { Component } from 'react';
-import {
- EuiFlexItem,
- EuiFlexGroup,
- EuiPanel,
- EuiTitle,
- EuiPage,
- EuiText
-} from '@elastic/eui';
-
-// Wazuh components
-import WzReportingTable from './reporting-table';
-import WzReportingActionButtons from './utils/actions-buttons-main';
-
-export class WzReportingOverview extends Component {
- _isMounted = false;
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- componentDidMount() {
- this._isMounted = true;
- }
-
- componentDidUpdate() {}
-
- componentWillUnmount() {
- this._isMounted = false;
- }
-
- render() {
- return (
-
-
-
-
-
-
-
- Reporting
-
-
-
-
-
-
-
-
-
- From here you can check all your reports.
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default WzReportingOverview;
diff --git a/plugins/main/public/controllers/management/components/management/reporting/reporting-table.js b/plugins/main/public/controllers/management/components/management/reporting/reporting-table.js
deleted file mode 100644
index 53aa7e6801..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/reporting-table.js
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Wazuh app - React component for reporting table.
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- */
-import React, { Component } from 'react';
-import { EuiInMemoryTable, EuiCallOut, EuiOverlayMask, EuiConfirmModal } from '@elastic/eui';
-
-import { connect } from 'react-redux';
-import ReportingHandler from './utils/reporting-handler';
-import { getToasts } from '../../../../../kibana-services';
-
-import {
- updateIsProcessing,
- updateShowModal,
- updateListItemsForRemove,
-} from '../../../../../redux/actions/reportingActions';
-
-import ReportingColums from './utils/columns-main';
-
-import { UI_ERROR_SEVERITIES } from '../../../../../react-services/error-orchestrator/types';
-import { UI_LOGGER_LEVELS } from '../../../../../../common/constants';
-import { getErrorOrchestrator } from '../../../../../react-services/common-services';
-
-class WzReportingTable extends Component {
- _isMounted = false;
- constructor(props) {
- super(props);
- this.state = {
- items: [],
- isLoading: false,
- };
-
- this.reportingHandler = ReportingHandler;
- }
-
- async componentDidMount() {
- this.props.updateIsProcessing(true);
- this._isMounted = true;
- }
-
- async componentDidUpdate() {
- try {
- if (this.props.state.isProcessing && this._isMounted) {
- await this.getItems();
- }
- } catch (error) {
- const options = {
- context: `${WzReportingTable.name}.componentDidUpdate`,
- level: UI_LOGGER_LEVELS.ERROR,
- severity: UI_ERROR_SEVERITIES.BUSINESS,
- error: {
- error: error,
- message: error.message || error,
- title: error.name || error,
- },
- };
- getErrorOrchestrator().handleError(options);
- }
- }
-
- componentWillUnmount() {
- this._isMounted = false;
- }
-
- /**
- * Loads the initial information
- */
- async getItems() {
- try {
- const rawItems = await this.reportingHandler.listReports();
- const {reports: items = []} = rawItems?.data;
- this.setState({
- items,
- isProcessing: false,
- });
- this.props.updateIsProcessing(false);
- } catch (error) {
- this.props.updateIsProcessing(false);
- throw error;
- }
- }
-
- render() {
- this.reportingColumns = new ReportingColums(this.props);
- const { isLoading, error } = this.props.state;
- const { items } = this.state;
- const columns = this.reportingColumns.columns;
- const message = isLoading ? null : 'No results...';
-
- const deleteReport = (itemList) => {
- try {
- this.deleteReport(itemList);
- this.props.updateShowModal(false);
- } catch (error) {
- const options = {
- context: `${WzReportingTable.name}.deleteReport`,
- level: UI_LOGGER_LEVELS.ERROR,
- severity: UI_ERROR_SEVERITIES.BUSINESS,
- error: {
- error: error,
- message: error.message || error,
- title: `${error.name}: Error deleting report`,
- },
- };
- getErrorOrchestrator().handleError(options);
- }
- };
-
- const sorting = {
- sort: {
- field: 'date',
- direction: 'desc',
- },
- };
-
- if (!error) {
- const itemList = this.props.state.itemList;
- return (
-
-
- {this.props.state.showModal ? (
-
- this.props.updateShowModal(false)}
- onConfirm={() => deleteReport(itemList)}
- cancelButtonText="Cancel"
- confirmButtonText="Delete"
- defaultFocusedButton="cancel"
- buttonColor="danger"
- >
-
- ) : null}
-
- );
- } else {
- return ;
- }
- }
-
- showToast = (color, title, text, time) => {
- getToasts().add({
- color: color,
- title: title,
- text: text,
- toastLifeTimeMs: time,
- });
- };
-
- async deleteReport(items) {
- try {
- const results = items.map(async (item, i) => {
- await this.reportingHandler.deleteReport(item.name);
- });
- await Promise.all(results);
- this.props.updateIsProcessing(true);
- this.showToast('success', 'Success', 'Deleted successfully', 3000);
- } catch (error) {
- throw error;
- }
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- state: state.reportingReducers,
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- updateIsProcessing: (isProcessing) => dispatch(updateIsProcessing(isProcessing)),
- updateShowModal: (showModal) => dispatch(updateShowModal(showModal)),
- updateListItemsForRemove: (itemList) => dispatch(updateListItemsForRemove(itemList)),
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(WzReportingTable);
diff --git a/plugins/main/public/controllers/management/components/management/reporting/utils/actions-buttons-main.js b/plugins/main/public/controllers/management/components/management/reporting/utils/actions-buttons-main.js
deleted file mode 100644
index 92c70bc926..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/utils/actions-buttons-main.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Wazuh app - React component for reporting buttons
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- */
-import React, { Component, Fragment } from 'react';
-// Eui components
-import { EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
-
-import { connect } from 'react-redux';
-
-import { updateIsProcessing } from '../../../../../../redux/actions/reportingActions';
-
-import { UI_ERROR_SEVERITIES } from '../../../../../../react-services/error-orchestrator/types';
-import { UI_LOGGER_LEVELS } from '../../../../../../../common/constants';
-import { getErrorOrchestrator } from '../../../../../../react-services/common-services';
-
-class WzReportingActionButtons extends Component {
- _isMounted = false;
-
- constructor(props) {
- super(props);
- }
-
- componentDidMount() {
- this._isMounted = true;
- }
-
- componentDidUpdate() {}
-
- componentWillUnmount() {
- this._isMounted = false;
- }
-
- /**
- * Refresh the items
- */
- async refresh() {
- try {
- this.props.updateIsProcessing(true);
- } catch (error) {
- const options = {
- context: `${WzReportingActionButtons.name}.refresh`,
- level: UI_LOGGER_LEVELS.ERROR,
- severity: UI_ERROR_SEVERITIES.UI,
- error: {
- error: error,
- message: error.message || error,
- title: error.name || error,
- },
- };
- getErrorOrchestrator().handleError(options);
- }
- }
-
- render() {
- // Refresh
- const refreshButton = (
- await this.refresh()}
- >
- Refresh
-
- );
-
- return (
-
- {refreshButton}
-
- );
- }
-}
-
-const mapStateToProps = state => {
- return {
- state: state.reportingReducers
- };
-};
-
-const mapDispatchToProps = dispatch => {
- return {
- updateIsProcessing: isProcessing =>
- dispatch(updateIsProcessing(isProcessing))
- };
-};
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(WzReportingActionButtons);
diff --git a/plugins/main/public/controllers/management/components/management/reporting/utils/columns-main.js b/plugins/main/public/controllers/management/components/management/reporting/utils/columns-main.js
deleted file mode 100644
index b9c288ce1f..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/utils/columns-main.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import React from 'react';
-import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
-import ReportingHandler from './reporting-handler';
-import moment from 'moment-timezone';
-import { WzButton } from '../../../../../../components/common/buttons';
-import { getHttp, getUiSettings } from '../../../../../../kibana-services';
-import { formatUIDate } from '../../../../../../react-services/time-service';
-export default class ReportingColums {
- constructor(tableProps) {
- this.tableProps = tableProps;
- this.reportingHandler = ReportingHandler;
-
- this.buildColumns = () => {
- this.columns = [
- {
- field: 'name',
- name: 'File',
- align: 'left',
- sortable: true,
- },
- {
- field: 'size',
- name: 'Size',
- render: size => {
- const fixedSize = size / 1024;
- return `${fixedSize.toFixed(2)}KB`;
- },
- sortable: true,
- },
- {
- field: 'date',
- name: 'Created',
- render: value => formatUIDate(value),
- sortable: true,
- },
- ];
- this.columns.push({
- name: 'Actions',
- align: 'left',
- render: item => {
- return (
-
-
- this.goReport(item.name)}
- color='primary'
- />
-
-
- {
- this.tableProps.updateListItemsForRemove([item]);
- this.tableProps.updateShowModal(true);
- }}
- color='danger'
- isDisabled={item.name === 'default'}
- />
-
- );
- },
- });
- };
-
- this.buildColumns();
- }
-
- /**
- * Downloads the report
- * @param {*} name The name of the report
- */
- goReport(name) {
- window.open(getHttp().basePath.prepend(`/reports/${name}`), '_blank');
- }
-
- /**
- * Returns given date adding the timezone offset
- * @param {string} date Date
- */
- offset(d) {
- try {
- const dateUTC = moment.utc(d);
- const kibanaTz = getUiSettings().get('dateFormat:tz');
- const dateLocate =
- kibanaTz === 'Browser'
- ? moment(dateUTC).local()
- : moment(dateUTC).tz(kibanaTz);
- return dateLocate.format('YYYY/MM/DD HH:mm:ss');
- } catch (error) {
- throw new Error(error);
- }
- }
-}
diff --git a/plugins/main/public/controllers/management/components/management/reporting/utils/reporting-handler.js b/plugins/main/public/controllers/management/components/management/reporting/utils/reporting-handler.js
deleted file mode 100644
index e728fd9066..0000000000
--- a/plugins/main/public/controllers/management/components/management/reporting/utils/reporting-handler.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Wazuh app - Reporting handler service
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- */
-
-import { WzRequest } from '../../../../../../react-services/wz-request';
-
-export default class ReportingHandler {
- /**
- * Get list reports
- * @param {String} name
- */
- static async listReports() {
- try {
- const result = await WzRequest.genericReq('GET', '/reports');
- return result;
- } catch (error) {
- throw error;
- }
- }
-
- /**
- * Delete report
- * @param {String} name
- */
- static async deleteReport(name) {
- try {
- const result = await WzRequest.genericReq(
- 'DELETE',
- `/reports/${name}`
- );
- return result;
- } catch (error) {
- throw error;
- }
- }
-}
diff --git a/plugins/main/public/controllers/overview/overview.js b/plugins/main/public/controllers/overview/overview.js
index 3060f0a533..5f8b8ea7f6 100644
--- a/plugins/main/public/controllers/overview/overview.js
+++ b/plugins/main/public/controllers/overview/overview.js
@@ -37,7 +37,6 @@ export class OverviewController {
* @param {*} $rootScope
* @param {*} errorHandler
* @param {*} commonData
- * @param {*} reportingService
* @param {*} visFactoryService
*/
constructor(
@@ -46,7 +45,6 @@ export class OverviewController {
$rootScope,
errorHandler,
commonData,
- reportingService,
visFactoryService,
$route,
) {
@@ -57,7 +55,6 @@ export class OverviewController {
this.errorHandler = errorHandler;
this.tabVisualizations = new TabVisualizations();
this.commonData = commonData;
- this.reportingService = reportingService;
this.visFactoryService = visFactoryService;
this.wazuhConfig = new WazuhConfig();
this.visFactoryService = VisFactoryHandler;
@@ -98,7 +95,6 @@ export class OverviewController {
this.$scope.getMainProps = resultState => {
return {
section: this.tab,
- disabledReport: resultState !== 'ready',
agentsSelectionProps: this.agentsSelectionProps,
switchSubTab: subtab => this.switchSubtab(subtab),
};
@@ -326,13 +322,6 @@ export class OverviewController {
this.$scope.$applyAsync();
}
- /**
- * Transform a visualization into an image
- */
- startVis2Png() {
- return this.reportingService.startVis2Png(this.tab);
- }
-
/**
* This fetch de agents summary
*/
diff --git a/plugins/main/public/react-services/export-file.ts b/plugins/main/public/react-services/export-file.ts
new file mode 100644
index 0000000000..9ec563c30b
--- /dev/null
+++ b/plugins/main/public/react-services/export-file.ts
@@ -0,0 +1,33 @@
+import { getToasts } from '../kibana-services';
+import * as FileSaver from '../services/file-saver';
+
+interface IExportResponseToFile {
+ headers: {
+ 'content-disposition'?: string;
+ 'content-type': string;
+ };
+}
+/**
+ * Export response data to file
+ */
+export const exportResponseToFile = async (response: IExportResponseToFile) => {
+ // Get the filename from the response headers
+ const [_, filename] =
+ response?.headers?.['content-disposition']?.match?.(/filename="([^"]+)"/) ||
+ [];
+
+ // Create blob
+ const blob = new Blob([response.data], {
+ type: response.headers['content-type'],
+ });
+
+ // Save file from frontend side
+ FileSaver.saveAs(blob, filename);
+
+ // Display a toast message
+ getToasts().add({
+ color: 'success',
+ title: 'File downloaded',
+ toastLifeTimeMs: 4000,
+ });
+};
diff --git a/plugins/main/public/react-services/reporting.js b/plugins/main/public/react-services/reporting.js
index 2306b60d80..4557a6aaa5 100644
--- a/plugins/main/public/react-services/reporting.js
+++ b/plugins/main/public/react-services/reporting.js
@@ -10,7 +10,6 @@
* Find more information about this on the LICENSE file.
*/
-import $ from 'jquery';
import moment from 'moment';
import { WazuhConfig } from '../react-services/wazuh-config';
import { AppState } from './app-state';
@@ -22,6 +21,10 @@ import { getAngularModule, getDataPlugin, getToasts } from '../kibana-services';
import { UI_LOGGER_LEVELS } from '../../common/constants';
import { UI_ERROR_SEVERITIES } from './error-orchestrator/types';
import { getErrorOrchestrator } from './common-services';
+import { exportResponseToFile } from './export-file';
+import domtoimage from '../utils/dom-to-image';
+import store from '../redux/store';
+
const app = getAngularModule();
export class ReportingService {
@@ -59,63 +62,50 @@ export class ReportingService {
return idArray;
}
- async startVis2Png(tab, agents = false, syscollectorFilters = null) {
+ async getVisualizationsFromDOM() {
+ const domVisualizations = document.querySelectorAll('.visualization');
+ return await Promise.all(
+ Array.from(domVisualizations).map(async node => {
+ return {
+ element: await domtoimage.toPng(node),
+ width: node.clientWidth,
+ height: node.clientHeight,
+ title: node?.parentNode?.parentNode?.parentNode?.querySelector(
+ 'figcaption > h2 > .embPanel__titleInner',
+ )?.textContent,
+ };
+ }),
+ );
+ }
+
+ async getDataSourceSearchContext() {
+ return store.getState().reportingReducers?.dataSourceSearchContext;
+ }
+
+ async startVis2Png(tab, agents = false, searchContext = null) {
try {
- if (this.vis2png.isWorking()) {
- this.showToast('danger', 'Error', 'Report in progress', 4000);
- return;
- }
this.$rootScope.reportBusy = true;
this.$rootScope.reportStatus = 'Generating report...0%';
this.$rootScope.$applyAsync();
-
- this.vis2png.clear();
-
- const rawVisualizations = this.rawVisualizations
- .getList()
- .filter(this.removeTableVis);
-
- let idArray = [];
- if (tab === 'general') {
- idArray = this.removeAgentStatusVis(
- rawVisualizations.map(item => item.id),
- );
- } else {
- idArray = rawVisualizations.map(item => item.id);
- }
-
- const visualizationIDList = [];
- for (const item of idArray) {
- const tmpHTMLElement = $(`#${item}`);
- if (tmpHTMLElement[0]) {
- this.vis2png.assignHTMLItem(item, tmpHTMLElement);
- visualizationIDList.push(item);
- }
- }
-
- const appliedFilters = await this.visHandlers.getAppliedFilters(
- syscollectorFilters,
- );
+ const dataSourceContext =
+ searchContext || (await this.getDataSourceSearchContext());
+ const visualizations = await this.getVisualizationsFromDOM();
const dataplugin = await getDataPlugin();
const serverSideQuery = dataplugin.query.getOpenSearchQuery();
- const array = await this.vis2png.checkArray(visualizationIDList);
-
const browserTimezone = moment.tz.guess(true);
const data = {
- array,
+ array: visualizations,
serverSideQuery, // Used for applying the same filters on the server side requests
- filters: appliedFilters.filters,
- time: appliedFilters.time,
- searchBar: appliedFilters.searchBar,
- tables: appliedFilters.tables,
+ filters: dataSourceContext.filters,
+ time: dataSourceContext.time,
+ searchBar: dataSourceContext?.query?.query || '',
+ tables: [], // TODO: check is this is used
tab,
section: agents ? 'agents' : 'overview',
agents,
browserTimezone,
- indexPatternTitle: (
- await getDataPlugin().indexPatterns.get(AppState.getCurrentPattern())
- ).title,
+ indexPatternTitle: dataSourceContext.indexPattern.title,
apiId: JSON.parse(AppState.getCurrentAPI()).id,
};
@@ -123,18 +113,15 @@ export class ReportingService {
tab === 'syscollector'
? `/reports/agents/${agents}/inventory`
: `/reports/modules/${tab}`;
- await WzRequest.genericReq('POST', apiEndpoint, data);
+ const response = await WzRequest.genericReq('POST', apiEndpoint, data, {
+ requestClientOptions: { responseType: 'blob' },
+ });
+
+ exportResponseToFile(response);
this.$rootScope.reportBusy = false;
this.$rootScope.reportStatus = false;
this.$rootScope.$applyAsync();
- this.showToast(
- 'success',
- 'Created report',
- 'Success. Go to Dashboard management > Reporting',
- 4000,
- );
- return;
} catch (error) {
this.$rootScope.reportBusy = false;
this.$rootScope.reportStatus = false;
@@ -174,18 +161,14 @@ export class ReportingService {
type === 'agentConfig'
? `/reports/agents/${obj.id}`
: `/reports/groups/${obj.name}`;
- await WzRequest.genericReq('POST', apiEndpoint, data);
+ const response = await WzRequest.genericReq('POST', apiEndpoint, data, {
+ requestClientOptions: { responseType: 'blob' },
+ });
+ exportResponseToFile(response);
this.$rootScope.reportBusy = false;
this.$rootScope.reportStatus = false;
this.$rootScope.$applyAsync();
- this.showToast(
- 'success',
- 'Created report',
- 'Success. Go to Dashboard management > Reporting',
- 4000,
- );
- return;
} catch (error) {
this.$rootScope.reportBusy = false;
this.$rootScope.reportStatus = false;
diff --git a/plugins/main/public/react-services/wz-request.ts b/plugins/main/public/react-services/wz-request.ts
index fa0785eb29..a55ad7b2c6 100644
--- a/plugins/main/public/react-services/wz-request.ts
+++ b/plugins/main/public/react-services/wz-request.ts
@@ -36,10 +36,12 @@ export class WzRequest {
shouldRetry?: boolean;
checkCurrentApiIsUp?: boolean;
overwriteHeaders?: any;
+ requestClientOptions?: any;
} = {
shouldRetry: true,
checkCurrentApiIsUp: true,
overwriteHeaders: {},
+ requestClientOptions: {},
},
) {
const shouldRetry =
@@ -54,6 +56,10 @@ export class WzRequest {
typeof extraOptions.overwriteHeaders === 'object'
? extraOptions.overwriteHeaders
: {};
+ const requestClientOptions =
+ typeof extraOptions.requestClientOptions === 'object'
+ ? extraOptions.requestClientOptions
+ : {};
try {
if (!method || !path) {
throw new Error('Missing parameters');
@@ -73,6 +79,7 @@ export class WzRequest {
url: url,
data: payload,
timeout: timeout,
+ ...requestClientOptions,
};
const data = await request(options);
diff --git a/plugins/main/public/redux/actions/reportingActions.js b/plugins/main/public/redux/actions/reportingActions.js
index 9ada6e18e3..a6dfd76ad3 100644
--- a/plugins/main/public/redux/actions/reportingActions.js
+++ b/plugins/main/public/redux/actions/reportingActions.js
@@ -17,7 +17,7 @@
export const updateIsProcessing = isProcessing => {
return {
type: 'UPDATE_IS_PROCESSING',
- isProcessing: isProcessing
+ isProcessing: isProcessing,
};
};
@@ -28,7 +28,7 @@ export const updateIsProcessing = isProcessing => {
export const updateListItemsForRemove = itemList => {
return {
type: 'UPDATE_LIST_ITEMS_FOR_REMOVE',
- itemList: itemList
+ itemList: itemList,
};
};
@@ -39,7 +39,7 @@ export const updateListItemsForRemove = itemList => {
export const updateShowModal = showModal => {
return {
type: 'UPDATE_SHOW_MODAL',
- showModal: showModal
+ showModal: showModal,
};
};
@@ -49,6 +49,18 @@ export const updateShowModal = showModal => {
*/
export const cleanInfo = () => {
return {
- type: 'CLEAN_INFO'
+ type: 'CLEAN_INFO',
};
};
+
+/**
+ * Update reporting data source search context
+ * @param {Object} dataSourceSearchContext
+ */
+export const updateReportingCommunicateSearchContext =
+ dataSourceSearchContext => {
+ return {
+ type: 'UPDATE_REPORTING_DATA_SEARCH_SOURCE_CONTEXT',
+ dataSourceSearchContext,
+ };
+ };
diff --git a/plugins/main/public/redux/reducers/reportingReducers.js b/plugins/main/public/redux/reducers/reportingReducers.js
index 5e53baa9b2..063b11a7b8 100644
--- a/plugins/main/public/redux/reducers/reportingReducers.js
+++ b/plugins/main/public/redux/reducers/reportingReducers.js
@@ -9,12 +9,14 @@
*
* Find more information about this on the LICENSE file.
*/
+import { cloneDeep } from 'lodash';
const initialState = {
isLoading: false,
isProcessing: false,
itemList: [],
- showModal: false
+ showModal: false,
+ dataSourceSearchContext: null,
};
const statusReducers = (state = initialState, action) => {
@@ -22,19 +24,19 @@ const statusReducers = (state = initialState, action) => {
return {
...state,
isProcessing: action.isProcessing,
- isLoading: action.isProcessing
+ isLoading: action.isProcessing,
};
}
if (action.type === 'UPDATE_LIST_ITEMS_FOR_REMOVE') {
return {
...state,
- itemList: action.itemList
+ itemList: action.itemList,
};
}
if (action.type === 'UPDATE_SHOW_MODAL') {
return {
...state,
- showModal: action.showModal
+ showModal: action.showModal,
};
}
if (action.type === 'CLEAN_INFO') {
@@ -43,7 +45,13 @@ const statusReducers = (state = initialState, action) => {
isLoading: false,
isProcessing: false,
itemList: [],
- showModal: false
+ showModal: false,
+ };
+ }
+ if (action.type === 'UPDATE_REPORTING_DATA_SEARCH_SOURCE_CONTEXT') {
+ return {
+ ...state,
+ dataSourceSearchContext: cloneDeep(action.dataSourceSearchContext),
};
}
diff --git a/plugins/main/public/services/index.js b/plugins/main/public/services/index.js
index a82f4124c9..dea9069f72 100644
--- a/plugins/main/public/services/index.js
+++ b/plugins/main/public/services/index.js
@@ -14,7 +14,6 @@ import './theming';
import './routes';
import { CSVRequest } from './csv-request';
import { CommonData } from './common-data';
-import { ReportingService } from './reporting';
import { VisFactoryService } from './vis-factory-handler';
import './region-maps';
import './order-object-by';
@@ -28,7 +27,6 @@ app
.service('errorHandler', ErrorHandler)
.service('csvReq', CSVRequest)
.service('commonData', CommonData)
- .service('reportingService', ReportingService)
.service('visFactoryService', VisFactoryService)
.service('configHandler', ConfigHandler)
.service('checkDaemonsStatus', CheckDaemonsStatus);
diff --git a/plugins/main/public/services/reporting.js b/plugins/main/public/services/reporting.js
deleted file mode 100644
index e44106bb66..0000000000
--- a/plugins/main/public/services/reporting.js
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Wazuh app - Reporting service
- * Copyright (C) 2015-2022 Wazuh, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Find more information about this on the LICENSE file.
- */
-
-import $ from 'jquery';
-import moment from 'moment';
-import { WazuhConfig } from '../react-services/wazuh-config';
-import { GenericRequest } from '../react-services/generic-request';
-import { ErrorHandler } from '../react-services/error-handler';
-
-export class ReportingService {
- constructor(
- $rootScope,
- vis2png,
- rawVisualizations,
- visHandlers,
- errorHandler,
- ) {
- this.$rootScope = $rootScope;
- this.vis2png = vis2png;
- this.rawVisualizations = rawVisualizations;
- this.visHandlers = visHandlers;
- this.genericReq = GenericRequest;
- this.errorHandler = errorHandler;
- this.wazuhConfig = new WazuhConfig();
- }
- removeTableVis(visList) {
- const attributes = JSON.parse(visList.attributes.visState);
- return attributes.type !== 'table';
- }
-
- removeAgentStatusVis(idArray) {
- const monitoringEnabled =
- this.wazuhConfig.getConfig()['wazuh.monitoring.enabled'];
- if (!monitoringEnabled) {
- const visArray = idArray.filter(vis => {
- return vis !== 'Wazuh-App-Overview-General-Agents-status';
- });
- return visArray;
- }
- return idArray;
- }
-
- async startVis2Png(tab, isAgents = false, syscollectorFilters = null) {
- try {
- if (this.vis2png.isWorking()) {
- ErrorHandler.handle('Report in progress', 'Reporting', {
- warning: true,
- });
- return;
- }
- this.$rootScope.reportBusy = true;
- this.$rootScope.reportStatus = 'Generating report...0%';
- this.$rootScope.$applyAsync();
-
- this.vis2png.clear();
-
- const rawVisualizations = this.rawVisualizations
- .getList()
- .filter(this.removeTableVis);
-
- let idArray = [];
- if (tab === 'general') {
- idArray = this.removeAgentStatusVis(
- rawVisualizations.map(item => item.id),
- );
- } else {
- idArray = rawVisualizations.map(item => item.id);
- }
-
- for (const item of idArray) {
- const tmpHTMLElement = $(`#${item}`);
- this.vis2png.assignHTMLItem(item, tmpHTMLElement);
- }
-
- const appliedFilters = await this.visHandlers.getAppliedFilters(
- syscollectorFilters,
- );
-
- const array = await this.vis2png.checkArray(idArray);
- const name = `wazuh-${isAgents ? 'agents' : 'overview'}-${tab}-${
- (Date.now() / 1000) | 0
- }.pdf`;
-
- const browserTimezone = moment.tz.guess(true);
-
- const data = {
- array,
- name,
- title: isAgents ? `Agents ${tab}` : `Overview ${tab}`,
- filters: appliedFilters.filters,
- time: appliedFilters.time,
- searchBar: appliedFilters.searchBar,
- tables: appliedFilters.tables,
- tab,
- section: isAgents ? 'agents' : 'overview',
- isAgents,
- browserTimezone,
- };
-
- await this.genericReq.request('POST', '/reports', data);
-
- this.$rootScope.reportBusy = false;
- this.$rootScope.reportStatus = false;
- this.$rootScope.$applyAsync();
- ErrorHandler.info(
- 'Success. Go to Dashboard management > Reporting',
- 'Reporting',
- );
-
- return;
- } catch (error) {
- this.$rootScope.reportBusy = false;
- this.$rootScope.reportStatus = false;
- throw error;
- }
- }
-
- async startConfigReport(obj, type, components) {
- try {
- this.$rootScope.reportBusy = true;
- this.$rootScope.reportStatus = 'Generating PDF document...';
- this.$rootScope.$applyAsync();
-
- const docType =
- type === 'agentConfig'
- ? `wazuh-agent-${obj.id}`
- : `wazuh-group-${obj.name}`;
-
- const name = `${docType}-configuration-${(Date.now() / 1000) | 0}.pdf`;
- const browserTimezone = moment.tz.guess(true);
-
- const data = {
- array: [],
- name,
- filters: [
- type === 'agentConfig' ? { agent: obj.id } : { group: obj.name },
- ],
- time: '',
- searchBar: '',
- tables: [],
- tab: type,
- browserTimezone,
- components,
- };
-
- await this.genericReq.request('POST', '/reports', data);
-
- this.$rootScope.reportBusy = false;
- this.$rootScope.reportStatus = false;
- this.$rootScope.$applyAsync();
- ErrorHandler.info(
- 'Success. Go to Dashboard management > Reporting',
- 'Reporting',
- );
-
- return;
- } catch (error) {
- this.$rootScope.reportBusy = false;
- this.$rootScope.reportStatus = false;
- this.$rootScope.$applyAsync();
- throw error;
- }
- }
-}
diff --git a/plugins/main/public/services/request-handler.js b/plugins/main/public/services/request-handler.js
index 80d2a183fa..1ea22638fe 100644
--- a/plugins/main/public/services/request-handler.js
+++ b/plugins/main/public/services/request-handler.js
@@ -2,16 +2,16 @@ import axios from 'axios';
import { HTTP_STATUS_CODES } from '../../common/constants';
let allow = true;
-export let unregisterInterceptor = () => { };
+export let unregisterInterceptor = () => {};
const source = axios.CancelToken.source();
const disableRequests = () => {
allow = false;
source.cancel('Requests cancelled');
return;
-}
+};
-export const initializeInterceptor = (core) => {
+export const initializeInterceptor = core => {
unregisterInterceptor = core.http.intercept({
responseError: (httpErrorResponse, controller) => {
if (
@@ -21,37 +21,47 @@ export const initializeInterceptor = (core) => {
}
},
request: (current, controller) => {
- if (
- !allow
- ) {
- throw new Error("Disable request");
- };
+ if (!allow) {
+ throw new Error('Disable request');
+ }
},
});
-}
+};
export const request = async (options = {}) => {
if (!allow) {
return Promise.reject('Requests are disabled');
- };
+ }
if (!options.method || !options.url) {
- return Promise.reject("Missing parameters");
- };
+ return Promise.reject('Missing parameters');
+ }
options = {
- ...options, cancelToken: source?.token
+ ...options,
+ cancelToken: source?.token,
};
if (allow) {
try {
const requestData = await axios(options);
return Promise.resolve(requestData);
- }
- catch (e) {
- if (e.response?.data?.message === 'Unauthorized' || e.response?.data?.message === 'Authentication required') {
+ } catch (e) {
+ /* Transform the response when the data is comming as a blob to POJO.
+ Using the responseType: blob causes the response data is formatted to a blob, despite
+ the response can be a json. */
+ if (
+ e.response?.data?.constructor?.name === 'Blob' &&
+ e?.response?.headers?.['content-type']?.includes?.('application/json')
+ ) {
+ e.response.data = JSON.parse(await e.response.data.text());
+ }
+ if (
+ e.response?.data?.message === 'Unauthorized' ||
+ e.response?.data?.message === 'Authentication required'
+ ) {
disableRequests();
window.location.reload();
}
return Promise.reject(e);
}
}
-}
+};
diff --git a/plugins/main/public/utils/applications.ts b/plugins/main/public/utils/applications.ts
index e9a82082ac..47377dc813 100644
--- a/plugins/main/public/utils/applications.ts
+++ b/plugins/main/public/utils/applications.ts
@@ -656,25 +656,6 @@ export const logs = {
redirectTo: () => '/manager/?tab=logs',
};
-export const reporting = {
- category: 'wz-category-dashboard-management',
- id: 'reporting',
- title: i18n.translate('wz-app-reporting-title', {
- defaultMessage: 'Reporting',
- }),
- breadcrumbLabel: i18n.translate('wz-app-reporting-breadcrumbLabel', {
- defaultMessage: 'Reporting',
- }),
- description: i18n.translate('wz-app-reporting-description', {
- defaultMessage: 'Check your stored Wazuh reports.',
- }),
- euiIconType: 'indexRollupApp',
- order: 702,
- showInOverviewApp: false,
- showInAgentMenu: false,
- redirectTo: () => '/manager/?tab=reporting',
-};
-
export const settings = {
category: 'wz-category-server-management',
id: 'settings',
@@ -860,7 +841,6 @@ export const Applications = [
statistics,
logs,
settings,
- reporting,
serverApis,
sampleData,
appSettings,
diff --git a/plugins/main/server/controllers/wazuh-reporting-security-endpoint-handler.test.ts b/plugins/main/server/controllers/wazuh-reporting-security-endpoint-handler.test.ts
deleted file mode 100644
index 84a585d1ce..0000000000
--- a/plugins/main/server/controllers/wazuh-reporting-security-endpoint-handler.test.ts
+++ /dev/null
@@ -1,278 +0,0 @@
-import md5 from 'md5';
-import fs from 'fs';
-import { WazuhReportingCtrl } from './wazuh-reporting';
-
-jest.mock('../lib/reporting/extended-information', () => ({
- extendedInformation: () => {},
- buildAgentsTable: () => {},
-}));
-
-jest.mock('../lib/reporting/printer', () => {
- class ReportPrinterMock {
- constructor() {}
- addContent() {}
- addConfigTables() {}
- addTables() {}
- addTimeRangeAndFilters() {}
- addVisualizations() {}
- formatDate() {}
- checkTitle() {}
- addSimpleTable() {}
- addList() {}
- addNewLine() {}
- addContentWithNewLine() {}
- addAgentsFilters() {}
- print() {}
- }
- return {
- ReportPrinter: ReportPrinterMock,
- };
-});
-
-const getMockerUserContext = (username: string) => ({
- username,
- hashUsername: md5(username),
-});
-
-const mockContext = (username: string) => ({
- wazuh: {
- security: {
- getCurrentUser: () => getMockerUserContext(username),
- },
- logger: {
- info: jest.fn(),
- warn: jest.fn(),
- error: jest.fn(),
- debug: jest.fn(),
- get: jest.fn(() => ({
- info: jest.fn(),
- warn: jest.fn(),
- error: jest.fn(),
- debug: jest.fn(),
- })),
- },
- },
- wazuh_core: {
- configuration: {},
- },
-});
-
-const mockResponse = () => ({
- ok: body => body,
- custom: body => body,
- badRequest: body => body,
-});
-
-const endpointController = new WazuhReportingCtrl();
-
-console.warn(`
-Theses tests don't have in account the validation of endpoint parameters.
-The endpoints related to an specific file.
-This validation could prevent the endpoint handler is executed, so these tests
-don't cover the reality.
-`);
-
-describe('[security] Report endpoints guard related to a file. Parameter defines or builds the filename.', () => {
- let routeHandler = null;
- const routeHandlerResponse = 'Endpoint handler executed.';
-
- beforeEach(() => {
- routeHandler = jest.fn(() => routeHandlerResponse);
- });
-
- afterEach(() => {
- routeHandler = null;
- });
-
- it.each`
- testTitle | username | filename | endpointProtected
- ${'Execute endpoint handler'} | ${'admin'} | ${'wazuh-module-overview-general-1234.pdf'} | ${false}
- ${'Endpoint protected'} | ${'admin'} | ${'../wazuh-module-overview-general-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'admin'} | ${'wazuh-module-overview-../general-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'admin'} | ${'custom../wazuh-module-overview-general-1234.pdf'} | ${true}
- ${'Execute endpoint handler'} | ${'../../etc'} | ${'wazuh-module-agents-001-general-1234.pdf'} | ${false}
- ${'Endpoint protected'} | ${'../../etc'} | ${'../wazuh-module-agents-001-general-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'../../etc'} | ${'wazuh-module-overview-../general-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'../../etc'} | ${'custom../wazuh-module-overview-general-1234.pdf'} | ${true}
- `(
- `$testTitle
- username: $username
- filename: $filename
- endpointProtected: $endpointProtected`,
- async ({ username, filename, endpointProtected }) => {
- const response =
- await endpointController.checkReportsUserDirectoryIsValidRouteDecorator(
- routeHandler,
- function getFilename(request) {
- return request.params.name;
- },
- )(
- mockContext(username),
- { params: { name: filename } },
- mockResponse(),
- );
- if (endpointProtected) {
- expect(response.body.message).toBe('5040 - You shall not pass!');
- expect(routeHandler.mock.calls).toHaveLength(0);
- } else {
- expect(routeHandler.mock.calls).toHaveLength(1);
- expect(response).toBe(routeHandlerResponse);
- }
- },
- );
-});
-
-describe('[security] GET /reports', () => {
- it.each`
- username
- ${'admin'}
- ${'../../etc'}
- `(
- `Get user reports: GET /reports
- username: $username`,
- async ({ username }) => {
- jest.spyOn(fs, 'readdirSync').mockImplementation(() => []);
-
- const response = await endpointController.getReports(
- mockContext(username),
- {},
- mockResponse(),
- );
- expect(response.body.reports).toHaveLength(0);
- },
- );
-});
-
-describe('[security] GET /reports/{name}', () => {
- it.each`
- titleTest | username | filename | valid
- ${'Get report'} | ${'admin'} | ${'wazuh-module-overview-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'admin'} | ${'../wazuh-module-overview-1234.pdf'} | ${false}
- ${'Get report'} | ${'../../etc'} | ${'wazuh-module-overview-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'../../etc'} | ${'../wazuh-module-overview-1234.pdf'} | ${false}
- `(
- `$titleTest: GET /reports/$filename
- username: $username
- valid: $valid`,
- async ({ username, filename, valid }) => {
- const fileContent = 'content file';
- jest.spyOn(fs, 'readFileSync').mockImplementation(() => fileContent);
-
- const response = await endpointController.getReportByName(
- mockContext(username),
- { params: { name: filename } },
- mockResponse(),
- );
- if (valid) {
- expect(response.headers['Content-Type']).toBe('application/pdf');
- expect(response.body).toBe('content file');
- } else {
- expect(response.body.message).toBe('5040 - You shall not pass!');
- }
- },
- );
-});
-
-describe('[security] POST /reports', () => {
- jest.mock('../lib/filesystem', () => ({
- createDataDirectoryIfNotExists: jest.fn(),
- }));
-
- it.each`
- titleTest | username | moduleID | valid
- ${'Create report'} | ${'admin'} | ${'general'} | ${true}
- ${'Endpoint protected'} | ${'admin'} | ${'../general'} | ${false}
- ${'Create report'} | ${'../../etc'} | ${'general'} | ${true}
- ${'Endpoint protected'} | ${'../../etc'} | ${'../general'} | ${false}
- `(
- `$titleTest: POST /reports/modules/$moduleID
- username: $username
- valid: $valid`,
- async ({ username, moduleID, valid }) => {
- jest
- .spyOn(endpointController, 'renderHeader')
- .mockImplementation(() => true);
- jest
- .spyOn(endpointController, 'sanitizeKibanaFilters')
- .mockImplementation(() => [false, false]);
-
- const mockRequest = {
- body: {
- array: [],
- agents: false,
- browserTimezone: '',
- searchBar: '',
- filters: [],
- time: {
- from: '',
- to: '',
- },
- tables: [],
- section: 'overview',
- indexPatternTitle: 'wazuh-alerts-*',
- apiId: 'default',
- tab: moduleID,
- },
- params: {
- moduleID: moduleID,
- },
- };
-
- const response = await endpointController.createReportsModules(
- mockContext(username),
- mockRequest,
- mockResponse(),
- );
-
- if (valid) {
- expect(response.body.success).toBe(true);
- expect(response.body.message).toMatch(
- new RegExp(`Report wazuh-module-overview-${moduleID}`),
- );
- } else {
- expect(response.body.message).toBe('5040 - You shall not pass!');
- }
- },
- );
-});
-
-describe('[security] DELETE /reports/', () => {
- let mockFsUnlinkSync;
-
- afterEach(() => {
- mockFsUnlinkSync.mockClear();
- });
-
- it.each`
- titleTest | username | filename | valid
- ${'Delete report'} | ${'admin'} | ${'wazuh-module-overview-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'admin'} | ${'../wazuh-module-overview-1234.pdf'} | ${false}
- ${'Endpoint protected'} | ${'admin'} | ${'custom../wazuh-module-overview-1234.pdf'} | ${false}
- ${'Delete report'} | ${'../../etc'} | ${'wazuh-module-overview-1234.pdf'} | ${true}
- ${'Endpoint protected'} | ${'../../etc'} | ${'../wazuh-module-overview-1234.pdf'} | ${false}
- ${'Endpoint protected'} | ${'../../etc'} | ${'custom../wazuh-module-overview-1234.pdf'} | ${false}
- `(
- `[security] DELETE /reports/$filename
- username: $username
- valid: $valid`,
- async ({ filename, username, valid }) => {
- mockFsUnlinkSync = jest
- .spyOn(fs, 'unlinkSync')
- .mockImplementation(() => {});
-
- const response = await endpointController.deleteReportByName(
- mockContext(username),
- { params: { name: filename } },
- mockResponse(),
- );
-
- if (valid) {
- expect(response.body.error).toBe(0);
- expect(mockFsUnlinkSync.mock.calls).toHaveLength(1);
- } else {
- expect(response.body.message).toBe('5040 - You shall not pass!');
- expect(mockFsUnlinkSync.mock.calls).toHaveLength(0);
- }
- },
- );
-});
diff --git a/plugins/main/server/controllers/wazuh-reporting-security-endpoint-parameters-validation.test.ts b/plugins/main/server/controllers/wazuh-reporting-security-endpoint-parameters-validation.test.ts
index 4aa002af30..61c3c8d2f0 100644
--- a/plugins/main/server/controllers/wazuh-reporting-security-endpoint-parameters-validation.test.ts
+++ b/plugins/main/server/controllers/wazuh-reporting-security-endpoint-parameters-validation.test.ts
@@ -5,18 +5,6 @@ import { ByteSizeValue } from '@osd/config-schema';
import supertest from 'supertest';
import { WazuhReportingRoutes } from '../routes/wazuh-reporting';
import md5 from 'md5';
-import {
- createDataDirectoryIfNotExists,
- createDirectoryIfNotExists,
-} from '../lib/filesystem';
-import {
- WAZUH_DATA_ABSOLUTE_PATH,
- WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH,
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
-} from '../../common/constants';
-import { execSync } from 'child_process';
-import path from 'path';
-import fs from 'fs';
const loggingService = loggingSystemMock.create();
const logger = loggingService.get();
@@ -45,40 +33,6 @@ const enhanceWithContext = (fn: (...args: any[]) => any) =>
let server, innerServer;
beforeAll(async () => {
- // Create /data/wazuh directory.
- createDataDirectoryIfNotExists();
- // Create /data/wazuh/downloads directory.
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH);
- // Create /data/wazuh/downloads/reports directory.
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH);
- // Create report files
- [
- { name: md5('admin'), files: ['wazuh-module-overview-general-1234.pdf'] },
- {
- name: md5('../../etc'),
- files: ['wazuh-module-overview-general-1234.pdf'],
- },
- ].forEach(({ name, files }) => {
- createDirectoryIfNotExists(
- path.join(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH, name),
- );
-
- if (files) {
- files.forEach(filename =>
- fs.closeSync(
- fs.openSync(
- path.join(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- name,
- filename,
- ),
- 'w',
- ),
- ),
- );
- }
- });
-
// Create server
const config = {
name: 'plugin_platform',
@@ -112,63 +66,10 @@ beforeAll(async () => {
});
afterAll(async () => {
- // Remove /data/wazuh directory.
- execSync(`rm -rf ${WAZUH_DATA_ABSOLUTE_PATH}`);
-
// Stop server
await server.stop();
});
-describe('[endpoint] GET /reports', () => {
- it.each`
- username
- ${'admin'}
- ${'../../etc'}
- `(
- `Get reports of user GET /reports - 200
- username: $username`,
- async ({ username }) => {
- const response = await supertest(innerServer.listener)
- .get('/reports')
- .set('x-test-username', username)
- .expect(200);
-
- expect(response.body.reports).toBeDefined();
- },
- );
-});
-
-describe('[endpoint][security] GET /reports/{name} - Parameters validation', () => {
- it.each`
- testTitle | username | filename | responseStatusCode | responseBodyMessage
- ${'Get report by filename'} | ${'admin'} | ${'wazuh-module-overview-general-1234.pdf'} | ${200} | ${null}
- ${'Invalid parameters'} | ${'admin'} | ${'..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Invalid parameters'} | ${'admin'} | ${'custom..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Route not found'} | ${'admin'} | ${'../custom..%2fwazuh-module-overview-general-1234.pdf'} | ${404} | ${/Not Found/}
- ${'Get report by filename'} | ${'../../etc'} | ${'wazuh-module-overview-general-1234.pdf'} | ${200} | ${null}
- ${'Invalid parameters'} | ${'../../etc'} | ${'..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Invalid parameters'} | ${'../../etc'} | ${'custom..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Route not found'} | ${'../../etc'} | ${'../custom..%2fwazuh-module-overview-general-1234.pdf'} | ${404} | ${/Not Found/}
- `(
- `$testTitle: GET /reports/$filename - responseStatusCode: $responseStatusCode
- username: $username
- responseBodyMessage: $responseBodyMessage`,
- async ({ username, filename, responseStatusCode, responseBodyMessage }) => {
- const response = await supertest(innerServer.listener)
- .get(`/reports/${filename}`)
- .set('x-test-username', username)
- .expect(responseStatusCode);
- if (responseStatusCode === 200) {
- expect(response.header['content-type']).toMatch(/application\/pdf/);
- expect(response.body instanceof Buffer).toBe(true);
- }
- if (responseBodyMessage) {
- expect(response.body.message).toMatch(responseBodyMessage);
- }
- },
- );
-});
-
describe('[endpoint][security] POST /reports/modules/{moduleID} - Parameters validation', () => {
it.each`
testTitle | username | moduleID | agents | responseStatusCode | responseBodyMessage
@@ -225,7 +126,7 @@ describe('[endpoint][security] POST /reports/groups/{groupID} - Parameters valid
${'Invalid parameters'} | ${'../../etc'} | ${'..%2fdefault'} | ${400} | ${'[request params.groupID]: must be A-z, 0-9, _, . are allowed. It must not be ., .. or all.'}
${'Route not found'} | ${'../../etc'} | ${'../default'} | ${404} | ${/Not Found/}
`(
- `$testTitle: GET /reports/groups/$groupID - $responseStatusCode
+ `$testTitle: POST /reports/groups/$groupID - $responseStatusCode
username: $username
responseBodyMessage: $responseBodyMessage`,
async ({ username, groupID, responseStatusCode, responseBodyMessage }) => {
@@ -258,7 +159,7 @@ describe('[endpoint][security] POST /reports/agents/{agentID} - Parameters valid
${'Invalid parameters'} | ${'../../etc'} | ${'..%2f001'} | ${400} | ${/\[request params.agentID\]: must be 0-9 are allowed/}
${'Invalid parameters'} | ${'../../etc'} | ${'1'} | ${400} | ${/\[request params.agentID\]: value has length \[1\] but it must have a minimum length of \[3\]./}
`(
- `$testTitle: GET /reports/agents/$agentID - $responseStatusCode
+ `$testTitle: POST /reports/agents/$agentID - $responseStatusCode
username: $username
responseBodyMessage: $responseBodyMessage`,
async ({ username, agentID, responseStatusCode, responseBodyMessage }) => {
@@ -320,30 +221,3 @@ describe('[endpoint][security] POST /reports/agents/{agentID}/inventory - Parame
},
);
});
-
-describe('[endpoint][security] DELETE /reports/{name} - Parameters validation', () => {
- it.each`
- testTitle | username | filename | responseStatusCode | responseBodyMessage
- ${'Delete report file'} | ${'admin'} | ${'wazuh-module-overview-general-1234.pdf'} | ${200} | ${null}
- ${'Invalid parameters'} | ${'admin'} | ${'..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Invalid parameters'} | ${'admin'} | ${'custom..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Route not found'} | ${'admin'} | ${'../wazuh-module-overview-general-1234.pdf'} | ${404} | ${/Not Found/}
- ${'Delete report file'} | ${'../../etc'} | ${'wazuh-module-overview-general-1234.pdf'} | ${200} | ${null}
- ${'Invalid parameters'} | ${'../../etc'} | ${'..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Invalid parameters'} | ${'../../etc'} | ${'custom..%2fwazuh-module-overview-general-1234.pdf'} | ${400} | ${'[request params.name]: must be A-z, 0-9, _, ., and - are allowed. It must end with .pdf.'}
- ${'Route not found'} | ${'../../etc'} | ${'../wazuh-module-overview-general-1234.pdf'} | ${404} | ${/Not Found/}
- `(
- `$testTitle: DELETE /reports/$filename - $responseStatusCode
- username: $username
- responseBodyMessage: $responseBodyMessage`,
- async ({ username, filename, responseStatusCode, responseBodyMessage }) => {
- const response = await supertest(innerServer.listener)
- .delete(`/reports/${filename}`)
- .set('x-test-username', username)
- .expect(responseStatusCode);
- if (responseBodyMessage) {
- expect(response.body.message).toMatch(responseBodyMessage);
- }
- },
- );
-});
diff --git a/plugins/main/server/controllers/wazuh-reporting.ts b/plugins/main/server/controllers/wazuh-reporting.ts
index 3b43daa7cc..eee1fa0821 100644
--- a/plugins/main/server/controllers/wazuh-reporting.ts
+++ b/plugins/main/server/controllers/wazuh-reporting.ts
@@ -9,10 +9,7 @@
*
* Find more information about this on the LICENSE file.
*/
-import path from 'path';
-import fs from 'fs';
import { WAZUH_MODULES } from '../../common/wazuh-modules';
-import * as TimSort from 'timsort';
import { ErrorResponse } from '../lib/error-response';
import ProcessEquivalence from '../lib/process-state-equivalence';
import { KeyEquivalence } from '../../common/csv-key-equivalence';
@@ -28,15 +25,9 @@ import {
} from '../lib/reporting/extended-information';
import { ReportPrinter } from '../lib/reporting/printer';
import {
- WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH,
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
AUTHORIZED_AGENTS,
API_NAME_AGENT_STATUS,
} from '../../common/constants';
-import {
- createDirectoryIfNotExists,
- createDataDirectoryIfNotExists,
-} from '../lib/filesystem';
import { agentStatusLabelByAgentStatus } from '../../common/services/wz_agent_status';
interface AgentsFilter {
@@ -297,113 +288,102 @@ export class WazuhReportingCtrl {
* @param {Object} response
* @returns {*} reports list or ErrorResponse
*/
- createReportsModules = this.checkReportsUserDirectoryIsValidRouteDecorator(
- async (
- context: RequestHandlerContext,
- request: OpenSearchDashboardsRequest,
- response: OpenSearchDashboardsResponseFactory,
- ) => {
- try {
- context.wazuh.logger.debug('Report started');
- const {
- array,
- agents,
- browserTimezone,
- searchBar,
- filters,
- serverSideQuery,
- time,
- tables,
- section,
- indexPatternTitle,
- apiId,
- } = request.body;
- const { moduleID } = request.params;
- const { from, to } = time || {};
- let additionalTables = [];
- // Init
- const printer = new ReportPrinter(
- context.wazuh.logger.get('report-printer'),
- context.wazuh_core.configuration,
- );
+ async createReportsModules(
+ context: RequestHandlerContext,
+ request: OpenSearchDashboardsRequest,
+ response: OpenSearchDashboardsResponseFactory,
+ ) {
+ try {
+ context.wazuh.logger.debug('Report started');
+ const {
+ array,
+ agents,
+ browserTimezone,
+ searchBar,
+ filters,
+ serverSideQuery,
+ time,
+ tables,
+ section,
+ indexPatternTitle,
+ apiId,
+ } = request.body;
+ const { moduleID } = request.params;
+ const { from, to } = time || {};
+ let additionalTables = [];
+ // Init
+ const printer = new ReportPrinter(
+ context.wazuh.logger.get('report-printer'),
+ context.wazuh_core.configuration,
+ );
- createDataDirectoryIfNotExists();
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH);
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH);
- createDirectoryIfNotExists(
- path.join(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- context.wazuhEndpointParams.hashUsername,
- ),
+ await this.renderHeader(
+ context,
+ printer,
+ section,
+ moduleID,
+ agents,
+ apiId,
+ );
+
+ const [sanitizedFilters, agentsFilter] = filters
+ ? this.sanitizeKibanaFilters(context, filters, searchBar)
+ : [false, null];
+
+ if (time && sanitizedFilters) {
+ printer.addTimeRangeAndFilters(
+ from,
+ to,
+ sanitizedFilters,
+ browserTimezone,
);
+ }
- await this.renderHeader(
+ if (time) {
+ additionalTables = await extendedInformation(
context,
printer,
section,
moduleID,
- agents,
apiId,
+ new Date(from).getTime(),
+ new Date(to).getTime(),
+ serverSideQuery,
+ agentsFilter,
+ indexPatternTitle ||
+ context.wazuh_core.configuration.getSettingValue('pattern'),
+ agents,
);
+ }
- const [sanitizedFilters, agentsFilter] = filters
- ? this.sanitizeKibanaFilters(context, filters, searchBar)
- : [false, null];
-
- if (time && sanitizedFilters) {
- printer.addTimeRangeAndFilters(
- from,
- to,
- sanitizedFilters,
- browserTimezone,
- );
- }
-
- if (time) {
- additionalTables = await extendedInformation(
- context,
- printer,
- section,
- moduleID,
- apiId,
- new Date(from).getTime(),
- new Date(to).getTime(),
- serverSideQuery,
- agentsFilter,
- indexPatternTitle ||
- context.wazuh_core.configuration.getSettingValue('pattern'),
- agents,
- );
- }
-
- printer.addVisualizations(array, agents, moduleID);
+ printer.addVisualizations(array, agents, moduleID);
- if (tables) {
- printer.addTables([...tables, ...(additionalTables || [])]);
- }
+ if (tables) {
+ printer.addTables([...tables, ...(additionalTables || [])]);
+ }
- //add authorized agents
- if (agentsFilter?.agentsText) {
- printer.addAgentsFilters(agentsFilter.agentsText);
- }
+ //add authorized agents
+ if (agentsFilter?.agentsText) {
+ printer.addAgentsFilters(agentsFilter.agentsText);
+ }
- await printer.print(context.wazuhEndpointParams.pathFilename);
+ const buffer = await printer.print();
+ const filename = `wazuh-module-${
+ request.body.agents ? `agents-${request.body.agents}` : 'overview'
+ }-${request.params.moduleID}-${this.generateReportTimestamp()}.pdf`;
- return response.ok({
- body: {
- success: true,
- message: `Report ${context.wazuhEndpointParams.filename} was created`,
- },
- });
- } catch (error) {
- return ErrorResponse(error.message || error, 5029, 500, response);
- }
- },
- ({ body: { agents }, params: { moduleID } }) =>
- `wazuh-module-${
- agents ? `agents-${agents}` : 'overview'
- }-${moduleID}-${this.generateReportTimestamp()}.pdf`,
- );
+ return response.ok({
+ headers: {
+ 'Content-Type': 'application/pdf',
+ 'Content-Disposition': `attachment;filename="${filename}"`,
+ 'Cache-Control': 'no-store,no-cache',
+ },
+ body: buffer,
+ });
+ } catch (error) {
+ return ErrorResponse(error.message || error, 5029, 500, response);
+ }
+ }
/**
* Create a report for the groups
@@ -412,170 +392,136 @@ export class WazuhReportingCtrl {
* @param {Object} response
* @returns {*} reports list or ErrorResponse
*/
- createReportsGroups = this.checkReportsUserDirectoryIsValidRouteDecorator(
- async (
- context: RequestHandlerContext,
- request: OpenSearchDashboardsRequest,
- response: OpenSearchDashboardsResponseFactory,
- ) => {
- try {
- context.wazuh.logger.debug('Report started');
- const { components, apiId } = request.body;
- const { groupID } = request.params;
- // Init
- const printer = new ReportPrinter(
- context.wazuh.logger.get('report-printer'),
- context.wazuh_core.configuration,
- );
-
- createDataDirectoryIfNotExists();
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH);
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH);
- createDirectoryIfNotExists(
- path.join(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- context.wazuhEndpointParams.hashUsername,
- ),
- );
+ async createReportsGroups(
+ context: RequestHandlerContext,
+ request: OpenSearchDashboardsRequest,
+ response: OpenSearchDashboardsResponseFactory,
+ ) {
+ try {
+ context.wazuh.logger.debug('Report started');
+ const { components, apiId } = request.body;
+ const { groupID } = request.params;
+ // Init
+ const printer = new ReportPrinter(
+ context.wazuh.logger.get('report-printer'),
+ context.wazuh_core.configuration,
+ );
- let tables = [];
- const equivalences = {
- localfile: 'Local files',
- osquery: 'Osquery',
- command: 'Command',
- syscheck: 'Syscheck',
- 'open-scap': 'OpenSCAP',
- 'cis-cat': 'CIS-CAT',
- syscollector: 'Syscollector',
- rootcheck: 'Rootcheck',
- labels: 'Labels',
- sca: 'Security configuration assessment',
- };
- printer.addContent({
- text: `Group ${groupID} configuration`,
- style: 'h1',
- });
+ let tables = [];
+ const equivalences = {
+ localfile: 'Local files',
+ osquery: 'Osquery',
+ command: 'Command',
+ syscheck: 'Syscheck',
+ 'open-scap': 'OpenSCAP',
+ 'cis-cat': 'CIS-CAT',
+ syscollector: 'Syscollector',
+ rootcheck: 'Rootcheck',
+ labels: 'Labels',
+ sca: 'Security configuration assessment',
+ };
+ printer.addContent({
+ text: `Group ${groupID} configuration`,
+ style: 'h1',
+ });
- // Group configuration
- if (components['0']) {
- const {
- data: { data: configuration },
- } = await context.wazuh.api.client.asCurrentUser.request(
- 'GET',
- `/groups/${groupID}/configuration`,
- {},
- { apiHostID: apiId },
- );
+ // Group configuration
+ if (components['0']) {
+ const {
+ data: { data: configuration },
+ } = await context.wazuh.api.client.asCurrentUser.request(
+ 'GET',
+ `/groups/${groupID}/configuration`,
+ {},
+ { apiHostID: apiId },
+ );
- if (
- configuration.affected_items.length > 0 &&
- Object.keys(configuration.affected_items[0].config).length
- ) {
+ if (
+ configuration.affected_items.length > 0 &&
+ Object.keys(configuration.affected_items[0].config).length
+ ) {
+ printer.addContent({
+ text: 'Configurations',
+ style: { fontSize: 14, color: '#000' },
+ margin: [0, 10, 0, 15],
+ });
+ const section = {
+ labels: [],
+ isGroupConfig: true,
+ };
+ for (let config of configuration.affected_items) {
+ let filterTitle = '';
+ let index = 0;
+ for (let filter of Object.keys(config.filters)) {
+ filterTitle = filterTitle.concat(
+ `${filter}: ${config.filters[filter]}`,
+ );
+ if (index < Object.keys(config.filters).length - 1) {
+ filterTitle = filterTitle.concat(' | ');
+ }
+ index++;
+ }
printer.addContent({
- text: 'Configurations',
- style: { fontSize: 14, color: '#000' },
- margin: [0, 10, 0, 15],
+ text: filterTitle,
+ style: 'h4',
+ margin: [0, 0, 0, 10],
});
- const section = {
- labels: [],
- isGroupConfig: true,
- };
- for (let config of configuration.affected_items) {
- let filterTitle = '';
- let index = 0;
- for (let filter of Object.keys(config.filters)) {
- filterTitle = filterTitle.concat(
- `${filter}: ${config.filters[filter]}`,
- );
- if (index < Object.keys(config.filters).length - 1) {
- filterTitle = filterTitle.concat(' | ');
- }
- index++;
- }
- printer.addContent({
- text: filterTitle,
- style: 'h4',
- margin: [0, 0, 0, 10],
- });
- let idx = 0;
- section.tabs = [];
- for (let _d of Object.keys(config.config)) {
- for (let c of AgentConfiguration.configurations) {
- for (let s of c.sections) {
- section.opts = s.opts || {};
- for (let cn of s.config || []) {
- if (cn.configuration === _d) {
- section.labels = s.labels || [[]];
- }
+ let idx = 0;
+ section.tabs = [];
+ for (let _d of Object.keys(config.config)) {
+ for (let c of AgentConfiguration.configurations) {
+ for (let s of c.sections) {
+ section.opts = s.opts || {};
+ for (let cn of s.config || []) {
+ if (cn.configuration === _d) {
+ section.labels = s.labels || [[]];
}
- for (let wo of s.wodle || []) {
- if (wo.name === _d) {
- section.labels = s.labels || [[]];
- }
+ }
+ for (let wo of s.wodle || []) {
+ if (wo.name === _d) {
+ section.labels = s.labels || [[]];
}
}
}
- section.labels[0]['pack'] = 'Packs';
- section.labels[0]['content'] = 'Evaluations';
- section.labels[0]['7'] = 'Scan listening netwotk ports';
- section.tabs.push(equivalences[_d]);
-
- if (Array.isArray(config.config[_d])) {
- /* LOG COLLECTOR */
- if (_d === 'localfile') {
- let groups = [];
- config.config[_d].forEach(obj => {
- if (!groups[obj.logformat]) {
- groups[obj.logformat] = [];
+ }
+ section.labels[0]['pack'] = 'Packs';
+ section.labels[0]['content'] = 'Evaluations';
+ section.labels[0]['7'] = 'Scan listening netwotk ports';
+ section.tabs.push(equivalences[_d]);
+
+ if (Array.isArray(config.config[_d])) {
+ /* LOG COLLECTOR */
+ if (_d === 'localfile') {
+ let groups = [];
+ config.config[_d].forEach(obj => {
+ if (!groups[obj.logformat]) {
+ groups[obj.logformat] = [];
+ }
+ groups[obj.logformat].push(obj);
+ });
+ Object.keys(groups).forEach(group => {
+ let saveidx = 0;
+ groups[group].forEach((x, i) => {
+ if (
+ Object.keys(x).length >
+ Object.keys(groups[group][saveidx]).length
+ ) {
+ saveidx = i;
}
- groups[obj.logformat].push(obj);
- });
- Object.keys(groups).forEach(group => {
- let saveidx = 0;
- groups[group].forEach((x, i) => {
- if (
- Object.keys(x).length >
- Object.keys(groups[group][saveidx]).length
- ) {
- saveidx = i;
- }
- });
- const columns = Object.keys(groups[group][saveidx]);
- const rows = groups[group].map(x => {
- let row = [];
- columns.forEach(key => {
- row.push(
- typeof x[key] !== 'object'
- ? x[key]
- : Array.isArray(x[key])
- ? x[key].map(x => {
- return x + '\n';
- })
- : JSON.stringify(x[key]),
- );
- });
- return row;
- });
- columns.forEach((col, i) => {
- columns[i] = col[0].toUpperCase() + col.slice(1);
- });
- tables.push({
- title: 'Local files',
- type: 'table',
- columns,
- rows,
- });
});
- } else if (_d === 'labels') {
- const obj = config.config[_d][0].label;
- const columns = Object.keys(obj[0]);
- if (!columns.includes('hidden')) {
- columns.push('hidden');
- }
- const rows = obj.map(x => {
+ const columns = Object.keys(groups[group][saveidx]);
+ const rows = groups[group].map(x => {
let row = [];
columns.forEach(key => {
- row.push(x[key]);
+ row.push(
+ typeof x[key] !== 'object'
+ ? x[key]
+ : Array.isArray(x[key])
+ ? x[key].map(x => {
+ return x + '\n';
+ })
+ : JSON.stringify(x[key]),
+ );
});
return row;
});
@@ -583,120 +529,145 @@ export class WazuhReportingCtrl {
columns[i] = col[0].toUpperCase() + col.slice(1);
});
tables.push({
- title: 'Labels',
+ title: 'Local files',
type: 'table',
columns,
rows,
});
- } else {
- for (let _d2 of config.config[_d]) {
- tables.push(
- ...this.getConfigTables(context, _d2, section, idx),
- );
- }
+ });
+ } else if (_d === 'labels') {
+ const obj = config.config[_d][0].label;
+ const columns = Object.keys(obj[0]);
+ if (!columns.includes('hidden')) {
+ columns.push('hidden');
}
- } else {
- /*INTEGRITY MONITORING MONITORED DIRECTORIES */
- if (config.config[_d].directories) {
- const directories = config.config[_d].directories;
- delete config.config[_d].directories;
- tables.push(
- ...this.getConfigTables(
- context,
- config.config[_d],
- section,
- idx,
- ),
- );
- let diffOpts = [];
- Object.keys(section.opts).forEach(x => {
- diffOpts.push(x);
- });
- const columns = [
- '',
- ...diffOpts.filter(
- x => x !== 'check_all' && x !== 'check_sum',
- ),
- ];
- let rows = [];
- directories.forEach(x => {
- let row = [];
- row.push(x.path);
- columns.forEach(y => {
- if (y !== '') {
- y = y !== 'check_whodata' ? y : 'whodata';
- row.push(x[y] ? x[y] : 'no');
- }
- });
- row.push(x.recursion_level);
- rows.push(row);
- });
- columns.forEach((x, idx) => {
- columns[idx] = section.opts[x];
+ const rows = obj.map(x => {
+ let row = [];
+ columns.forEach(key => {
+ row.push(x[key]);
});
- columns.push('RL');
- tables.push({
- title: 'Monitored directories',
- type: 'table',
- columns,
- rows,
- });
- } else {
+ return row;
+ });
+ columns.forEach((col, i) => {
+ columns[i] = col[0].toUpperCase() + col.slice(1);
+ });
+ tables.push({
+ title: 'Labels',
+ type: 'table',
+ columns,
+ rows,
+ });
+ } else {
+ for (let _d2 of config.config[_d]) {
tables.push(
- ...this.getConfigTables(
- context,
- config.config[_d],
- section,
- idx,
- ),
+ ...this.getConfigTables(context, _d2, section, idx),
);
}
}
- for (const table of tables) {
- printer.addConfigTables([table]);
+ } else {
+ /*INTEGRITY MONITORING MONITORED DIRECTORIES */
+ if (config.config[_d].directories) {
+ const directories = config.config[_d].directories;
+ delete config.config[_d].directories;
+ tables.push(
+ ...this.getConfigTables(
+ context,
+ config.config[_d],
+ section,
+ idx,
+ ),
+ );
+ let diffOpts = [];
+ Object.keys(section.opts).forEach(x => {
+ diffOpts.push(x);
+ });
+ const columns = [
+ '',
+ ...diffOpts.filter(
+ x => x !== 'check_all' && x !== 'check_sum',
+ ),
+ ];
+ let rows = [];
+ directories.forEach(x => {
+ let row = [];
+ row.push(x.path);
+ columns.forEach(y => {
+ if (y !== '') {
+ y = y !== 'check_whodata' ? y : 'whodata';
+ row.push(x[y] ? x[y] : 'no');
+ }
+ });
+ row.push(x.recursion_level);
+ rows.push(row);
+ });
+ columns.forEach((x, idx) => {
+ columns[idx] = section.opts[x];
+ });
+ columns.push('RL');
+ tables.push({
+ title: 'Monitored directories',
+ type: 'table',
+ columns,
+ rows,
+ });
+ } else {
+ tables.push(
+ ...this.getConfigTables(
+ context,
+ config.config[_d],
+ section,
+ idx,
+ ),
+ );
}
- idx++;
- tables = [];
}
+ for (const table of tables) {
+ printer.addConfigTables([table]);
+ }
+ idx++;
tables = [];
}
- } else {
- printer.addContent({
- text: 'A configuration for this group has not yet been set up.',
- style: { fontSize: 12, color: '#000' },
- margin: [0, 10, 0, 15],
- });
+ tables = [];
}
+ } else {
+ printer.addContent({
+ text: 'A configuration for this group has not yet been set up.',
+ style: { fontSize: 12, color: '#000' },
+ margin: [0, 10, 0, 15],
+ });
}
+ }
- // Agents in group
- if (components['1']) {
- await this.renderHeader(
- context,
- printer,
- 'groupConfig',
- groupID,
- [],
- apiId,
- );
- }
+ // Agents in group
+ if (components['1']) {
+ await this.renderHeader(
+ context,
+ printer,
+ 'groupConfig',
+ groupID,
+ [],
+ apiId,
+ );
+ }
- await printer.print(context.wazuhEndpointParams.pathFilename);
+ const buffer = await printer.print();
+ const filename = `wazuh-group-configuration-${
+ request.params.groupID
+ }-${this.generateReportTimestamp()}.pdf`;
- return response.ok({
- body: {
- success: true,
- message: `Report ${context.wazuhEndpointParams.filename} was created`,
- },
- });
- } catch (error) {
- context.wazuh.logger.error(error.message || error);
- return ErrorResponse(error.message || error, 5029, 500, response);
- }
- },
- ({ params: { groupID } }) =>
- `wazuh-group-configuration-${groupID}-${this.generateReportTimestamp()}.pdf`,
- );
+ return response.ok({
+ headers: {
+ 'Content-Type': 'application/pdf',
+ 'Content-Disposition': `attachment;filename="${filename}"`,
+ 'Cache-Control': 'no-store,no-cache',
+ },
+ body: buffer,
+ });
+ } catch (error) {
+ context.wazuh.logger.error(error.message || error);
+ return ErrorResponse(error.message || error, 5029, 500, response);
+ }
+ }
/**
* Create a report for the agents
@@ -705,337 +676,301 @@ export class WazuhReportingCtrl {
* @param {Object} response
* @returns {*} reports list or ErrorResponse
*/
- createReportsAgentsConfiguration =
- this.checkReportsUserDirectoryIsValidRouteDecorator(
- async (
- context: RequestHandlerContext,
- request: OpenSearchDashboardsRequest,
- response: OpenSearchDashboardsResponseFactory,
- ) => {
- try {
- context.wazuh.logger.debug('Report started');
- const { components, apiId } = request.body;
- const { agentID } = request.params;
+ async createReportsAgentsConfiguration(
+ context: RequestHandlerContext,
+ request: OpenSearchDashboardsRequest,
+ response: OpenSearchDashboardsResponseFactory,
+ ) {
+ try {
+ context.wazuh.logger.debug('Report started');
+ const { components, apiId } = request.body;
+ const { agentID } = request.params;
- const printer = new ReportPrinter(
- context.wazuh.logger.get('report-printer'),
- context.wazuh_core.configuration,
- );
- createDataDirectoryIfNotExists();
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH);
- createDirectoryIfNotExists(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- );
- createDirectoryIfNotExists(
- path.join(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- context.wazuhEndpointParams.hashUsername,
- ),
- );
+ const printer = new ReportPrinter(
+ context.wazuh.logger.get('report-printer'),
+ context.wazuh_core.configuration,
+ );
- let wmodulesResponse = {};
- let tables = [];
- try {
- wmodulesResponse =
- await context.wazuh.api.client.asCurrentUser.request(
- 'GET',
- `/agents/${agentID}/config/wmodules/wmodules`,
- {},
- { apiHostID: apiId },
- );
- } catch (error) {
- context.wazuh.logger.debug(error.message || error);
- }
+ let wmodulesResponse = {};
+ let tables = [];
+ try {
+ wmodulesResponse = await context.wazuh.api.client.asCurrentUser.request(
+ 'GET',
+ `/agents/${agentID}/config/wmodules/wmodules`,
+ {},
+ { apiHostID: apiId },
+ );
+ } catch (error) {
+ context.wazuh.logger.debug(error.message || error);
+ }
- await this.renderHeader(
- context,
- printer,
- 'agentConfig',
- 'agentConfig',
- agentID,
- apiId,
- );
+ await this.renderHeader(
+ context,
+ printer,
+ 'agentConfig',
+ 'agentConfig',
+ agentID,
+ apiId,
+ );
- let idxComponent = 0;
- for (let config of AgentConfiguration.configurations) {
- let titleOfSection = false;
+ let idxComponent = 0;
+ for (let config of AgentConfiguration.configurations) {
+ let titleOfSection = false;
+ context.wazuh.logger.debug(
+ `Iterate over ${config.sections.length} configuration sections`,
+ );
+ for (let section of config.sections) {
+ let titleOfSubsection = false;
+ if (components[idxComponent] && (section.config || section.wodle)) {
+ let idx = 0;
+ const configs = (section.config || []).concat(section.wodle || []);
context.wazuh.logger.debug(
- `Iterate over ${config.sections.length} configuration sections`,
+ `Iterate over ${configs.length} configuration blocks`,
);
- for (let section of config.sections) {
- let titleOfSubsection = false;
- if (
- components[idxComponent] &&
- (section.config || section.wodle)
- ) {
- let idx = 0;
- const configs = (section.config || []).concat(
- section.wodle || [],
- );
- context.wazuh.logger.debug(
- `Iterate over ${configs.length} configuration blocks`,
- );
- for (let conf of configs) {
- let agentConfigResponse = {};
- try {
- if (!conf['name']) {
- agentConfigResponse =
- await context.wazuh.api.client.asCurrentUser.request(
- 'GET',
- `/agents/${agentID}/config/${conf.component}/${conf.configuration}`,
- {},
- { apiHostID: apiId },
- );
- } else {
- for (let wodle of wmodulesResponse.data.data[
- 'wmodules'
- ]) {
- if (Object.keys(wodle)[0] === conf['name']) {
- agentConfigResponse.data = {
- data: wodle,
- };
- }
- }
+ for (let conf of configs) {
+ let agentConfigResponse = {};
+ try {
+ if (!conf['name']) {
+ agentConfigResponse =
+ await context.wazuh.api.client.asCurrentUser.request(
+ 'GET',
+ `/agents/${agentID}/config/${conf.component}/${conf.configuration}`,
+ {},
+ { apiHostID: apiId },
+ );
+ } else {
+ for (let wodle of wmodulesResponse.data.data['wmodules']) {
+ if (Object.keys(wodle)[0] === conf['name']) {
+ agentConfigResponse.data = {
+ data: wodle,
+ };
}
+ }
+ }
- const agentConfig =
- agentConfigResponse &&
- agentConfigResponse.data &&
- agentConfigResponse.data.data;
- if (!titleOfSection) {
- printer.addContent({
- text: config.title,
- style: 'h1',
- margin: [0, 0, 0, 15],
- });
- titleOfSection = true;
- }
- if (!titleOfSubsection) {
- printer.addContent({
- text: section.subtitle,
- style: 'h4',
- });
- printer.addContent({
- text: section.desc,
- style: { fontSize: 12, color: '#000' },
- margin: [0, 0, 0, 10],
- });
- titleOfSubsection = true;
- }
- if (agentConfig) {
- for (let agentConfigKey of Object.keys(agentConfig)) {
- if (Array.isArray(agentConfig[agentConfigKey])) {
- /* LOG COLLECTOR */
- if (conf.filterBy) {
- let groups = [];
- agentConfig[agentConfigKey].forEach(obj => {
- if (!groups[obj.logformat]) {
- groups[obj.logformat] = [];
- }
- groups[obj.logformat].push(obj);
- });
- Object.keys(groups).forEach(group => {
- let saveidx = 0;
- groups[group].forEach((x, i) => {
- if (
- Object.keys(x).length >
- Object.keys(groups[group][saveidx]).length
- ) {
- saveidx = i;
- }
- });
- const columns = Object.keys(
- groups[group][saveidx],
+ const agentConfig =
+ agentConfigResponse &&
+ agentConfigResponse.data &&
+ agentConfigResponse.data.data;
+ if (!titleOfSection) {
+ printer.addContent({
+ text: config.title,
+ style: 'h1',
+ margin: [0, 0, 0, 15],
+ });
+ titleOfSection = true;
+ }
+ if (!titleOfSubsection) {
+ printer.addContent({
+ text: section.subtitle,
+ style: 'h4',
+ });
+ printer.addContent({
+ text: section.desc,
+ style: { fontSize: 12, color: '#000' },
+ margin: [0, 0, 0, 10],
+ });
+ titleOfSubsection = true;
+ }
+ if (agentConfig) {
+ for (let agentConfigKey of Object.keys(agentConfig)) {
+ if (Array.isArray(agentConfig[agentConfigKey])) {
+ /* LOG COLLECTOR */
+ if (conf.filterBy) {
+ let groups = [];
+ agentConfig[agentConfigKey].forEach(obj => {
+ if (!groups[obj.logformat]) {
+ groups[obj.logformat] = [];
+ }
+ groups[obj.logformat].push(obj);
+ });
+ Object.keys(groups).forEach(group => {
+ let saveidx = 0;
+ groups[group].forEach((x, i) => {
+ if (
+ Object.keys(x).length >
+ Object.keys(groups[group][saveidx]).length
+ ) {
+ saveidx = i;
+ }
+ });
+ const columns = Object.keys(groups[group][saveidx]);
+ const rows = groups[group].map(x => {
+ let row = [];
+ columns.forEach(key => {
+ row.push(
+ typeof x[key] !== 'object'
+ ? x[key]
+ : Array.isArray(x[key])
+ ? x[key].map(x => {
+ return x + '\n';
+ })
+ : JSON.stringify(x[key]),
);
- const rows = groups[group].map(x => {
- let row = [];
- columns.forEach(key => {
- row.push(
- typeof x[key] !== 'object'
- ? x[key]
- : Array.isArray(x[key])
- ? x[key].map(x => {
- return x + '\n';
- })
- : JSON.stringify(x[key]),
- );
- });
- return row;
- });
- columns.forEach((col, i) => {
- columns[i] =
- col[0].toUpperCase() + col.slice(1);
- });
- tables.push({
- title: section.labels[0][group],
- type: 'table',
- columns,
- rows,
- });
});
- } else if (
- agentConfigKey.configuration !== 'socket'
- ) {
- tables.push(
- ...this.getConfigTables(
+ return row;
+ });
+ columns.forEach((col, i) => {
+ columns[i] = col[0].toUpperCase() + col.slice(1);
+ });
+ tables.push({
+ title: section.labels[0][group],
+ type: 'table',
+ columns,
+ rows,
+ });
+ });
+ } else if (agentConfigKey.configuration !== 'socket') {
+ tables.push(
+ ...this.getConfigTables(
+ context,
+ agentConfig[agentConfigKey],
+ section,
+ idx,
+ ),
+ );
+ } else {
+ for (let _d2 of agentConfig[agentConfigKey]) {
+ tables.push(
+ ...this.getConfigTables(context, _d2, section, idx),
+ );
+ }
+ }
+ } else {
+ /* INTEGRITY MONITORING MONITORED DIRECTORIES */
+ if (conf.matrix) {
+ const {
+ directories,
+ diff,
+ synchronization,
+ file_limit,
+ ...rest
+ } = agentConfig[agentConfigKey];
+ tables.push(
+ ...this.getConfigTables(context, rest, section, idx),
+ ...(diff && diff.disk_quota
+ ? this.getConfigTables(
context,
- agentConfig[agentConfigKey],
- section,
- idx,
- ),
- );
- } else {
- for (let _d2 of agentConfig[agentConfigKey]) {
- tables.push(
- ...this.getConfigTables(
- context,
- _d2,
- section,
- idx,
- ),
- );
- }
- }
- } else {
- /* INTEGRITY MONITORING MONITORED DIRECTORIES */
- if (conf.matrix) {
- const {
- directories,
- diff,
- synchronization,
- file_limit,
- ...rest
- } = agentConfig[agentConfigKey];
- tables.push(
- ...this.getConfigTables(
+ diff.disk_quota,
+ { tabs: ['Disk quota'] },
+ 0,
+ )
+ : []),
+ ...(diff && diff.file_size
+ ? this.getConfigTables(
context,
- rest,
- section,
- idx,
- ),
- ...(diff && diff.disk_quota
- ? this.getConfigTables(
- context,
- diff.disk_quota,
- { tabs: ['Disk quota'] },
- 0,
- )
- : []),
- ...(diff && diff.file_size
- ? this.getConfigTables(
- context,
- diff.file_size,
- { tabs: ['File size'] },
- 0,
- )
- : []),
- ...(synchronization
- ? this.getConfigTables(
- context,
- synchronization,
- { tabs: ['Synchronization'] },
- 0,
- )
- : []),
- ...(file_limit
- ? this.getConfigTables(
- context,
- file_limit,
- { tabs: ['File limit'] },
- 0,
- )
- : []),
- );
- let diffOpts = [];
- Object.keys(section.opts).forEach(x => {
- diffOpts.push(x);
- });
- const columns = [
- '',
- ...diffOpts.filter(
- x => x !== 'check_all' && x !== 'check_sum',
- ),
- ];
- let rows = [];
- directories.forEach(x => {
- let row = [];
- row.push(x.dir);
- columns.forEach(y => {
- if (y !== '') {
- row.push(
- x.opts.indexOf(y) > -1 ? 'yes' : 'no',
- );
- }
- });
- row.push(x.recursion_level);
- rows.push(row);
- });
- columns.forEach((x, idx) => {
- columns[idx] = section.opts[x];
- });
- columns.push('RL');
- tables.push({
- title: 'Monitored directories',
- type: 'table',
- columns,
- rows,
- });
- } else {
- tables.push(
- ...this.getConfigTables(
+ diff.file_size,
+ { tabs: ['File size'] },
+ 0,
+ )
+ : []),
+ ...(synchronization
+ ? this.getConfigTables(
context,
- agentConfig[agentConfigKey],
- section,
- idx,
- ),
- );
- }
- }
+ synchronization,
+ { tabs: ['Synchronization'] },
+ 0,
+ )
+ : []),
+ ...(file_limit
+ ? this.getConfigTables(
+ context,
+ file_limit,
+ { tabs: ['File limit'] },
+ 0,
+ )
+ : []),
+ );
+ let diffOpts = [];
+ Object.keys(section.opts).forEach(x => {
+ diffOpts.push(x);
+ });
+ const columns = [
+ '',
+ ...diffOpts.filter(
+ x => x !== 'check_all' && x !== 'check_sum',
+ ),
+ ];
+ let rows = [];
+ directories.forEach(x => {
+ let row = [];
+ row.push(x.dir);
+ columns.forEach(y => {
+ if (y !== '') {
+ row.push(x.opts.indexOf(y) > -1 ? 'yes' : 'no');
+ }
+ });
+ row.push(x.recursion_level);
+ rows.push(row);
+ });
+ columns.forEach((x, idx) => {
+ columns[idx] = section.opts[x];
+ });
+ columns.push('RL');
+ tables.push({
+ title: 'Monitored directories',
+ type: 'table',
+ columns,
+ rows,
+ });
+ } else {
+ tables.push(
+ ...this.getConfigTables(
+ context,
+ agentConfig[agentConfigKey],
+ section,
+ idx,
+ ),
+ );
}
- } else {
- // Print no configured module and link to the documentation
- printer.addContent({
- text: [
- 'This module is not configured. Please take a look on how to configure it in ',
- {
- text: `${section.subtitle.toLowerCase()} configuration.`,
- link: section.docuLink,
- style: { fontSize: 12, color: '#1a0dab' },
- },
- ],
- margin: [0, 0, 0, 20],
- });
}
- } catch (error) {
- context.wazuh.logger.debug(error.message || error);
}
- idx++;
- }
- for (const table of tables) {
- printer.addConfigTables([table]);
+ } else {
+ // Print no configured module and link to the documentation
+ printer.addContent({
+ text: [
+ 'This module is not configured. Please take a look on how to configure it in ',
+ {
+ text: `${section.subtitle.toLowerCase()} configuration.`,
+ link: section.docuLink,
+ style: { fontSize: 12, color: '#1a0dab' },
+ },
+ ],
+ margin: [0, 0, 0, 20],
+ });
}
+ } catch (error) {
+ context.wazuh.logger.debug(error.message || error);
}
- idxComponent++;
- tables = [];
+ idx++;
+ }
+ for (const table of tables) {
+ printer.addConfigTables([table]);
}
}
+ idxComponent++;
+ tables = [];
+ }
+ }
- await printer.print(context.wazuhEndpointParams.pathFilename);
+ const buffer = await printer.print();
+ const filename = `wazuh-agent-configuration-${
+ request.params.agentID
+ }-${this.generateReportTimestamp()}.pdf`;
- return response.ok({
- body: {
- success: true,
- message: `Report ${context.wazuhEndpointParams.filename} was created`,
- },
- });
- } catch (error) {
- context.wazuh.logger.debug(error.message || error);
- return ErrorResponse(error.message || error, 5029, 500, response);
- }
- },
- ({ params: { agentID } }) =>
- `wazuh-agent-configuration-${agentID}-${this.generateReportTimestamp()}.pdf`,
- );
+ return response.ok({
+ headers: {
+ 'Content-Type': 'application/pdf',
+ 'Content-Disposition': `attachment;filename="${filename}"`,
+ 'Cache-Control': 'no-store,no-cache',
+ },
+ body: buffer,
+ });
+ } catch (error) {
+ context.wazuh.logger.debug(error.message || error);
+ return ErrorResponse(error.message || error, 5029, 500, response);
+ }
+ }
/**
* Create a report for the agents
@@ -1044,462 +979,271 @@ export class WazuhReportingCtrl {
* @param {Object} response
* @returns {*} reports list or ErrorResponse
*/
- createReportsAgentsInventory =
- this.checkReportsUserDirectoryIsValidRouteDecorator(
- async (
- context: RequestHandlerContext,
- request: OpenSearchDashboardsRequest,
- response: OpenSearchDashboardsResponseFactory,
- ) => {
- try {
- context.wazuh.logger.debug('Report started');
- const {
- searchBar,
- filters,
- time,
- indexPatternTitle,
- apiId,
- serverSideQuery,
- } = request.body;
- const { agentID } = request.params;
- const { from, to } = time || {};
- // Init
- const printer = new ReportPrinter(
- context.wazuh.logger.get('report-printer'),
- context.wazuh_core.configuration,
- );
-
- const { hashUsername } = await context.wazuh.security.getCurrentUser(
- request,
- context,
- );
- createDataDirectoryIfNotExists();
- createDirectoryIfNotExists(WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH);
- createDirectoryIfNotExists(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- );
- createDirectoryIfNotExists(
- path.join(
- WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
- hashUsername,
- ),
- );
-
- context.wazuh.logger.debug('Syscollector report');
- const [sanitizedFilters, agentsFilter] = filters
- ? this.sanitizeKibanaFilters(context, filters, searchBar)
- : [false, null];
-
- // Get the agent OS
- let agentOs = '';
- let isAgentWindows = false;
- let isAgentLinux = false;
- try {
- const agentResponse =
- await context.wazuh.api.client.asCurrentUser.request(
- 'GET',
- `/agents?agents_list=${agentID}`,
- {},
- { apiHostID: apiId },
- );
- isAgentWindows =
- agentResponse?.data?.data?.affected_items?.[0].os?.platform ===
- 'windows';
- isAgentLinux =
- agentResponse?.data?.data?.affected_items?.[0].os?.uname?.includes(
- 'Linux',
- );
- agentOs =
- (isAgentWindows && 'windows') || (isAgentLinux && 'linux') || '';
- } catch (error) {
- context.wazuh.logger.debug(error.message || error);
- }
-
- // Add title
- printer.addContentWithNewLine({
- text: 'Inventory data report',
- style: 'h1',
- });
-
- // Add table with the agent info
- await buildAgentsTable(context, printer, [agentID], apiId);
-
- // Get syscollector packages and processes
- const agentRequestsInventory = [
- {
- endpoint: `/syscollector/${agentID}/packages`,
- loggerMessage: `Fetching packages for agent ${agentID}`,
- table: {
- title: 'Packages',
- columns:
- agentOs === 'windows'
- ? [
- { id: 'name', label: 'Name' },
- { id: 'architecture', label: 'Architecture' },
- { id: 'version', label: 'Version' },
- { id: 'vendor', label: 'Vendor' },
- ]
- : [
- { id: 'name', label: 'Name' },
- { id: 'architecture', label: 'Architecture' },
- { id: 'version', label: 'Version' },
- { id: 'vendor', label: 'Vendor' },
- { id: 'description', label: 'Description' },
- ],
- },
- },
- {
- endpoint: `/syscollector/${agentID}/processes`,
- loggerMessage: `Fetching processes for agent ${agentID}`,
- table: {
- title: 'Processes',
- columns:
- agentOs === 'windows'
- ? [
- { id: 'name', label: 'Name' },
- { id: 'cmd', label: 'CMD' },
- { id: 'priority', label: 'Priority' },
- { id: 'nlwp', label: 'NLWP' },
- ]
- : [
- { id: 'name', label: 'Name' },
- { id: 'euser', label: 'Effective user' },
- { id: 'nice', label: 'Priority' },
- { id: 'state', label: 'State' },
- ],
- },
- mapResponseItems: item =>
- agentOs === 'windows'
- ? item
- : { ...item, state: ProcessEquivalence[item.state] },
- },
- {
- endpoint: `/syscollector/${agentID}/ports`,
- loggerMessage: `Fetching ports for agent ${agentID}`,
- table: {
- title: 'Network ports',
- columns:
- agentOs === 'windows'
- ? [
- { id: 'local_port', label: 'Local port' },
- { id: 'local_ip', label: 'Local IP address' },
- { id: 'process', label: 'Process' },
- { id: 'state', label: 'State' },
- { id: 'protocol', label: 'Protocol' },
- ]
- : agentOs === 'linux'
- ? [
- { id: 'local_port', label: 'Local port' },
- { id: 'local_ip', label: 'Local IP address' },
- { id: 'process', label: 'Process' },
- { id: 'pid', label: 'PID' },
- { id: 'state', label: 'State' },
- { id: 'protocol', label: 'Protocol' },
- ]
- : [
- { id: 'local_port', label: 'Local port' },
- { id: 'local_ip', label: 'Local IP address' },
- { id: 'state', label: 'State' },
- { id: 'protocol', label: 'Protocol' },
- ],
- },
- mapResponseItems: item => ({
- ...item,
- local_ip: item.local.ip,
- local_port: item.local.port,
- }),
- },
- {
- endpoint: `/syscollector/${agentID}/netiface`,
- loggerMessage: `Fetching netiface for agent ${agentID}`,
- table: {
- title: 'Network interfaces',
- columns: [
- { id: 'name', label: 'Name' },
- { id: 'mac', label: 'Mac' },
- { id: 'state', label: 'State' },
- { id: 'mtu', label: 'MTU' },
- { id: 'type', label: 'Type' },
- ],
- },
- },
- {
- endpoint: `/syscollector/${agentID}/netaddr`,
- loggerMessage: `Fetching netaddr for agent ${agentID}`,
- table: {
- title: 'Network settings',
- columns: [
- { id: 'iface', label: 'Interface' },
- { id: 'address', label: 'Address' },
- { id: 'netmask', label: 'Netmask' },
- { id: 'proto', label: 'Protocol' },
- { id: 'broadcast', label: 'Broadcast' },
- ],
- },
- },
- ];
-
- agentOs === 'windows' &&
- agentRequestsInventory.push({
- endpoint: `/syscollector/${agentID}/hotfixes`,
- loggerMessage: `Fetching hotfixes for agent ${agentID}`,
- table: {
- title: 'Windows updates',
- columns: [{ id: 'hotfix', label: 'Update code' }],
- },
- });
-
- const requestInventory = async agentRequestInventory => {
- try {
- context.wazuh.logger.debug(agentRequestInventory.loggerMessage);
-
- const inventoryResponse =
- await context.wazuh.api.client.asCurrentUser.request(
- 'GET',
- agentRequestInventory.endpoint,
- {},
- { apiHostID: apiId },
- );
-
- const inventory =
- inventoryResponse &&
- inventoryResponse.data &&
- inventoryResponse.data.data &&
- inventoryResponse.data.data.affected_items;
- if (inventory) {
- return {
- ...agentRequestInventory.table,
- items: agentRequestInventory.mapResponseItems
- ? inventory.map(agentRequestInventory.mapResponseItems)
- : inventory,
- };
- }
- } catch (error) {
- context.wazuh.logger.debug(error.message || error);
- }
- };
-
- if (time) {
- // Add Vulnerability Detector filter to the Server Side Query
- serverSideQuery?.bool?.must?.push?.({
- match_phrase: {
- 'rule.groups': {
- query: 'vulnerability-detector',
- },
- },
- });
-
- await extendedInformation(
- context,
- printer,
- 'agents',
- 'syscollector',
- apiId,
- from,
- to,
- serverSideQuery,
- agentsFilter,
- indexPatternTitle ||
- context.wazuh_core.configuration.getSettingValue('pattern'),
- agentID,
- );
- }
-
- // Add inventory tables
- (await Promise.all(agentRequestsInventory.map(requestInventory)))
- .filter(table => table)
- .forEach(table => printer.addSimpleTable(table));
-
- // Print the document
- await printer.print(context.wazuhEndpointParams.pathFilename);
-
- return response.ok({
- body: {
- success: true,
- message: `Report ${context.wazuhEndpointParams.filename} was created`,
- },
- });
- } catch (error) {
- context.wazuh.logger.error(error.message || error);
- return ErrorResponse(error.message || error, 5029, 500, response);
- }
- },
- ({ params: { agentID } }) =>
- `wazuh-agent-inventory-${agentID}-${this.generateReportTimestamp()}.pdf`,
- );
-
- /**
- * Fetch the reports list
- * @param {Object} context
- * @param {Object} request
- * @param {Object} response
- * @returns {Array