diff --git a/CHANGELOG.md b/CHANGELOG.md index eb12982b32..e1d9ebe559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Move AngularJS controller and view for manage groups to ReactJS [#6543](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6543) - Move AngularJS controllers and views of Tools and Dev Tools to ReactJS [#6544](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6544) - Move the AngularJS controller and template of blank screen to ReactJS component [#6538](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6538) +- Move AngularJS controller for management to ReactJS component [#6555](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6555) - Moved the registry data to in-memory cache [#6481](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6481) - Enhance the validation for `enrollment.dns` on App Settings application [#6573](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6573) - Remove AngularJS controller for manage groups [#6543](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6543) diff --git a/plugins/main/public/controllers/management/components/management/common/file-editor.tsx b/plugins/main/public/controllers/management/components/management/common/file-editor.tsx index f38df59189..39ba0dd75b 100644 --- a/plugins/main/public/controllers/management/components/management/common/file-editor.tsx +++ b/plugins/main/public/controllers/management/components/management/common/file-editor.tsx @@ -48,6 +48,8 @@ import _ from 'lodash'; import { UI_ERROR_SEVERITIES } from '../../../../../react-services/error-orchestrator/types'; import { UI_LOGGER_LEVELS } from '../../../../../../common/constants'; import { getErrorOrchestrator } from '../../../../../react-services/common-services'; +import { WzButtonPermissionsOpenFlyout } from '../../../../../components/common/buttons/flyout'; +import { Logtest } from '../../../../../directives/wz-logtest/components/logtest'; class WzFileEditor extends Component { _isMounted = false; @@ -236,22 +238,23 @@ class WzFileEditor extends Component { const xmlError = validateXML(content); - const onClickOpenLogtest = () => { - this.props.logtestProps.openCloseFlyout(); - }; - const buildLogtestButton = () => { return ( - ( + + )} + buttonProps={{ + buttonType: 'empty', + permissions: [{ action: 'logtest:run', resource: `*:*:*` }], + color: 'primary', + iconType: 'documentEdit', + style: { margin: '0px 8px', cursor: 'pointer' }, + }} > {isRules} - + ); }; diff --git a/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js b/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js index 3958f81cde..06d0cb45f5 100644 --- a/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js +++ b/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js @@ -347,11 +347,9 @@ export const restartCluster = async () => { const str = validationError.detail; throw new Error(str); } - // this.performClusterRestart(); // TODO: convert AngularJS to React await WzRequest.apiReq('PUT', `/cluster/restart`, { delay: 15000, }); - // this.$rootScope.$broadcast('removeRestarting', {}); TODO: isRestarting: false? return { data: { data: 'Restarting cluster', diff --git a/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx b/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx index 47f48f3152..57ff2f39c6 100644 --- a/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx +++ b/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx @@ -16,8 +16,7 @@ import WzDecodersOverview from './views/decoders-overview'; import WzFileEditor from '../common/file-editor'; import { SECTION_DECODERS_SECTION } from '../common/constants'; -export default function WzDecoder({ logtestProps }) { - +export default function WzDecoder() { const [fileContent, setFileContent] = useState(false); const [addingFile, setAddingFile] = useState(false); const [showingFiles, setShowingFiles] = useState(false); @@ -25,29 +24,34 @@ export default function WzDecoder({ logtestProps }) { const cleanEditState = () => { setFileContent(false); setAddingFile(false); - } + }; return ( - { - ((fileContent || addingFile) && ( - { setFileContent(fileContent) }} - cleanEditState={() => cleanEditState()} - /> - )) || ( - { setFileContent(fileContent) }} - updateAddingFile={(addingFile) => { setAddingFile(addingFile) }} - setShowingFiles={() => { setShowingFiles(!showingFiles) }} - showingFiles={showingFiles} - /> - ) - } + {((fileContent || addingFile) && ( + { + setFileContent(fileContent); + }} + cleanEditState={() => cleanEditState()} + /> + )) || ( + { + setFileContent(fileContent); + }} + updateAddingFile={addingFile => { + setAddingFile(addingFile); + }} + setShowingFiles={() => { + setShowingFiles(!showingFiles); + }} + showingFiles={showingFiles} + /> + )} ); } diff --git a/plugins/main/public/controllers/management/components/management/management-main.js b/plugins/main/public/controllers/management/components/management/management-main.js index 573b88c8c2..45d0a127ab 100644 --- a/plugins/main/public/controllers/management/components/management/management-main.js +++ b/plugins/main/public/controllers/management/components/management/management-main.js @@ -27,13 +27,17 @@ import { SECTION_DECODERS_SECTION, SECTION_RULES_SECTION, } from './common/constants'; +import { getAngularModule } from '../../../../kibana-services'; +import { + withGuardAsync, + withReduxProvider, +} from '../../../../components/common/hocs'; +import { compose } from 'redux'; import { ClusterOverview } from './cluster/cluster-overview'; class WzManagementMain extends Component { constructor(props) { super(props); - this.state = {}; - this.store = store; } render() { @@ -47,20 +51,51 @@ class WzManagementMain extends Component { (section === 'statistics' && ) || (section === 'logs' && ) || (section === 'configuration' && ( - - )) || - (section === SECTION_DECODERS_SECTION && ( - - )) || - (section === SECTION_CDBLIST_SECTION && ( - + )) || + (section === SECTION_DECODERS_SECTION && ) || + (section === SECTION_CDBLIST_SECTION && ) || (['ruleset', SECTION_RULES_SECTION].includes(section) && ( - + ))} ); } } -export default WzManagementMain; +const availableViews = [ + 'groups', + 'status', + 'reporting', + 'statistics', + 'logs', + 'configuration', + 'decoders', + 'lists', + 'ruleset', + 'rules', + 'monitoring', +]; + +export const ManagementRouter = compose( + withReduxProvider, + withGuardAsync( + () => { + // This uses AngularJS to get the tab query parameter + const section = getAngularModule() + .$injector.get('$location') + .search().tab; + if (availableViews.includes(section)) { + return { ok: false, data: { section } }; + } + return { ok: true, data: { section } }; + }, + () => null, + ), +)(({ section }) => ); + +export default ManagementRouter; diff --git a/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx b/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx index 770e383211..e8fe5da73a 100644 --- a/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx +++ b/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx @@ -15,9 +15,7 @@ import WzRulesetOverview from './views/ruleset-overview'; import WzFileEditor from '../common/file-editor'; import { SECTION_RULES_SECTION } from '../common/constants'; - -export default function WzRuleset({ logtestProps }) { - +export default function WzRuleset() { const [fileContent, setFileContent] = useState(false); const [addingFile, setAddingFile] = useState(false); const [showingFiles, setShowingFiles] = useState(false); @@ -25,29 +23,34 @@ export default function WzRuleset({ logtestProps }) { const cleanEditState = () => { setFileContent(false); setAddingFile(false); - } + }; return ( - { - ((fileContent || addingFile) && ( - { setFileContent(fileContent) }} - cleanEditState={() => cleanEditState()} - /> - )) || ( - { setFileContent(fileContent) }} - updateAddingFile={(addingFile) => { setAddingFile(addingFile) }} - setShowingFiles={() => { setShowingFiles(!showingFiles) }} - showingFiles={showingFiles} - /> - ) - } + {((fileContent || addingFile) && ( + { + setFileContent(fileContent); + }} + cleanEditState={() => cleanEditState()} + /> + )) || ( + { + setFileContent(fileContent); + }} + updateAddingFile={addingFile => { + setAddingFile(addingFile); + }} + setShowingFiles={() => { + setShowingFiles(!showingFiles); + }} + showingFiles={showingFiles} + /> + )} ); } diff --git a/plugins/main/public/controllers/management/index.js b/plugins/main/public/controllers/management/index.js index 79281a2010..f142dd6b2f 100644 --- a/plugins/main/public/controllers/management/index.js +++ b/plugins/main/public/controllers/management/index.js @@ -9,8 +9,6 @@ * * Find more information about this on the LICENSE file. */ - -import { ManagementController } from './management'; import WzManagement from './components/management/management-provider'; import WzManagementConfiguration from './components/management/configuration/configuration-main'; import { getAngularModule } from '../../kibana-services'; @@ -21,6 +19,5 @@ WzManagement.displayName = 'WzManagement'; WzManagementConfiguration.displayName = 'WzManagementConfiguration'; app - .controller('managementController', ManagementController) .value('WzManagement', WzManagement) .value('WzManagementConfiguration', WzManagementConfiguration); diff --git a/plugins/main/public/controllers/management/management.js b/plugins/main/public/controllers/management/management.js deleted file mode 100644 index 5fcbe60d69..0000000000 --- a/plugins/main/public/controllers/management/management.js +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Wazuh app - Management controller - * 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 { TabNames } from '../../utils/tab-names'; -import { AppState } from '../../react-services/app-state'; -import { WazuhConfig } from '../../react-services/wazuh-config'; -import { WzRequest } from '../../react-services/wz-request'; -import { ErrorHandler } from '../../react-services/error-handler'; -import { ShareAgent } from '../../factories/share-agent'; -import { - ResourcesHandler, - ResourcesConstants -} from './components/management/common/resources-handler'; - -import { UI_ERROR_SEVERITIES } from '../../react-services/error-orchestrator/types'; -import { UI_LOGGER_LEVELS } from '../../../common/constants'; -import { getErrorOrchestrator } from '../../react-services/common-services'; - -export class ManagementController { - /** - * Class constructor - * @param {*} $scope - * @param {*} $location - */ - constructor($scope, $rootScope, $location, configHandler, errorHandler, $interval) { - this.$scope = $scope; - this.$rootScope = $rootScope; - this.$location = $location; - this.shareAgent = new ShareAgent(); - this.wazuhConfig = new WazuhConfig(); - this.configHandler = configHandler; - this.errorHandler = errorHandler; - this.$interval = $interval; - this.tab = 'welcome'; - this.globalConfigTab = 'overview'; - this.tabNames = TabNames; - this.wazuhManagementTabs = ['ruleset', 'groups', 'configuration']; - this.statusReportsTabs = ['status', 'logs', 'reporting', 'monitoring']; - this.currentGroup = false; - this.logtestOpened = false; - this.uploadOpened = false; - this.rulesetTab = ResourcesConstants.RULES; - - this.$scope.$on('setCurrentGroup', (ev, params) => { - this.currentGroup = (params || {}).currentGroup || false; - }); - - this.$scope.$on('removeCurrentGroup', () => { - this.currentGroup = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentGroup', null); - }); - - this.$scope.$on('setCurrentRule', (ev, params) => { - this.setCurrentRule(params); - }); - - this.$scope.$on('removeCurrentRule', () => { - this.currentRule = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentRule', null); - }); - - this.$scope.$on('setCurrentDecoder', (ev, params) => { - this.currentDecoder = (params || {}).currentDecoder || false; - this.$location.search('currentDecoder', true); - AppState.setNavigation({ status: true }); - }); - - this.$scope.$on('removeCurrentDecoder', () => { - this.currentDecoder = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentDecoder', null); - }); - - this.$scope.$on('setCurrentList', (ev, params) => { - this.currentList = (params || {}).currentList || false; - this.$location.search('currentList', true); - AppState.setNavigation({ status: true }); - this.$scope.$applyAsync(); - }); - - this.$scope.$on('removeCurrentList', () => { - this.currentList = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentList', null); - }); - - this.$scope.$on('setCurrentConfiguration', (ev, params) => { - this.currentConfiguration = (params || {}).currentConfiguration || false; - }); - - this.$scope.$on('removeCurrentConfiguration', () => { - this.currentConfiguration = false; - }); - - this.$scope.$on('viewFileOnly', (ev, params) => { - $scope.$broadcast('viewFileOnlyTable', { - file: params.item, - path: params.path, - }); - }); - - this.$rootScope.$on('setRestarting', () => { - if (this.clusterInfo.status === 'enabled') { - this.blockEditioncounter = 0; - this.blockEdition = true; - this.$interval( - () => { - this.blockEditioncounter++; - if (this.blockEditioncounter == 100) { - this.blockEdition = false; - this.isRestarting = false; - this.$scope.$applyAsync(); - } - }, - 333, - 100 - ); - } - this.isRestarting = true; - this.$scope.$applyAsync(); - }); - - this.$rootScope.$on('removeBlockEdition', () => { - this.blockEdition = false; - this.isRestarting = false; - this.$scope.$applyAsync(); - }); - - this.$scope.$on('removeRestarting', () => { - this.isRestarting = false; - this.$scope.$applyAsync(); - }); - - this.$rootScope.$on('performRestart', (ev) => { - ev.stopPropagation(); - this.clusterInfo.status === 'enabled' ? this.restartCluster() : this.restartManager(); - }); - - this.$rootScope.timeoutIsReady; - this.$rootScope.$watch('resultState', () => { - if (this.$rootScope.timeoutIsReady) { - clearTimeout(this.$rootScope.timeoutIsReady); - } - if (this.$rootScope.resultState === 'ready') { - this.$scope.isReady = true; - } else { - this.$rootScope.timeoutIsReady = setTimeout(() => (this.$scope.isReady = false), 1000); - } - }); - - this.welcomeCardsProps = { - switchTab: (tab, setNav) => this.switchTab(tab, setNav), - }; - - this.managementTabsProps = { - clickAction: (tab) => this.switchTab(tab, true), - selectedTab: this.tab, - tabs: [ - { id: 'status', name: 'Status' }, - { id: 'logs', name: 'Logs' }, - { id: 'monitoring', name: 'Cluster' }, - { id: 'reporting', name: 'Reporting' }, - ], - }; - - this.logtestProps = { - clickAction: (log) => log, - openCloseFlyout: () => this.openCloseFlyout(), - showClose: true, - onFlyout: true, - }; - - this.managementProps = { - switchTab: (section) => this.switchTab(section, true), - section: '', - groupsProps: {}, - configurationProps: { - agent: { - id: '000', - }, // TODO: get dynamically the agent? - updateWazuhNotReadyYet: (status) => { - this.$rootScope.wazuhNotReadyYet = status; - this.$scope.$applyAsync(); - }, - wazuhNotReadyYet: () => this.$rootScope.wazuhNotReadyYet, - }, - logtestProps: this.logtestProps, - }; - } - - /** - * When controller loads - */ - $onInit() { - try { - this.clusterInfo = AppState.getClusterInfo(); - - if (this.shareAgent.getAgent() && this.shareAgent.getSelectedGroup()) { - this.tab = 'groups'; - this.switchTab(this.tab); - return; - } - - const location = this.$location.search(); - - if (location && location.tab) { - this.tab = location.tab; - this.switchTab(this.tab); - } - - this.uploadFilesProps = { - msg: this.$scope.mctrl.rulesetTab, - path: `etc/${this.$scope.mctrl.rulesetTab}`, - upload: (files) => this.uploadFiles(files, this.$scope.mctrl.rulesetTab), - }; - } catch (error) { - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.$onInit`, - error: { - error: error, - message: error?.message || '', - title: 'Error restarting cluster', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } - - /** - * This check if given array of items contais a single given item - * @param {Object} item - * @param {Array} array - */ - inArray(item, array) { - return item && Array.isArray(array) && array.includes(item); - } - - async restartManager() { - try { - if (this.isRestarting) return; - this.isRestarting = true; - await this.configHandler.restartManager(); - this.isRestarting = false; - this.$scope.$applyAsync(); - ErrorHandler.info('Restarting manager.'); - } catch (error) { - this.isRestarting = false; - this.$scope.$applyAsync(); - - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.restartManager`, - error: { - error: error, - message: error?.message || '', - title: 'Error restarting manager', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } - - async restartCluster() { - try { - if (this.isRestarting) return; - this.isRestarting = true; - await this.configHandler.restartCluster(); - this.isRestarting = false; - this.$scope.$applyAsync(); - ErrorHandler.info('Restarting cluster, it will take up to 30 seconds.'); - } catch (error) { - this.isRestarting = false; - this.$scope.$applyAsync(); - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.restartCluster`, - error: { - error: error, - message: error?.message || '', - title: 'Error restarting cluster', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } - - setConfigTab(tab, nav = false) { - this.globalConfigTab = tab; - if (nav) { - AppState.setNavigation({ status: true }); - } else { - this.editionTab = tab; - } - this.$location.search('configSubTab', null); - this.$location.search('editSubTab', tab); - this.$scope.$broadcast('configurationIsReloaded', { - globalConfigTab: this.globalConfigTab, - reloadConfigSubTab: true, - }); - } - - setCurrentRule(params) { - this.currentRule = (params || {}).currentRule || false; - this.$location.search('currentRule', true); - AppState.setNavigation({ status: true }); - } - - /** - * This switch to a selected tab - * @param {String} tab - */ - switchTab(tab, setNav = false) { - this.editTab = ''; - if (setNav) { - AppState.setNavigation({ status: true }); - } else { - if (this.$location.search().editSubTab) { - this.editTab = this.$location.search().editSubTab; - } - } - this.$location.search('editSubTab', null); - this.tab = tab; - - if (this.tab === 'groups') { - this.$scope.$broadcast('groupsIsReloaded'); - } - if (this.tab !== 'groups') { - this.currentGroup = false; - this.$location.search('currentGroup', null); - } - if (this.tab === 'configuration' && !this.editTab) { - this.globalConfigTab = 'overview'; - this.currentConfiguration = false; - this.$scope.$broadcast('configurationIsReloaded'); - } else if (this.tab === 'configuration' && this.editTab) { - this.setConfigTab(this.editTab); - } else { - this.$location.search('configSubTab', null); - } - if (this.tab === 'ruleset') { - this.$scope.$broadcast('rulesetIsReloaded'); - this.globalRuleSet = 'ruleset'; - this.globalRulesetTab = this.rulesetTab; - } else { - this.globalRuleSet = false; - this.globalRulesetTab = false; - this.currentRule = false; - this.currentDecoder = false; - this.currentList = false; - this.managementTabsProps.selectedTab = this.tab; - } - this.managementProps.section = this.tab === 'ruleset' ? this.rulesetTab : this.tab; - this.$location.search('tab', this.tab); - } - - /** - * This set the rules tab - * @param {String} tab - */ - setRulesTab(tab, flag) { - this.openedFileDirect = false; - this.rulesetTab = tab; - this.globalRulesetTab = this.rulesetTab; - this.managingFiles = false; - //this.refreshUploadFileProps(); - if (!flag) { - this.breadCrumbBack(); - } - } - - switchFilesSubTab(flag, showFile) { - this.managingFiles = flag || true; - if (showFile) { - this.showFile = showFile; - this.$scope.$broadcast('editFromTable'); - } else if (!this.openedFileDirect) { - this.$scope.$broadcast('closeRulesetFile'); - } - } - - breadCrumbBack(goRoot = false) { - if (this.currentRule) { - this.$scope.$broadcast('closeRuleView'); - this.$scope.$broadcast('closeRulesetFile'); - this.$scope.$emit('removeCurrentRule'); - } - if (this.currentDecoder) { - this.$scope.$broadcast('closeDecoderView'); - this.$scope.$broadcast('closeRulesetFile'); - this.$scope.$emit('removeCurrentDecoder'); - } - if (this.currentList) { - this.$scope.$broadcast('closeListView'); - } - if (goRoot) { - this.switchTab('ruleset', true); - this.setRulesTab('rules'); - } - this.$scope.$broadcast('closeRulesetFile'); - this.$scope.$applyAsync(); - } - - changeNode(node) { - this.selectedNode = node; - this.$scope.$broadcast('configNodeChanged'); - this.$scope.$applyAsync(); - } - - openCloseFlyout() { - this.logtestOpened = !this.logtestOpened; - this.logtestProps.isRuleset = this.tab; - this.$scope.$applyAsync(); - } - - newFile() { - this.openedFileDirect = true; - this.switchFilesSubTab(); - this.$scope.$applyAsync(); - this.$scope.$broadcast('addNewFile', { type: this.globalRulesetTab }); - } - - openUploadFile() { - this.uploadOpened = !this.uploadOpened; - this.$scope.$applyAsync(); - } - - refreshUploadFileProps() { - this.uploadFilesProps = { - msg: this.rulesetTab, - path: `etc/${this.rulesetTab}`, - upload: (files) => this.uploadFiles(files, this.rulesetTab), - }; - } - - /** - * Uploads the filess - * @param {Array} files - * @param {String} path - */ - async uploadFiles(files, resource) { - try { - this.errors = false; - this.results = []; - const resourcesHandler = new ResourcesHandler(resource); - - for (let idx in files) { - const { file, content } = files[idx]; - try { - await resourcesHandler.updateFile(file, content, true); // True does not overwrite the file - this.results.push({ - index: idx, - uploaded: true, - file: file, - error: 0, - }); - } catch (error) { - this.errors = true; - this.results.push({ - index: idx, - uploaded: false, - file: file, - error: error, - }); - } - } - if (this.errors) throw this.results; - ErrorHandler.info('Upload successful'); - } catch (error) { - if (Array.isArray(error) && error.length) throw error; - - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.uploadFiles`, - error: { - error: error, - message: error?.message || '', - title: 'Files cannot be loaded', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } -} diff --git a/plugins/main/public/directives/wz-logtest/components/logtest.tsx b/plugins/main/public/directives/wz-logtest/components/logtest.tsx index eb376f1bbb..f6a5eec19d 100644 --- a/plugins/main/public/directives/wz-logtest/components/logtest.tsx +++ b/plugins/main/public/directives/wz-logtest/components/logtest.tsx @@ -16,16 +16,11 @@ import { EuiCodeBlock, EuiFlexGroup, EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutHeader, - EuiOverlayMask, EuiPage, EuiPanel, EuiSpacer, EuiTextArea, EuiTitle, - EuiOutsideClickDetector, } from '@elastic/eui'; import { WzRequest } from '../../../react-services'; import { @@ -45,29 +40,27 @@ import { } from '../../../react-services/error-orchestrator/types'; import { UI_LOGGER_LEVELS } from '../../../../common/constants'; import { getErrorOrchestrator } from '../../../react-services/common-services'; -import { WzFlyout } from '../../../components/common/flyouts'; import _ from 'lodash'; type LogstestProps = { - openCloseFlyout: () => {}; - showClose: boolean; onFlyout: boolean; - isRuleset: string; }; export const Logtest = compose( withErrorBoundary, withReduxProvider, - withUserAuthorizationPrompt([{ action: 'logtest:run', resource: `*:*:*` }]) + withUserAuthorizationPrompt([{ action: 'logtest:run', resource: '*:*:*' }]), )((props: LogstestProps) => { const [events, setEvents] = useState([]); const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState(''); const dispatch = useDispatch(); - const sessionToken = useSelector((state) => state.appStateReducers.logtestToken); + const sessionToken = useSelector( + state => state.appStateReducers.logtestToken, + ); - const onChange = (e) => { - setEvents(e.target.value.split('\n').filter((item) => item)); + const onChange = e => { + setEvents(e.target.value.split('\n').filter(item => item)); }; // Format the result of the Wazuh API response to an output similar one to the `wazuh-logtest` utility @@ -75,30 +68,39 @@ export const Logtest = compose( // How to the `wazuh-logtest` utility logs the output: // https://github.com/wazuh/wazuh/blob/master/framework/scripts/wazuh-logtest.py#L359-L397 - const logging = []; - + const showFieldInfo = (item, path, label = '') => { - _.has(item, path) && logging.push( - `\t${label || path}: '${Array.isArray(_.get(item, path)) - ? JSON.stringify(_.get(item, path)) - : _.get(item, path)}'` + _.has(item, path) && + logging.push( + `\t${label || path}: '${ + Array.isArray(_.get(item, path)) + ? JSON.stringify(_.get(item, path)) + : _.get(item, path) + }'`, ); }; const showPhaseInfo = (item, showFirst = [], prefix = '') => { - showFirst && showFirst.forEach(field => { - showFieldInfo(item, field, prefix+field); - _.unset(item, field); - }); - typeof item === 'object' && Object.keys(item).sort().forEach((field) => { - if(typeof item[field] === 'object' && !Array.isArray(item[field])){ - showPhaseInfo(item[field],[], prefix + field + '.'); - }else{ - showFieldInfo(item, field, prefix+field); - }; - }); - } + showFirst && + showFirst.forEach(field => { + showFieldInfo(item, field, prefix + field); + _.unset(item, field); + }); + typeof item === 'object' && + Object.keys(item) + .sort() + .forEach(field => { + if ( + typeof item[field] === 'object' && + !Array.isArray(item[field]) + ) { + showPhaseInfo(item[field], [], prefix + field + '.'); + } else { + showFieldInfo(item, field, prefix + field); + } + }); + }; // Output messages if (messages) { @@ -110,25 +112,29 @@ export const Logtest = compose( // Pre-decoding phase logging.push('**Phase 1: Completed pre-decoding.'); // Check in case rule has no_full_log attribute - if(result.full_log){ + if (result.full_log) { showFieldInfo(result, 'full_log', 'full event'); - }; + } - if(result.predecoder){ - showPhaseInfo(result.predecoder, ['timestamp', 'hostname', 'program_name']); + if (result.predecoder) { + showPhaseInfo(result.predecoder, [ + 'timestamp', + 'hostname', + 'program_name', + ]); } // Decoding phase logging.push(''); logging.push('**Phase 2: Completed decoding.'); - if(result.decoder && Object.keys(result.decoder).length > 0){ + if (result.decoder && Object.keys(result.decoder).length > 0) { showPhaseInfo(result.decoder, ['name', 'parent']); - if(result.data){ + if (result.data) { showPhaseInfo(result.data, []); - }; - }else{ - logging.push('\tNo decoder matched.') + } + } else { + logging.push('\tNo decoder matched.'); } // Rule phase @@ -136,24 +142,34 @@ export const Logtest = compose( // Rule debugging // The output has data if the utility is ran in verbose mode: `wazuh-logtest -v`. // At this moment, the Wazuh API doesn't let run in verbose mode. - if(result.rules_debug){ + if (result.rules_debug) { logging.push(''); logging.push('**Rule debugging:'); - result.rules_debug.forEach(debugMessage => logging.push(`${debugMessage[0] === '*' ? '\t\t' : '\t'}${debugMessage}`)); - }; - - if(result.rule){ + result.rules_debug.forEach(debugMessage => + logging.push( + `${debugMessage[0] === '*' ? '\t\t' : '\t'}${debugMessage}`, + ), + ); + } + + if (result.rule) { logging.push(''); logging.push('**Phase 3: Completed filtering (rules).'); - showPhaseInfo(result.rule, ['id', 'level', 'description', 'groups', 'firedtimes']); - }; + showPhaseInfo(result.rule, [ + 'id', + 'level', + 'description', + 'groups', + 'firedtimes', + ]); + } - if(alert){ + if (alert) { logging.push('**Alert to be generated.'); - }; + } return logging.join('\n'); - }; + }; const runAllTests = async () => { setTestResult(''); @@ -172,22 +188,31 @@ export const Logtest = compose( }); token = response.data.data.token; - !sessionToken && !gotToken && token && dispatch(updateLogtestToken(token)); + !sessionToken && + !gotToken && + token && + dispatch(updateLogtestToken(token)); token && (gotToken = true); responses.push(response); } - const testResults = responses.map((response) => { - return response.data.data.output || '' - ? formatResult(response.data.data.output, response.data.data.alert, response.data.data.messages) - : `No result found for: ${response.data.data.output.full_log}`; - }).join('\n\n'); + const testResults = responses + .map(response => { + return response.data.data.output || '' + ? formatResult( + response.data.data.output, + response.data.data.alert, + response.data.data.messages, + ) + : `No result found for: ${response.data.data.output.full_log}`; + }) + .join('\n\n'); setTestResult(testResults); } finally { setTesting(false); } }; - const handleKeyPress = async (event) => { + const handleKeyPress = async event => { if (event.ctrlKey && event.key === 'Enter') { await runAllTests(); } @@ -205,7 +230,9 @@ export const Logtest = compose( severity: UI_ERROR_SEVERITIES.BUSINESS as UIErrorSeverity, error: { error: error, - message: `Error trying to delete logtest token due to: ${error.message || error}`, + message: `Error trying to delete logtest token due to: ${ + error.message || error + }`, title: error.name, }, }; @@ -217,21 +244,21 @@ export const Logtest = compose( return ( - - + + @@ -244,12 +271,12 @@ export const Logtest = compose( tooltip={{ position: 'top', content: 'Clear current session' }} fill isDisabled={sessionToken === '' ? true : false} - aria-label="Clear current session" - iconType="broom" + aria-label='Clear current session' + iconType='broom' onConfirm={async () => { deleteToken(); }} - color="danger" + color='danger' modalTitle={`Do you want to clear current session?`} modalProps={{ buttonColor: 'danger', @@ -261,10 +288,10 @@ export const Logtest = compose( - + - DynamicHeight.dynamicHeightStatic('.euiCodeBlock', props.showClose ? 70 : 100); + DynamicHeight.dynamicHeightStatic( + '.euiCodeBlock', + props.onFlyout ? 70 : 100, + ); dynamicHeight(); @@ -287,40 +317,33 @@ export const Logtest = compose( {(!props.onFlyout && ( - + - + - +

Ruleset Test

- + {buildLogtest()}
)) || ( - props.openCloseFlyout()}> - - - {props.isRuleset.includes('rules') ?

Ruleset Test

:

Decoders Test

} -
-
- - - - - - {buildLogtest()} - -
+ <> + + + + + {buildLogtest()} + )}
); diff --git a/plugins/main/public/services/config-handler.js b/plugins/main/public/services/config-handler.js index e9547e35fe..e87fde2436 100644 --- a/plugins/main/public/services/config-handler.js +++ b/plugins/main/public/services/config-handler.js @@ -24,11 +24,10 @@ export class ConfigHandler { */ async saveManagerConfiguration(content) { try { - const result = await WzRequest.apiReq( - 'PUT', - `/manager/configuration`, - { content, origin: 'xmleditor' } - ); + const result = await WzRequest.apiReq('PUT', `/manager/configuration`, { + content, + origin: 'xmleditor', + }); return result; } catch (error) { return Promise.reject(error); @@ -45,7 +44,7 @@ export class ConfigHandler { const result = await WzRequest.apiReq( 'PUT', `/cluster/${node}/configuration`, - { content, origin: 'xmleditor' } + { content, origin: 'xmleditor' }, ); return result; } catch (error) { @@ -56,9 +55,7 @@ export class ConfigHandler { async performClusterRestart() { try { await WzRequest.apiReq('PUT', `/cluster/restart`, { delay: 15000 }); - this.$rootScope.$broadcast('removeRestarting', {}); } catch (error) { - this.$rootScope.$broadcast('removeRestarting', {}); throw new Error('Error restarting cluster'); } } @@ -71,7 +68,7 @@ export class ConfigHandler { const validationError = await WzRequest.apiReq( 'GET', `/manager/configuration/validation`, - {} + {}, ); const data = ((validationError || {}).data || {}).data || {}; @@ -96,7 +93,7 @@ export class ConfigHandler { const validationError = await WzRequest.apiReq( 'GET', `/cluster/configuration/validation`, - {} + {}, ); const data = ((validationError || {}).data || {}).data || {}; @@ -120,7 +117,7 @@ export class ConfigHandler { const validationError = await WzRequest.apiReq( 'GET', `/cluster/${node}/configuration/validation`, - {} + {}, ); const data = ((validationError || {}).data || {}).data || {}; @@ -132,7 +129,7 @@ export class ConfigHandler { const result = await WzRequest.apiReq( 'PUT', `/cluster/${node}/restart`, - {} + {}, ); return result; } catch (error) { diff --git a/plugins/main/public/templates/management/management.html b/plugins/main/public/templates/management/management.html index 4d69103378..01db1a17d5 100644 --- a/plugins/main/public/templates/management/management.html +++ b/plugins/main/public/templates/management/management.html @@ -1,49 +1 @@ - -
- - -
- -
- -
- -
- {{ mctrl.tabNames[mctrl.tab] }} - / {{ mctrl.currentGroup.name }} -
- -
- - -
- -
- - -
- -
- -
+