diff --git a/.gitignore b/.gitignore index ddf8aadb6e..3f31152b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,4 @@ typings/ .yarn-integrity # dotenv environment variables file -.env +.env \ No newline at end of file diff --git a/package.json b/package.json index 007d64bed1..2c065a059f 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "lodash": "3.10.1", "needle": "^2.0.1", "node-cron": "^1.1.2", - "rison": "^0.1.1", "winston": "3.0.0-rc1" } } diff --git a/public/controllers/agents.js b/public/controllers/agents.js index 8494ca905d..be2f79fafa 100644 --- a/public/controllers/agents.js +++ b/public/controllers/agents.js @@ -9,525 +9,480 @@ * * Find more information about this on the LICENSE file. */ -import beautifier from 'plugins/wazuh/utils/json-beautifier'; -import * as modules from 'ui/modules' -import rison from 'rison' +import beautifier from 'plugins/wazuh/utils/json-beautifier'; +import * as modules from 'ui/modules' +import FilterHandler from './filter-handler' const app = modules.get('app/wazuh', []); -app.controller('agentsController', - function ($timeout, $scope, $location, $q, $rootScope, appState, genericReq, apiReq, AgentsAutoComplete, errorHandler) { - - $rootScope.page = 'agents'; - $scope.extensions = appState.getExtensions().extensions; - $scope.agentsAutoComplete = AgentsAutoComplete; - - // Check the url hash and retrieve the tabView information - if ($location.search().tabView){ - $scope.tabView = $location.search().tabView; - } else { // If tabView doesn't exist, default it to 'panels' - $scope.tabView = "panels"; - $location.search("tabView", "panels"); - } - - // Check the url hash and retrivew the tab information - if ($location.search().tab){ - $scope.tab = $location.search().tab; - } else { // If tab doesn't exist, default it to 'general' - $scope.tab = "general"; - $location.search("tab", "general"); - - // Now we initialize the implicitFilter - $rootScope.currentImplicitFilter = ""; - } - - // Metrics Audit - const metricsAudit = { - auditNewFiles : '[vis-id="\'Wazuh-App-Agents-Audit-New-files-metric\'"]', - auditReadFiles : '[vis-id="\'Wazuh-App-Agents-Audit-Read-files-metric\'"]', - auditModifiedFiles: '[vis-id="\'Wazuh-App-Agents-Audit-Modified-files-metric\'"]', - auditRemovedFiles : '[vis-id="\'Wazuh-App-Agents-Audit-Removed-files-metric\'"]' - } - - // Metrics Vulnerability Detector - const metricsVulnerability = { - vulnCritical: '[vis-id="\'Wazuh-App-Agents-VULS-Metric-Critical-severity\'"]', - vulnHigh : '[vis-id="\'Wazuh-App-Agents-VULS-Metric-High-severity\'"]', - vulnMedium : '[vis-id="\'Wazuh-App-Agents-VULS-Metric-Medium-severity\'"]', - vulnLow : '[vis-id="\'Wazuh-App-Agents-VULS-Metric-Low-severity\'"]' - } - - // Metrics Scap - const metricsScap = { - scapLastScore : '[vis-id="\'Wazuh-App-Agents-OSCAP-Last-score\'"]', - scapHighestScore: '[vis-id="\'Wazuh-App-Agents-OSCAP-Higher-score-metric\'"]', - scapLowestScore : '[vis-id="\'Wazuh-App-Agents-OSCAP-Lower-score-metric\'"]' - } - - // Metrics Virustotal - const metricsVirustotal = { - virusMalicious: '[vis-id="\'Wazuh-App-Agents-Virustotal-Total-Malicious\'"]', - virusPositives: '[vis-id="\'Wazuh-App-Agents-Virustotal-Total-Positives\'"]', - virusTotal : '[vis-id="\'Wazuh-App-Agents-Virustotal-Total\'"]' - } +app.controller('agentsController', function ($timeout, $scope, $location, $rootScope, appState, genericReq, apiReq, AgentsAutoComplete, errorHandler, rawVisualizations, loadedVisualizations, tabVisualizations, discoverPendingUpdates, visHandlers) { + $location.search('_a',null) + const filterHandler = new FilterHandler(appState.getCurrentPattern()); + visHandlers.removeAll(); + discoverPendingUpdates.removeAll(); + rawVisualizations.removeAll(); + tabVisualizations.removeAll(); + loadedVisualizations.removeAll(); + + $rootScope.completedAgent = false; + $rootScope.page = 'agents'; + $scope.extensions = appState.getExtensions().extensions; + $scope.agentsAutoComplete = AgentsAutoComplete; + + // Check the url hash and retrieve the tabView information + if ($location.search().tabView){ + $scope.tabView = $location.search().tabView; + } else { // If tabView doesn't exist, default it to 'panels' + $scope.tabView = "panels"; + $location.search("tabView", "panels"); + } + + // Check the url hash and retrivew the tab information + if ($location.search().tab){ + $scope.tab = $location.search().tab; + } else { // If tab doesn't exist, default it to 'general' + $scope.tab = "general"; + $location.search("tab", "general"); + } + + // Metrics Audit + const metricsAudit = { + auditNewFiles : '[vis-id="\'Wazuh-App-Agents-Audit-New-files-metric\'"]', + auditReadFiles : '[vis-id="\'Wazuh-App-Agents-Audit-Read-files-metric\'"]', + auditModifiedFiles: '[vis-id="\'Wazuh-App-Agents-Audit-Modified-files-metric\'"]', + auditRemovedFiles : '[vis-id="\'Wazuh-App-Agents-Audit-Removed-files-metric\'"]' + } + + // Metrics Vulnerability Detector + const metricsVulnerability = { + vulnCritical: '[vis-id="\'Wazuh-App-Agents-VULS-Metric-Critical-severity\'"]', + vulnHigh : '[vis-id="\'Wazuh-App-Agents-VULS-Metric-High-severity\'"]', + vulnMedium : '[vis-id="\'Wazuh-App-Agents-VULS-Metric-Medium-severity\'"]', + vulnLow : '[vis-id="\'Wazuh-App-Agents-VULS-Metric-Low-severity\'"]' + } + + // Metrics Scap + const metricsScap = { + scapLastScore : '[vis-id="\'Wazuh-App-Agents-OSCAP-Last-score\'"]', + scapHighestScore: '[vis-id="\'Wazuh-App-Agents-OSCAP-Higher-score-metric\'"]', + scapLowestScore : '[vis-id="\'Wazuh-App-Agents-OSCAP-Lower-score-metric\'"]' + } + + // Metrics Virustotal + const metricsVirustotal = { + virusMalicious: '[vis-id="\'Wazuh-App-Agents-Virustotal-Total-Malicious\'"]', + virusPositives: '[vis-id="\'Wazuh-App-Agents-Virustotal-Total-Positives\'"]', + virusTotal : '[vis-id="\'Wazuh-App-Agents-Virustotal-Total\'"]' + } + + tabVisualizations.assign({ + general : 7, + fim : 8, + pm : 4, + vuls : 7, + oscap : 13, + audit : 15, + pci : 3, + virustotal : 6, + configuration: 0 + }); - $rootScope.tabVisualizations = { - general : 7, - fim : 8, - pm : 4, - vuls : 7, - oscap : 13, - audit : 15, - pci : 3, - virustotal : 6, - configuration: 0 - }; - - // Object for matching nav items and Wazuh groups - const tabFilters = { - general : { group: '' }, - fim : { group: 'syscheck' }, - pm : { group: 'rootcheck' }, - vuls : { group: 'vulnerability-detector' }, - oscap : { group: 'oscap' }, - audit : { group: 'audit' }, - pci : { group: 'pci_dss' }, - virustotal: { group: 'virustotal' } - }; - - const generateMetric = id => { - let html = $(id).html(); - if (typeof html !== 'undefined' && html.includes('')[1] !== 'undefined'){ - return html.split('')[1].split('')[1] && - nonB.split('>')[1].split('')[1].split(' { + try { + filters = []; + + filters.push(filterHandler.managerQuery( + appState.getClusterInfo().status == 'enabled' ? + appState.getClusterInfo().cluster : + appState.getClusterInfo().manager + )) + + if(tab !== 'general'){ + if(tab === 'pci') { + filters.push(filterHandler.pciQuery()) + } else { + filters.push(filterHandler.ruleGroupQuery(tabFilters[tab].group)); } } - return ''; - } - - const createMetrics = metricsObject => { - for(let key in metricsObject) { - $scope[key] = () => generateMetric(metricsObject[key]); + + filters.push(filterHandler.agentQuery(agent)); + $rootScope.$emit('wzEventFilters',{filters}); + if(!$rootScope.$$listenerCount['wzEventFilters']){ + $timeout(100) + .then(() => assignFilters(tab,agent)) } + } catch (error){ + console.log(error.message || error) } - - const checkMetrics = (tab, subtab) => { - if(subtab === 'panels'){ - switch (tab) { - case 'audit': - createMetrics(metricsAudit); - break; - case 'vuls': - createMetrics(metricsVulnerability); - break; - case 'oscap': - createMetrics(metricsScap); - break; - case 'virustotal': - createMetrics(metricsVirustotal); - break; + } + + const generateMetric = id => { + let html = $(id).html(); + if (typeof html !== 'undefined' && html.includes('')[1] !== 'undefined'){ + return html.split('')[1].split('')[1] && + nonB.split('>')[1].split('')[1].split(' { - if($scope.tabView === subtab) return; - if(subtab === 'panels' && $scope.tab !== 'configuration'){ - $rootScope.rawVisualizations = null; - - // Create current tab visualizations - genericReq.request('GET',`/api/wazuh-elastic/create-vis/agents-${$scope.tab}/${appState.getCurrentPattern()}`) - .then(data => { - $rootScope.rawVisualizations = data.data.raw; - // Render visualizations - $rootScope.$broadcast('updateVis'); - - checkMetrics($scope.tab, 'panels'); - }) - .catch(error => errorHandler.handle(error, 'Agents')); - } else { - checkMetrics($scope.tab, subtab); - } + const createMetrics = metricsObject => { + for(let key in metricsObject) { + $scope[key] = () => generateMetric(metricsObject[key]); } - - // Switch tab - $scope.switchTab = tab => { - if ($scope.tab === tab) return; - - if(tab !== 'configuration') { - $rootScope.rawVisualizations = null; - // Create current tab visualizations - genericReq.request('GET',`/api/wazuh-elastic/create-vis/agents-${tab}/${appState.getCurrentPattern()}`) - .then(data => { - $rootScope.rawVisualizations = data.data.raw; - // Render visualizations - $rootScope.$broadcast('updateVis'); - - checkMetrics(tab, 'panels'); - - }) - .catch(error => errorHandler.handle(error, 'Agents')); + } + + const checkMetrics = (tab, subtab) => { + if(subtab === 'panels'){ + switch (tab) { + case 'audit': + createMetrics(metricsAudit); + break; + case 'vuls': + createMetrics(metricsVulnerability); + break; + case 'oscap': + createMetrics(metricsScap); + break; + case 'virustotal': + createMetrics(metricsVirustotal); + break; } - }; + } - // Watchers + if(!$rootScope.$$phase) $rootScope.$digest(); + } - // We watch the resultState provided by the discover - $scope.$watch('tabView', () => { - $location.search('tabView', $scope.tabView); + // Switch subtab + $scope.switchSubtab = (subtab, force = false) => { + if($scope.tabView === subtab && !force) return; + visHandlers.removeAll(); + discoverPendingUpdates.removeAll(); + rawVisualizations.removeAll(); + loadedVisualizations.removeAll(); - if ($rootScope.ownHandlers) { - for (let h of $rootScope.ownHandlers) { - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + $location.search('tabView', subtab); - $rootScope.loadedVisualizations = []; - }); + if(subtab === 'panels' && $scope.tabView === 'discover'){ + $rootScope.$emit('changeTabView',{tabView:$scope.tabView}) + } - $scope.$watch('tab', () => { - const str = $location.search()._a; - if(str){ - const decoded = rison.decode(str); - const tmp = decoded.filters.filter(item => !( - (item.query && item.query.match && item.query.match['rule.groups']) || - (item.exists && item.exists.field === 'rule.pci_dss')) - ); - - decoded.filters = tmp; - const encoded = rison.encode(decoded); - $location.search('_a', encoded) - } - $location.search('tab', $scope.tab); + $scope.tabView = subtab; - $scope.tabView = 'panels'; + if(subtab === 'panels' && $scope.tab !== 'configuration'){ + // Create current tab visualizations + genericReq.request('GET',`/api/wazuh-elastic/create-vis/agents-${$scope.tab}/${appState.getCurrentPattern()}`) + .then(data => { + rawVisualizations.assignItems(data.data.raw); + assignFilters($scope.tab, $scope.agent.id); + $rootScope.$emit('changeTabView',{tabView:subtab}) + $rootScope.$broadcast('updateVis'); + checkMetrics($scope.tab, 'panels'); + }) + .catch(error => errorHandler.handle(error, 'Agents')); + } else { + $rootScope.$emit('changeTabView',{tabView:$scope.tabView}) + checkMetrics($scope.tab, subtab); + } + } - if ($rootScope.ownHandlers) { - for (let h of $rootScope.ownHandlers) { - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + // Switch tab + $scope.switchTab = (tab, force = false) => { + tabVisualizations.setTab(tab); + if ($scope.tab === tab && !force) return; - $rootScope.loadedVisualizations = []; + $location.search('tab', tab); + $scope.tab = tab; - // Update the implicit filter - if (typeof tabFilters[$scope.tab] !== 'undefined' && tabFilters[$scope.tab].group === "") $rootScope.currentImplicitFilter = ""; - else $rootScope.currentImplicitFilter = (typeof tabFilters[$scope.tab] !== 'undefined') ? tabFilters[$scope.tab].group : ''; + if($scope.tab === 'configuration'){ + firstLoad(); + } else { + $scope.switchSubtab('panels', true); + } + }; - if($scope.tab === 'configuration'){ - firstLoad(); - } - }); - // Agent data - $scope.getAgentStatusClass = (agentStatus) => agentStatus === "Active" ? "teal" : "red"; + // Agent data + $scope.getAgentStatusClass = (agentStatus) => agentStatus === "Active" ? "teal" : "red"; - $scope.formatAgentStatus = (agentStatus) => { - return ['Active','Disconnected'].includes(agentStatus) ? agentStatus : 'Never connected'; - }; + $scope.formatAgentStatus = (agentStatus) => { + return ['Active','Disconnected'].includes(agentStatus) ? agentStatus : 'Never connected'; + }; - const calculateMinutes = (start,end) => { - let time = new Date(start); - let endTime = new Date(end); - let minutes = ((endTime - time) / 1000) / 60; - return minutes; - } + const calculateMinutes = (start,end) => { + let time = new Date(start); + let endTime = new Date(end); + let minutes = ((endTime - time) / 1000) / 60; + return minutes; + } - const validateRootCheck = () => { - $scope.agent.rootcheck.duration = 'Unknown'; - if ($scope.agent.rootcheck.end && $scope.agent.rootcheck.start) { - $scope.agent.rootcheck.duration = ((new Date($scope.agent.rootcheck.end) - new Date($scope.agent.rootcheck.start))/1000)/60; - $scope.agent.rootcheck.duration = Math.round($scope.agent.rootcheck.duration * 100) / 100; + const validateRootCheck = () => { + $scope.agent.rootcheck.duration = 'Unknown'; + if ($scope.agent.rootcheck.end && $scope.agent.rootcheck.start) { + $scope.agent.rootcheck.duration = ((new Date($scope.agent.rootcheck.end) - new Date($scope.agent.rootcheck.start))/1000)/60; + $scope.agent.rootcheck.duration = Math.round($scope.agent.rootcheck.duration * 100) / 100; - if($scope.agent.rootcheck.duration <= 0){ - $scope.agent.rootcheck.inProgress = true; - } - } else { - if (!$scope.agent.rootcheck.end) { - $scope.agent.rootcheck.end = 'Unknown'; - } - if (!$scope.agent.rootcheck.start){ - $scope.agent.rootcheck.start = 'Unknown'; - } + if($scope.agent.rootcheck.duration <= 0){ + $scope.agent.rootcheck.inProgress = true; } - } - - const validateSysCheck = () => { - $scope.agent.syscheck.duration = 'Unknown'; - if ($scope.agent.syscheck.end && $scope.agent.syscheck.start) { - $scope.agent.syscheck.duration = ((new Date($scope.agent.syscheck.end) - new Date($scope.agent.syscheck.start))/1000)/60; - $scope.agent.syscheck.duration = Math.round($scope.agent.syscheck.duration * 100) / 100; - if($scope.agent.syscheck.duration <= 0){ - $scope.agent.syscheck.inProgress = true; - } - } else { - if (!$scope.agent.syscheck.end) { - $scope.agent.syscheck.end = 'Unknown'; - } - if (!$scope.agent.syscheck.start){ - $scope.agent.syscheck.start = 'Unknown'; - } + } else { + if (!$scope.agent.rootcheck.end) { + $scope.agent.rootcheck.end = 'Unknown'; + } + if (!$scope.agent.rootcheck.start){ + $scope.agent.rootcheck.start = 'Unknown'; } } - - /** Prevents from double agent and come from autocomplete */ - let lastAgent = null; - const checkDouble = id => { - if(lastAgent && lastAgent !== id){ - $rootScope.agentsAutoCompleteFired = true; - if(!$rootScope.$$phase) $rootScope.$digest(); + } + + const validateSysCheck = () => { + $scope.agent.syscheck.duration = 'Unknown'; + if ($scope.agent.syscheck.end && $scope.agent.syscheck.start) { + $scope.agent.syscheck.duration = ((new Date($scope.agent.syscheck.end) - new Date($scope.agent.syscheck.start))/1000)/60; + $scope.agent.syscheck.duration = Math.round($scope.agent.syscheck.duration * 100) / 100; + if($scope.agent.syscheck.duration <= 0){ + $scope.agent.syscheck.inProgress = true; + } + } else { + if (!$scope.agent.syscheck.end) { + $scope.agent.syscheck.end = 'Unknown'; + } + if (!$scope.agent.syscheck.start){ + $scope.agent.syscheck.start = 'Unknown'; } } + } - $scope.getAgent = async (newAgentId,fromAutocomplete) => { - try { - if($scope.tab === 'configuration'){ - return $scope.getAgentConfig(newAgentId); - } + $scope.getAgent = async (newAgentId,fromAutocomplete) => { + try { + $rootScope.completedAgent = false; + if($scope.tab === 'configuration'){ + return $scope.getAgentConfig(newAgentId); + } - try { - // Try to parse the _a trace and detect if there is any agent.id filter - // in order to delete it from the _a trace - const str = $location.search()._a; - if(str){ - const decoded = rison.decode(str); - const tmp = decoded.filters.filter(item => !item.query.match['agent.id']); - decoded.filters = tmp; - const encoded = rison.encode(decoded); - $location.search('_a', encoded) - } - } catch (error) { - // If some rison.js related error is generated we simply clean the _a trace - console.log(error.message || error); // not blocking action - } - let id = null; + let id = null; - // They passed an id - if (newAgentId) { - id = newAgentId; - checkDouble(id); + // They passed an id + if (newAgentId) { + id = newAgentId; + $location.search('agent', id); + } else { + if ($location.search().agent && !$rootScope.globalAgent) { // There's one in the url + id = $location.search().agent; + } else { // We pick the one in the rootScope + id = $rootScope.globalAgent; $location.search('agent', id); - } else { - if ($location.search().agent && !$rootScope.globalAgent) { // There's one in the url - id = $location.search().agent; - checkDouble(id); - } else { // We pick the one in the rootScope - id = $rootScope.globalAgent; - checkDouble(id); - $location.search('agent', id); - delete $rootScope.globalAgent; - } - } - - if (id === '000' && $scope.tab === 'configuration') { - $scope.tab = 'general'; - $scope.switchTab('general'); + delete $rootScope.globalAgent; } + } - const data = await Promise.all([ - apiReq.request('GET', `/agents/${id}`, {}), - apiReq.request('GET', `/syscheck/${id}/last_scan`, {}), - apiReq.request('GET', `/rootcheck/${id}/last_scan`, {}) - ]); - - // Agent - $scope.agent = data[0].data.data; - lastAgent = data[0].data.data.id; - if ($scope.agent.os) { - $scope.agentOS = $scope.agent.os.name + ' ' + $scope.agent.os.version; - } - else { $scope.agentOS = 'Unkwnown' }; - // Syscheck - $scope.agent.syscheck = data[1].data.data; - validateSysCheck(); + if (id === '000' && $scope.tab === 'configuration') { + $scope.tab = 'general'; + discoverPendingUpdates.removeAll(); + $scope.switchTab('general', true); + } - // Rootcheck - $scope.agent.rootcheck = data[2].data.data; - validateRootCheck(); + const data = await Promise.all([ + apiReq.request('GET', `/agents/${id}`, {}), + apiReq.request('GET', `/syscheck/${id}/last_scan`, {}), + apiReq.request('GET', `/rootcheck/${id}/last_scan`, {}) + ]); - if(!$scope.$$phase) $scope.$digest(); - return; - } catch (error) { - errorHandler.handle(error,'Agents'); - if(!$rootScope.$$phase) $rootScope.$digest(); + // Agent + $scope.agent = data[0].data.data; + if ($scope.agent.os) { + $scope.agentOS = $scope.agent.os.name + ' ' + $scope.agent.os.version; } - }; - - $scope.goGroups = agent => { - $rootScope.globalAgent = agent; - $scope.agentsAutoComplete.reset(); - if($rootScope.ownHandlers) { - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; - $rootScope.comeFrom = 'agents'; - $location.search('_a',null); - $location.search('tab', 'groups'); - $location.path('/manager'); - }; - - $scope.analyzeAgents = async search => { - try { - await $timeout(200); - $scope.agentsAutoComplete.filters = []; - await $scope.agentsAutoComplete.addFilter('search',search); + else { $scope.agentOS = 'Unkwnown' }; - if(!$scope.$$phase) $scope.$digest(); - return $scope.agentsAutoComplete.items; - } catch (error) { - errorHandler.handle(error,'Agents'); - if(!$rootScope.$$phase) $rootScope.$digest(); - } + // Syscheck + $scope.agent.syscheck = data[1].data.data; + validateSysCheck(); - } + // Rootcheck + $scope.agent.rootcheck = data[2].data.data; + validateRootCheck(); + + $rootScope.completedAgent = true; - //Load + $scope.switchTab($scope.tab, true); + + if(!$scope.$$phase) $scope.$digest(); + return; + } catch (error) { + errorHandler.handle(error,'Agents'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } + }; + + $scope.goGroups = agent => { + $rootScope.globalAgent = agent; + $scope.agentsAutoComplete.reset(); + visHandlers.removeAll(); + $rootScope.comeFrom = 'agents'; + //$location.search('_a',null); + $location.search('tab', 'groups'); + $location.path('/manager'); + }; + + $scope.analyzeAgents = async search => { try { - if($scope.tab !== 'configuration'){ - $scope.getAgent(); - } - $scope.agentsAutoComplete.nextPage(''); - } catch (e) { - errorHandler.handle('Unexpected exception loading controller','Agents'); + await $timeout(200); + $scope.agentsAutoComplete.filters = []; + await $scope.agentsAutoComplete.addFilter('search',search); + + if(!$scope.$$phase) $scope.$digest(); + return $scope.agentsAutoComplete.items; + } catch (error) { + errorHandler.handle(error,'Agents'); if(!$rootScope.$$phase) $rootScope.$digest(); } - //Destroy - $scope.$on("$destroy", () => { - $rootScope.rawVisualizations = null; - $scope.agentsAutoComplete.reset(); - if($rootScope.ownHandlers) { - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } + } + + //Load + try { + if($scope.tab !== 'configuration'){ + $scope.getAgent(); + } + $scope.agentsAutoComplete.nextPage(''); + } catch (e) { + errorHandler.handle('Unexpected exception loading controller','Agents'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } + + //Destroy + $scope.$on("$destroy", () => { + discoverPendingUpdates.removeAll(); + rawVisualizations.removeAll(); + tabVisualizations.removeAll(); + loadedVisualizations.removeAll(); + $scope.agentsAutoComplete.reset(); + visHandlers.removeAll(); + }); + + //PCI tab + let tabs = []; + genericReq.request('GET', '/api/wazuh-api/pci/all') + .then((data) => { + for(let key in data.data){ + tabs.push({ + "title": key, + "content": data.data[key] + }); } - $rootScope.ownHandlers = []; + }) + .catch(error => { + errorHandler.handle(error,'Agents'); + if(!$rootScope.$$phase) $rootScope.$digest(); }); - //PCI tab - let tabs = []; - genericReq.request('GET', '/api/wazuh-api/pci/all') - .then((data) => { - for(let key in data.data){ - tabs.push({ - "title": key, - "content": data.data[key] - }); - } - }) - .catch(error => { - errorHandler.handle(error,'Agents'); - if(!$rootScope.$$phase) $rootScope.$digest(); - }); + $scope.tabs = tabs; + $scope.selectedIndex = 0; - $scope.tabs = tabs; - $scope.selectedIndex = 0; + $scope.isArray = angular.isArray; - $scope.isArray = angular.isArray; + const getAgent = newAgentId => { - const getAgent = newAgentId => { + // They passed an id + if (newAgentId) { + $location.search('agent', newAgentId); + } - // They passed an id - if (newAgentId) { - $location.search('agent', newAgentId); + }; + + $scope.getAgentConfig = newAgentId => { + getAgent(newAgentId); + firstLoad(); + } + + $scope.goGroup = () => { + $rootScope.globalAgent = $scope.agent; + $rootScope.comeFrom = 'agents'; + $location.path('/manager/groups'); + }; + + const firstLoad = async () => { + try{ + $rootScope.completedAgent = false; + $scope.configurationError = false; + $scope.load = true; + let id; + if ($location.search().agent && !$rootScope.globalAgent) { // There's one in the url + id = $location.search().agent; + } else { // We pick the one in the rootScope + id = $rootScope.globalAgent; + $location.search('agent', id); + delete $rootScope.globalAgent; } - }; + let data = await apiReq.request('GET', `/agents/${id}`, {}); + $scope.agent = data.data.data; + $scope.groupName = $scope.agent.group; - $scope.getAgentConfig = newAgentId => { - getAgent(newAgentId); - firstLoad(); - } + if(!$scope.groupName){ - $scope.goGroup = () => { - $rootScope.globalAgent = $scope.agent; - $rootScope.comeFrom = 'agents'; - $location.search('tab', 'groups'); - $location.path('/manager'); - }; - - const firstLoad = async () => { - try{ - $scope.configurationError = false; - $scope.load = true; - let id; - if ($location.search().agent && !$rootScope.globalAgent) { // There's one in the url - id = $location.search().agent; - } else { // We pick the one in the rootScope - id = $rootScope.globalAgent; - $location.search('agent', id); - delete $rootScope.globalAgent; - } - let data = await apiReq.request('GET', `/agents/${id}`, {}); - $scope.agent = data.data.data; - $scope.groupName = $scope.agent.group; - - if(!$scope.groupName){ - - $scope.configurationError = true; - $scope.load = false; - if($scope.agent.id === '000'){ - $scope.configurationError = false; - $scope.tab = 'general'; - $scope.switchTab('general'); - } - if(!$scope.$$phase) $scope.$digest(); - return; + $scope.configurationError = true; + $scope.load = false; + if($scope.agent.id === '000'){ + $scope.configurationError = false; + $scope.tab = 'general'; + $scope.switchTab('general', true); } + if(!$scope.$$phase) $scope.$digest(); + return; + } - data = await apiReq.request('GET', `/agents/groups/${$scope.groupName}/configuration`, {}); - $scope.groupConfiguration = data.data.data.items[0]; - $scope.rawJSON = beautifier.prettyPrint(data.data.data.items); + data = await apiReq.request('GET', `/agents/groups/${$scope.groupName}/configuration`, {}); + $scope.groupConfiguration = data.data.data.items[0]; + $scope.rawJSON = beautifier.prettyPrint(data.data.data.items); - data = await Promise.all([ - apiReq.request('GET', `/agents/groups?search=${$scope.groupName}`, {}), - apiReq.request('GET', `/agents/groups/${$scope.groupName}`, {}) - ]); + data = await Promise.all([ + apiReq.request('GET', `/agents/groups?search=${$scope.groupName}`, {}), + apiReq.request('GET', `/agents/groups/${$scope.groupName}`, {}) + ]); - let filtered = data[0].data.data.items.filter(item => item.name === $scope.groupName); - $scope.groupMergedSum = (filtered.length) ? filtered[0].merged_sum : 'Unknown'; + let filtered = data[0].data.data.items.filter(item => item.name === $scope.groupName); + $scope.groupMergedSum = (filtered.length) ? filtered[0].merged_sum : 'Unknown'; - filtered = data[1].data.data.items.filter(item => item.id === $scope.agent.id); - $scope.agentMergedSum = (filtered.length) ? filtered[0].merged_sum : 'Unknown'; - $scope.isSynchronized = (($scope.agentMergedSum === $scope.groupMergedSum) && !([$scope.agentMergedSum,$scope.groupMergedSum].includes('Unknown')) ) ? true : false; + filtered = data[1].data.data.items.filter(item => item.id === $scope.agent.id); + $scope.agentMergedSum = (filtered.length) ? filtered[0].merged_sum : 'Unknown'; + $scope.isSynchronized = (($scope.agentMergedSum === $scope.groupMergedSum) && !([$scope.agentMergedSum,$scope.groupMergedSum].includes('Unknown')) ) ? true : false; - $scope.load = false; - if(!$scope.$$phase) $scope.$digest(); - return; - } catch (error){ - errorHandler.handle(error,'Agents'); - if(!$rootScope.$$phase) $rootScope.$digest(); - } - } - /** End of agent configuration */ - if($scope.tab !== 'configuration'){ - $rootScope.rawVisualizations = null; - // Create visualizations for controller's first execution - genericReq.request('GET',`/api/wazuh-elastic/create-vis/agents-${$scope.tab}/${appState.getCurrentPattern()}`) - .then(data => { - $rootScope.rawVisualizations = data.data.raw; - // Render visualizations - $rootScope.$broadcast('updateVis'); + $scope.load = false; - checkMetrics($scope.tab,'panels'); - }) - .catch(error => errorHandler.handle(error, 'Agents')); + $rootScope.completedAgent = true; + if($scope.tab !== 'configuration') $scope.switchTab($scope.tab, true); + + if(!$scope.$$phase) $scope.$digest(); + return; + } catch (error){ + errorHandler.handle(error,'Agents'); + if(!$rootScope.$$phase) $rootScope.$digest(); } - }); + } + /** End of agent configuration */ +}); diff --git a/public/controllers/filter-handler.js b/public/controllers/filter-handler.js new file mode 100644 index 0000000000..c87a87e6f2 --- /dev/null +++ b/public/controllers/filter-handler.js @@ -0,0 +1,103 @@ +/* + * Wazuh app - Filter handler class + * Copyright (C) 2018 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. + */ +export default class FilterHandler { + constructor(pattern) { + this.pattern = pattern; + } + + base(){ + return { + meta: { + removable: false, + index: this.pattern, + negate: false, + disabled: false, + alias: null, + type: 'phrase', + key: null, + value: null, + params: { + query: null, + type: 'phrase' + } + }, + query: { + match: null + }, + $state: { + store: 'appState' + } + } + } + + agentQuery(agent) { + const result = this.base(); + result.meta.key = 'agent.id'; + result.meta.value = agent; + result.meta.params.query = agent; + result.query.match = { + 'agent.id': { + query: agent, + type: 'phrase' + } + }; + return result; + } + + ruleGroupQuery(group) { + const result = this.base(); + result.meta.key = 'rule.groups'; + result.meta.value = group; + result.meta.params.query = group; + result.query.match = { + 'rule.groups': { + query: group, + type: 'phrase' + } + }; + return result; + } + + managerQuery(manager,isCluster) { + const result = this.base(); + result.meta.key = isCluster ? 'cluster.name' : 'manager.name'; + result.meta.value = manager; + result.meta.params.query = manager; + result.query.match = + isCluster ? + { + 'cluster.name': { + query: manager, + type: 'phrase' + } + }: + { + 'manager.name': { + query: manager, + type: 'phrase' + } + }; + return result; + } + + pciQuery(){ + const result = this.base(); + result.meta.type = 'exists'; + result.meta.value = 'exists'; + result.meta.key = 'rule.pci_dss'; + result.exists = { + field: 'rule.pci_dss' + } + delete result.query; + return result; + } +} \ No newline at end of file diff --git a/public/controllers/groups.js b/public/controllers/groups.js index 1c34641d9f..cad31f796b 100644 --- a/public/controllers/groups.js +++ b/public/controllers/groups.js @@ -198,12 +198,6 @@ function ($scope, $rootScope, $location, apiReq, Groups, GroupFiles, GroupAgents $scope.groups.reset(); $scope.groupFiles.reset(); $scope.groupAgents.reset(); - if($rootScope.ownHandlers){ - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; reloadWatcher(); }); @@ -220,11 +214,6 @@ app.controller('groupsController', function ($scope,$rootScope) { $scope.groupsMenu = 'preview'; $scope.groupName = ''; $scope.$on("$destroy", () => { - if($rootScope.ownHandlers){ - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + }); }); diff --git a/public/controllers/manager.js b/public/controllers/manager.js index 89fdd07277..aa6b5bcd7d 100644 --- a/public/controllers/manager.js +++ b/public/controllers/manager.js @@ -53,12 +53,7 @@ app.controller('managerController', function ($scope, $rootScope, $routeParams, $scope.setRulesTab = (tab) => $scope.submenuNavItem2 = tab; $scope.$on("$destroy", () => { - if($rootScope.ownHandlers){ - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + }); }); @@ -102,12 +97,7 @@ app.controller('managerStatusController', function ($scope,$rootScope, errorHand }); $scope.$on("$destroy", () => { - if($rootScope.ownHandlers){ - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + }); }); @@ -164,11 +154,6 @@ app.controller('managerConfigurationController', function ($scope, $rootScope, e load(); $scope.$on("$destroy", () => { - if($rootScope.ownHandlers){ - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + }); }); diff --git a/public/controllers/osseclog.js b/public/controllers/osseclog.js index f6d90d983f..7b4799ef75 100644 --- a/public/controllers/osseclog.js +++ b/public/controllers/osseclog.js @@ -91,11 +91,6 @@ app.controller('managerLogController', function ($scope, $rootScope, Logs, apiRe clearInterval(intervalId); } $scope.logs.reset(); - if($rootScope.ownHandlers){ - for(let h of $rootScope.ownHandlers){ - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; + }); }); diff --git a/public/controllers/overview.js b/public/controllers/overview.js index 3debba56af..1c535a6d37 100644 --- a/public/controllers/overview.js +++ b/public/controllers/overview.js @@ -9,13 +9,19 @@ * * Find more information about this on the LICENSE file. */ -import $ from 'jquery'; -import * as modules from 'ui/modules' +import $ from 'jquery'; +import * as modules from 'ui/modules' +import FilterHandler from './filter-handler' const app = modules.get('app/wazuh', []); -app.controller('overviewController', function ($scope, $location, $rootScope, appState, genericReq, errorHandler, apiReq) { - $rootScope.rawVisualizations = null; +app.controller('overviewController', function ($timeout, $scope, $location, $rootScope, appState, genericReq, errorHandler, apiReq, rawVisualizations, loadedVisualizations, tabVisualizations, discoverPendingUpdates, visHandlers) { + $location.search('_a',null) + const filterHandler = new FilterHandler(appState.getCurrentPattern()); + discoverPendingUpdates.removeAll(); + rawVisualizations.removeAll(); + tabVisualizations.removeAll(); + loadedVisualizations.removeAll(); $rootScope.page = 'overview'; $scope.extensions = appState.getExtensions().extensions; @@ -89,23 +95,20 @@ app.controller('overviewController', function ($scope, $location, $rootScope, ap } else { // If tab doesn't exist, default it to 'general' $scope.tab = 'general'; $location.search('tab', 'general'); - - // Now we initialize the implicitFilter - $rootScope.currentImplicitFilter = ""; } // This object represents the number of visualizations per tab; used to show a progress bar - $rootScope.tabVisualizations = { + tabVisualizations.assign({ general : 11, fim : 10, pm : 5, vuls : 8, oscap : 14, audit : 15, - pci : 6, + pci : 7, aws : 10, virustotal: 7 - }; + }); // Object for matching nav items and rules groups const tabFilters = { @@ -119,6 +122,36 @@ app.controller('overviewController', function ($scope, $location, $rootScope, ap aws : { group: 'amazon' }, virustotal: { group: 'virustotal' } }; + + let filters = [] + + const assignFilters = tab => { + try{ + + filters = []; + + filters.push(filterHandler.managerQuery( + appState.getClusterInfo().status == 'enabled' ? + appState.getClusterInfo().cluster : + appState.getClusterInfo().manager + )) + + if(tab !== 'general'){ + if(tab === 'pci') { + filters.push(filterHandler.pciQuery()) + } else { + filters.push(filterHandler.ruleGroupQuery(tabFilters[tab].group)); + } + } + $rootScope.$emit('wzEventFilters',{filters}); + if(!$rootScope.$$listenerCount['wzEventFilters']){ + $timeout(100) + .then(() => assignFilters(tab)) + } + } catch(error) { + console.log(error.message || error) + } + } const generateMetric = id => { let html = $(id).html(); @@ -175,105 +208,59 @@ app.controller('overviewController', function ($scope, $location, $rootScope, ap } // Switch subtab - $scope.switchSubtab = subtab => { - if ($scope.tabView === subtab) return; + $scope.switchSubtab = (subtab,force = false) => { + if ($scope.tabView === subtab && !force) return; - if(subtab === 'panels'){ - $rootScope.rawVisualizations = null; + visHandlers.removeAll(); + discoverPendingUpdates.removeAll(); + rawVisualizations.removeAll(); + loadedVisualizations.removeAll(); + $location.search('tabView', subtab); + + if(subtab === 'panels' && $scope.tabView === 'discover'){ + $rootScope.$emit('changeTabView',{tabView:$scope.tabView}) + } + + $scope.tabView = subtab; + + if(subtab === 'panels'){ // Create current tab visualizations genericReq.request('GET',`/api/wazuh-elastic/create-vis/overview-${$scope.tab}/${appState.getCurrentPattern()}`) .then(data => { - $rootScope.rawVisualizations = data.data.raw; - // Render visualizations + rawVisualizations.assignItems(data.data.raw); + assignFilters($scope.tab); + $rootScope.$emit('changeTabView',{tabView:subtab}) $rootScope.$broadcast('updateVis'); checkMetrics($scope.tab, 'panels'); }) .catch(error => errorHandler.handle(error, 'Overview')); } else { + $rootScope.$emit('changeTabView',{tabView:$scope.tabView}) checkMetrics($scope.tab, subtab); } } // Switch tab - $scope.switchTab = tab => { - if ($scope.tab === tab) return; - $rootScope.rawVisualizations = null; - - // Create current tab visualizations - genericReq.request('GET',`/api/wazuh-elastic/create-vis/overview-${tab}/${appState.getCurrentPattern()}`) - .then(data => { - $rootScope.rawVisualizations = data.data.raw; - // Render visualizations - $rootScope.$broadcast('updateVis'); - - checkMetrics(tab, 'panels'); - - // Deleting app state traces in the url - $location.search('_a', null); - - }) - .catch(error => errorHandler.handle(error, 'Overview')); - }; - - // Watch tabView - $scope.$watch('tabView', () => { - $location.search('tabView', $scope.tabView); - - if ($rootScope.ownHandlers) { - for (let h of $rootScope.ownHandlers) { - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; - - $rootScope.loadedVisualizations = []; - }); - - // Watch tab - $scope.$watch('tab', () => { + $scope.switchTab = (tab,force = false) => { + tabVisualizations.setTab(tab); + if ($scope.tab === tab && !force) return; $location.search('tab', $scope.tab); + $scope.tab = tab; - $scope.tabView = 'panels'; - - if ($rootScope.ownHandlers) { - for (let h of $rootScope.ownHandlers) { - h._scope.$destroy(); - } - } - $rootScope.ownHandlers = []; - - $rootScope.loadedVisualizations = []; - - // Update the implicit filter - if (tabFilters[$scope.tab].group === "") $rootScope.currentImplicitFilter = ""; - else $rootScope.currentImplicitFilter = tabFilters[$scope.tab].group; - }); + $scope.switchSubtab('panels',true); + }; $scope.$on('$destroy', () => { - $rootScope.rawVisualizations = null; - if ($rootScope.ownHandlers) { - for (let h of $rootScope.ownHandlers) { - h._scope.$destroy(); - } - } - - $rootScope.ownHandlers = []; + discoverPendingUpdates.removeAll(); + rawVisualizations.removeAll(); + tabVisualizations.removeAll(); + loadedVisualizations.removeAll(); + visHandlers.removeAll(); }); - // Create visualizations for controller's first execution - genericReq.request('GET',`/api/wazuh-elastic/create-vis/overview-${$scope.tab}/${appState.getCurrentPattern()}`) - .then(data => { - $rootScope.rawVisualizations = data.data.raw; - // Render visualizations - $rootScope.$broadcast('updateVis'); - - checkMetrics($scope.tab, $scope.tabView); - }) - .catch(error => { - errorHandler.handle(error, 'Overview'); - }); + $scope.switchTab($scope.tab,true); //PCI tab let tabs = []; diff --git a/public/factories/discover-pending-updates.js b/public/factories/discover-pending-updates.js new file mode 100644 index 0000000000..9010a7e2cc --- /dev/null +++ b/public/factories/discover-pending-updates.js @@ -0,0 +1,37 @@ +/* + * Wazuh app - Factory to store pending updates from Discover + * + * Copyright (C) 2018 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 * as modules from 'ui/modules' + +const app = modules.get('app/wazuh', []); + +app.factory('discoverPendingUpdates', function() { + let pendingUpdates = []; + + const addItem = (query, filters) => { + pendingUpdates.push(query, filters); + } + + const getList = () => { + return pendingUpdates; + } + + const removeAll = () => { + pendingUpdates = []; + } + + return { + addItem : addItem, + getList : getList, + removeAll : removeAll + }; +}); \ No newline at end of file diff --git a/public/factories/index.js b/public/factories/index.js index e93c8f07c8..e48bcc341c 100644 --- a/public/factories/index.js +++ b/public/factories/index.js @@ -9,4 +9,9 @@ * * Find more information about this on the LICENSE file. */ -import 'plugins/wazuh/factories/data-handler-composer'; \ No newline at end of file +import 'plugins/wazuh/factories/data-handler-composer'; +import 'plugins/wazuh/factories/raw-visualizations'; +import 'plugins/wazuh/factories/loaded-visualizations'; +import 'plugins/wazuh/factories/tab-visualizations'; +import 'plugins/wazuh/factories/discover-pending-updates'; +import 'plugins/wazuh/factories/vis-handlers'; \ No newline at end of file diff --git a/public/factories/loaded-visualizations.js b/public/factories/loaded-visualizations.js new file mode 100644 index 0000000000..495eb2dd2c --- /dev/null +++ b/public/factories/loaded-visualizations.js @@ -0,0 +1,37 @@ +/* + * Wazuh app - Factory to store loaded visualizations + * + * Copyright (C) 2018 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 * as modules from 'ui/modules' + +const app = modules.get('app/wazuh', []); + +app.factory('loadedVisualizations', function() { + let list = []; + + const addItem = item => { + list.push(item); + } + + const getList = () => { + return list; + } + + const removeAll = () => { + list = []; + } + + return { + addItem : addItem, + getList : getList, + removeAll : removeAll + }; +}); \ No newline at end of file diff --git a/public/factories/raw-visualizations.js b/public/factories/raw-visualizations.js new file mode 100644 index 0000000000..6cd940dcac --- /dev/null +++ b/public/factories/raw-visualizations.js @@ -0,0 +1,41 @@ +/* + * Wazuh app - Factory to store visualizations raw content + * Copyright (C) 2018 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 * as modules from 'ui/modules' + +const app = modules.get('app/wazuh', []); + +app.factory('rawVisualizations', function() { + let list = []; + + const addItem = item => { + list.push(item); + } + + const assignItems = items => { + list = Array.isArray(items) ? items : []; + } + + const getList = () => { + return list; + } + + const removeAll = () => { + list = []; + } + + return { + addItem : addItem, + getList : getList, + removeAll : removeAll, + assignItems: assignItems + }; +}); \ No newline at end of file diff --git a/public/factories/tab-visualizations.js b/public/factories/tab-visualizations.js new file mode 100644 index 0000000000..21af9d2780 --- /dev/null +++ b/public/factories/tab-visualizations.js @@ -0,0 +1,46 @@ +/* + * Wazuh app - Factory to store visualization tabs + * + * Copyright (C) 2018 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 * as modules from 'ui/modules' + +const app = modules.get('app/wazuh', []); + +app.factory('tabVisualizations', function() { + let tabVisualizations = {} + let currentTab = ''; + + const setTab = tab => currentTab = tab; + + const getTab = () => { + return currentTab; + } + + const getItem = item => { + return tabVisualizations[item] + } + + const assign = tabs => { + tabVisualizations = tabs; + } + + const removeAll = () => { + tabVisualizations = {}; + } + + return { + getItem : getItem, + removeAll: removeAll, + assign : assign, + setTab : setTab, + getTab : getTab + }; +}); \ No newline at end of file diff --git a/public/factories/vis-handlers.js b/public/factories/vis-handlers.js new file mode 100644 index 0000000000..0e3fa4995a --- /dev/null +++ b/public/factories/vis-handlers.js @@ -0,0 +1,45 @@ +/* + * Wazuh app - Factory to store visualizations handlers + * + * Copyright (C) 2018 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 * as modules from 'ui/modules' + +const app = modules.get('app/wazuh', []); + +app.factory('visHandlers', function() { + let list = []; + + const addItem = item => { + list.push(item); + } + + const getList = () => { + return list; + } + + const removeAll = () => { + for(const item of list){ + if(item && item._scope){ + item._scope.$destroy(); + } + if(item && item._scope && item._scope.savedObj){ + item._scope.savedObj.destroy(); + } + } + list = []; + } + + return { + addItem : addItem, + getList : getList, + removeAll : removeAll + }; +}); \ No newline at end of file diff --git a/public/kibana-integrations/kibana-discover.js b/public/kibana-integrations/kibana-discover.js index fbdf4be356..5a90f6b437 100644 --- a/public/kibana-integrations/kibana-discover.js +++ b/public/kibana-integrations/kibana-discover.js @@ -39,7 +39,6 @@ import 'ui/registry/doc_views.js'; import 'plugins/kbn_doc_views/kbn_doc_views.js'; import 'ui/tooltip/tooltip.js'; import moment from 'moment'; -import rison from 'rison-node'; import 'ui/pager_control'; import 'ui/pager'; import { UtilsBrushEventProvider } from 'ui/utils/brush_event'; @@ -115,7 +114,11 @@ function discoverController( timefilter, appState, $rootScope, - $location + $location, + getAppState, + globalState, + loadedVisualizations, + discoverPendingUpdates ) { const Vis = Private(VisProvider); @@ -310,13 +313,12 @@ function discoverController( //////////////////////////////////////////////////////////////////////////// /////////////////////////////// WAZUH /////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - - $rootScope.discoverPendingUpdates = []; - $rootScope.discoverPendingUpdates.push($state.query, queryFilter.getFilters()); - $rootScope.$broadcast('updateVis', $state.query, queryFilter.getFilters()); + discoverPendingUpdates.removeAll() + discoverPendingUpdates.addItem($state.query,queryFilter.getFilters()); + $rootScope.$broadcast('updateVis'); $rootScope.$broadcast('fetch'); if($location.search().tab != 'configuration') { - $rootScope.loadedVisualizations = []; + loadedVisualizations.removeAll(); $rootScope.rendered = false; $rootScope.loadingStatus = "Fetching data..."; } @@ -471,13 +473,14 @@ function discoverController( if ($state.query.language && $state.query.language !== query.language) { $state.filters = []; } - //////////////////////////////////////////////////////////////////////////// /////////////////////////////// WAZUH /////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - $rootScope.discoverPendingUpdates = []; - $rootScope.discoverPendingUpdates.push($state.query, queryFilter.getFilters()); - $rootScope.$broadcast('updateVis', $state.query, queryFilter.getFilters()); + const filters = queryFilter.getFilters(); + if(!filters || !filters.length) return; + discoverPendingUpdates.removeAll() + discoverPendingUpdates.addItem($state.query,queryFilter.getFilters()); + $rootScope.$broadcast('updateVis'); $rootScope.$broadcast('fetch'); //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// @@ -617,7 +620,7 @@ function discoverController( /////////////////////////////// WAZUH /////////////////////////////////// //////////////////////////////////////////////////////////////////////////// if($location.search().tab != 'configuration') { - $rootScope.loadedVisualizations = []; + loadedVisualizations.removeAll(); $rootScope.rendered = false; $rootScope.loadingStatus = "Fetching data..."; } @@ -757,188 +760,33 @@ function discoverController( ////////////////////////////////////////////////////// WAZUH ////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - function loadFilters() { - if ($scope.tab) { - let implicitFilter = []; - - if (appState.getClusterInfo().status == 'enabled') { - // The cluster filter - implicitFilter.push( - { - "meta":{ - "removable":false, - "index":$scope.indexPattern.id, - "negate":false, - "disabled":false, - "alias":null, - "type":"phrase", - "key":"cluster.name", - "value":appState.getClusterInfo().cluster, - "params":{ - "query":appState.getClusterInfo().cluster, - "type":"phrase"} - }, - "query":{ - "match":{ - "cluster.name":{ - "query":appState.getClusterInfo().cluster, - "type":"phrase"} - } - }, - "$state":{ - "store":"appState" - } - } - ); - } else { - // Manager name filter - implicitFilter.push( - { - "meta":{ - "removable":false, - "index":$scope.indexPattern.id, - "negate":false, - "disabled":false, - "alias":null, - "type":"phrase", - "key":"manager.name", - "value":appState.getClusterInfo().manager, - "params":{ - "query":appState.getClusterInfo().manager, - "type":"phrase"} - }, - "query":{ - "match":{ - "manager.name":{ - "query":appState.getClusterInfo().manager, - "type":"phrase"} - } - }, - "$state":{ - "store":"appState" - } - } - ); - } - - // Check if we are in the agents page and add the proper agent filter - if ($rootScope.page === 'agents' && $location.search().agent !== "" && $location.search().agent !== null && angular.isUndefined($location.search().agent) !== true) { - implicitFilter.push( - { - "meta":{ - "removable":false, - "index":$scope.indexPattern.id, - "negate":false, - "disabled":false, - "alias":null, - "type":"phrase", - "key":"agent.id", - "value":$location.search().agent, - "params":{ - "query":$location.search().agent, - "type":"phrase"} - }, - "query":{ - "match":{ - "agent.id":{ - "query":$location.search().agent, - "type":"phrase"} - } - }, - "$state":{ - "store":"appState" - } - } - ); - } - - // Build the full query using the implicit filter - if ($rootScope.currentImplicitFilter !== "" && $rootScope.currentImplicitFilter !== null && angular.isUndefined($rootScope.currentImplicitFilter) !== true) { - if ($rootScope.currentImplicitFilter === "pci_dss") { - implicitFilter.push( - { - "meta":{ - "removable":false, - "index":$scope.indexPattern.id, - "negate":false, - "disabled":false, - "alias":null, - "type":"exists", - "key":"rule.pci_dss", - "value":"exists" - }, - "exists":{ - "field":"rule.pci_dss" - }, - "$state":{ - "store":"appState" - } - } - ); - } else { - implicitFilter.push( - { - "meta":{ - "removable":false, - "index":$scope.indexPattern.id, - "negate":false, - "disabled":false, - "alias":null, - "type":"phrase", - "key":"rule.groups", - "value":$rootScope.currentImplicitFilter, - "params":{ - "query":$rootScope.currentImplicitFilter, - "type":"phrase" - } - }, - "query":{ - "match":{ - "rule.groups":{ - "query":$rootScope.currentImplicitFilter, - "type":"phrase" - } - } - }, - "$state":{ - "store":"appState" - } - } - ); - } - } + const loadFilters = wzCurrentFilters => { + const appState = getAppState(); + if(!appState || !globalState){ + $timeout(100) + .then(() => { + console.log('Awaiting app state...') + return loadFilters(wzCurrentFilters) + }) + } else { + $state.filters = []; - queryFilter.addFilters(implicitFilter); + queryFilter.addFilters(wzCurrentFilters) + .then(() => console.log('Filters loaded successfully')) + .catch(error => console.log(error.message || error)); } } - // Getting the location from the url - $scope.tabView = $location.search().tabView; - $scope.tab = $location.search().tab; - if ($rootScope.page === 'agents') $scope.agentId = $location.search().agent; - - // Initial loading of filters - loadFilters(); - - // Watch for changes in the location - $scope.$on('$routeUpdate', () => { - - if ($location.search().tabView != $scope.tabView) { // No need to change the filters - if ($scope.tabView !== "discover") { // Should do this the first time, to avoid the squeezing of the visualization - $scope.updateQueryAndFetch($state.query); - } - $scope.tabView = $location.search().tabView; - } - if ($location.search().tab != $scope.tab) { // Changing filters - $scope.tab = $location.search().tab; - } - - if ($location.search().agent != $scope.agentId) { // Changing filters - $scope.agentId = $location.search().agent; - } - if ($location.search().tabView === $scope.tabView) loadFilters(); + $rootScope.$on('wzEventFilters', (evt,parameters) => { + loadFilters(parameters.filters); }); + + $scope.tabView = $location.search().tabView || 'panels' + $rootScope.$on('changeTabView',(evt,parameters) => { + $scope.tabView = parameters.tabView || 'panels' + $scope.updateQueryAndFetch($state.query); + }) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/public/kibana-integrations/kibana-filter-bar.js b/public/kibana-integrations/kibana-filter-bar.js index 028a2f4939..8be7eb9d4f 100644 --- a/public/kibana-integrations/kibana-filter-bar.js +++ b/public/kibana-integrations/kibana-filter-bar.js @@ -106,7 +106,7 @@ module.directive('filterBarW', function (Private, Promise, getAppState) { $scope.$watch('state.$newFilters', function (filters) { if (!filters) return; - + // If filters is not undefined and the length is greater than // one we need to set the newFilters attribute and allow the // users to decide what they want to apply. diff --git a/public/kibana-integrations/kibana-visualization.js b/public/kibana-integrations/kibana-visualization.js index 8ae51a0f8d..513ea1b319 100644 --- a/public/kibana-integrations/kibana-visualization.js +++ b/public/kibana-integrations/kibana-visualization.js @@ -21,8 +21,8 @@ const app = modules.get('apps/webinar_app', []) visID: '=visId', specificTimeRange: '=specificTimeRange' }, - controller: function VisController($scope, $rootScope, $location, wzsavedVisualizations, genericReq, errorHandler,Private) { - if(!$rootScope.ownHandlers) $rootScope.ownHandlers = []; + controller: function VisController($scope, $rootScope, $location, wzsavedVisualizations, genericReq, errorHandler, Private, rawVisualizations, loadedVisualizations, tabVisualizations, discoverPendingUpdates, visHandlers) { + let originalImplicitFilter = ''; let implicitFilter = ''; let visTitle = ''; @@ -33,13 +33,12 @@ const app = modules.get('apps/webinar_app', []) let renderInProgress = false; const myRender = raw => { - - if (raw && (($rootScope.discoverPendingUpdates && $rootScope.discoverPendingUpdates.length != 0) || $scope.visID.includes('Ruleset') ) ) { // There are pending updates from the discover (which is the one who owns the true app state) - + if (raw && discoverPendingUpdates.getList().length) { // There are pending updates from the discover (which is the one who owns the true app state) + const discoverList = discoverPendingUpdates.getList(); if(!visualization && !rendered && !renderInProgress) { // There's no visualization object -> create it with proper filters renderInProgress = true; - const rawVis = raw.filter(item => item.id === $scope.visID); + const rawVis = raw.filter(item => item && item.id === $scope.visID); wzsavedVisualizations.get($scope.visID,rawVis[0]).then(savedObj => { originalImplicitFilter = savedObj.searchSource.get('query')['query']; visTitle = savedObj.vis.title; @@ -48,21 +47,21 @@ const app = modules.get('apps/webinar_app', []) // There's an original filter if (originalImplicitFilter.length > 0 ) { // And also a pending one -> concatenate them - if ($rootScope.discoverPendingUpdates && typeof $rootScope.discoverPendingUpdates[0].query === 'string' && $rootScope.discoverPendingUpdates[0].query.length > 0) { - implicitFilter = originalImplicitFilter + ' AND ' + $rootScope.discoverPendingUpdates[0].query; + if (typeof discoverList[0].query === 'string' && discoverList[0].query.length > 0) { + implicitFilter = originalImplicitFilter + ' AND ' + discoverList[0].query; } else { // Only the original filter implicitFilter = originalImplicitFilter; } } else { // Other case, use the pending one, if it is empty, it won't matter - implicitFilter = $rootScope.discoverPendingUpdates ? $rootScope.discoverPendingUpdates[0].query : ''; + implicitFilter = discoverList ? discoverList[0].query : ''; } if (visTitle !== 'Wazuh App Overview General Agents status') { // We don't want to filter that visualization as it uses another index-pattern visualization.searchSource .query({ language: 'lucene', query: implicitFilter }) - .set('filter', $rootScope.discoverPendingUpdates ? $rootScope.discoverPendingUpdates[1] : {}); + .set('filter', discoverList.length > 1 ? discoverList[1] : {}); } let params = {}; @@ -81,7 +80,7 @@ const app = modules.get('apps/webinar_app', []) visHandler = loader.embedVisualizationWithSavedObject($(`[vis-id="'${$scope.visID}'"]`), visualization, params); - $rootScope.ownHandlers.push(visHandler); + visHandlers.addItem(visHandler); visHandler.addRenderCompleteListener(renderComplete); }).catch(error => { if(error && error.message && error.message.includes('not locate that index-pattern-field')){ @@ -96,38 +95,45 @@ const app = modules.get('apps/webinar_app', []) // There's an original filter if (originalImplicitFilter.length > 0 ) { // And also a pending one -> concatenate them - if ($rootScope.discoverPendingUpdates && typeof $rootScope.discoverPendingUpdates[0].query === 'string' && $rootScope.discoverPendingUpdates[0].query.length > 0) { - implicitFilter = originalImplicitFilter + ' AND ' + $rootScope.discoverPendingUpdates[0].query; + if (discoverList[0].query === 'string' && discoverList[0].query.length > 0) { + implicitFilter = originalImplicitFilter + ' AND ' + discoverList[0].query; } else { // Only the original filter implicitFilter = originalImplicitFilter; } } else { // Other case, use the pending one, if it is empty, it won't matter - implicitFilter = $rootScope.discoverPendingUpdates ? $rootScope.discoverPendingUpdates[0].query : ''; + implicitFilter = discoverList ? discoverList[0].query : ''; } if (visTitle !== 'Wazuh App Overview General Agents status') { // We don't want to filter that visualization as it uses another index-pattern visualization.searchSource .query({ language: 'lucene', query: implicitFilter }) - .set('filter', $rootScope.discoverPendingUpdates ? $rootScope.discoverPendingUpdates[1] : {}); + .set('filter', discoverList.length > 1 ? discoverList[1] : {}); } } } }; // Listen for changes - $rootScope.$on('updateVis', function (event, query, filters) { + const updateVisWatcher = $rootScope.$on('updateVis', () => { if(!$rootScope.$$phase) $rootScope.$digest(); - myRender($rootScope.rawVisualizations); + const rawVis = rawVisualizations.getList(); + if(Array.isArray(rawVis) && rawVis.length){ + myRender(rawVis); + } }); - var renderComplete = function() { + $scope.$on('$destroy',() => { + updateVisWatcher(); + }) + + const renderComplete = () => { rendered = true; - - if(typeof $rootScope.loadedVisualizations === 'undefined') $rootScope.loadedVisualizations = []; - $rootScope.loadedVisualizations.push(true); - let currentCompleted = Math.round(($rootScope.loadedVisualizations.length / $rootScope.tabVisualizations[$location.search().tab]) * 100); + + loadedVisualizations.addItem(true); + + let currentCompleted = Math.round((loadedVisualizations.getList().length / tabVisualizations.getItem(tabVisualizations.getTab())) * 100); $rootScope.loadingStatus = `Rendering visualizations... ${currentCompleted > 100 ? 100 : currentCompleted} %`; if (currentCompleted >= 100) { diff --git a/public/templates/agents/agents-audit.html b/public/templates/agents/agents-audit.html index a91e37ed9a..cdc04f7691 100644 --- a/public/templates/agents/agents-audit.html +++ b/public/templates/agents/agents-audit.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-fim.html b/public/templates/agents/agents-fim.html index 9b3bc16e69..3abf5b6b11 100644 --- a/public/templates/agents/agents-fim.html +++ b/public/templates/agents/agents-fim.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-general.html b/public/templates/agents/agents-general.html index c74b16a74d..1d761276fb 100644 --- a/public/templates/agents/agents-general.html +++ b/public/templates/agents/agents-general.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-oscap.html b/public/templates/agents/agents-oscap.html index 724f274477..3fb1430542 100644 --- a/public/templates/agents/agents-oscap.html +++ b/public/templates/agents/agents-oscap.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-pci.html b/public/templates/agents/agents-pci.html index 1d2832476c..bc74cf5e15 100644 --- a/public/templates/agents/agents-pci.html +++ b/public/templates/agents/agents-pci.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-pm.html b/public/templates/agents/agents-pm.html index 72ffbcbaeb..5aca063e90 100644 --- a/public/templates/agents/agents-pm.html +++ b/public/templates/agents/agents-pm.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-virustotal.html b/public/templates/agents/agents-virustotal.html index 1d876ec4e9..ab55444adf 100644 --- a/public/templates/agents/agents-virustotal.html +++ b/public/templates/agents/agents-virustotal.html @@ -1,4 +1,4 @@ - + diff --git a/public/templates/agents/agents-vuls.html b/public/templates/agents/agents-vuls.html index 8aa6b2545d..c90abe6767 100644 --- a/public/templates/agents/agents-vuls.html +++ b/public/templates/agents/agents-vuls.html @@ -1,4 +1,4 @@ - +