wazuh-kibana-app/public/controllers/agents.js

485 lines
17 KiB
JavaScript
Raw Normal View History

/*
* Wazuh app - Agents controller
* 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.
*/
2018-05-14 08:05:25 +00:00
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', []);
2017-01-16 12:29:48 +00:00
2018-05-15 14:21:44 +00:00
app.controller('agentsController', function ($timeout, $scope, $location, $rootScope, appState, genericReq, apiReq, AgentsAutoComplete, errorHandler, rawVisualizations, loadedVisualizations, tabVisualizations, discoverPendingUpdates, visHandlers) {
2018-05-15 14:11:35 +00:00
$location.search('_a',null)
2018-05-14 08:05:25 +00:00
const filterHandler = new FilterHandler(appState.getCurrentPattern());
2018-05-15 14:21:44 +00:00
visHandlers.removeAll();
2018-05-15 14:11:35 +00:00
discoverPendingUpdates.removeAll();
rawVisualizations.removeAll();
tabVisualizations.removeAll();
loadedVisualizations.removeAll();
2018-05-14 08:05:25 +00:00
$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\'"]'
}
2018-05-15 12:01:26 +00:00
tabVisualizations.assign({
2018-05-14 08:05:25 +00:00
general : 7,
fim : 8,
pm : 4,
vuls : 7,
oscap : 13,
audit : 15,
pci : 3,
virustotal : 6,
configuration: 0
2018-05-15 12:01:26 +00:00
});
2018-05-14 08:05:25 +00:00
// 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' }
};
let filters = []
const assignFilters = (tab,agent) => {
2018-05-14 15:12:10 +00:00
try {
2018-05-15 14:11:35 +00:00
console.log(agent)
2018-05-14 15:12:10 +00:00
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));
}
2018-05-14 08:05:25 +00:00
}
2018-05-14 15:12:10 +00:00
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)
2018-03-09 10:20:20 +00:00
}
2018-05-14 08:05:25 +00:00
}
const generateMetric = id => {
let html = $(id).html();
if (typeof html !== 'undefined' && html.includes('<span')) {
if(typeof html.split('<span>')[1] !== 'undefined'){
return html.split('<span>')[1].split('</span')[0];
} else if(html.includes('table') && html.includes('cell-hover')){
let nonB = html.split('ng-non-bindable')[1];
if(nonB &&
nonB.split('>')[1] &&
nonB.split('>')[1].split('</')[0]
) {
return nonB.split('>')[1].split('</')[0];
2018-04-19 10:03:33 +00:00
}
}
}
2018-05-14 08:05:25 +00:00
return '';
}
2018-05-14 08:05:25 +00:00
const createMetrics = metricsObject => {
for(let key in metricsObject) {
$scope[key] = () => generateMetric(metricsObject[key]);
}
}
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;
2018-04-19 10:03:33 +00:00
}
}
2018-05-14 08:05:25 +00:00
if(!$rootScope.$$phase) $rootScope.$digest();
}
2018-03-08 16:59:08 +00:00
2018-05-14 08:05:25 +00:00
// Switch subtab
$scope.switchSubtab = (subtab, force = false) => {
if($scope.tabView === subtab && !force) return;
2018-05-15 14:21:44 +00:00
visHandlers.removeAll();
2018-05-15 14:11:35 +00:00
discoverPendingUpdates.removeAll();
rawVisualizations.removeAll();
2018-05-15 14:11:35 +00:00
loadedVisualizations.removeAll();
$location.search('tabView', subtab);
$scope.tabView = subtab;
2018-05-14 08:05:25 +00:00
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);
2018-05-15 14:11:35 +00:00
assignFilters($scope.tab, $scope.agent.id);
$rootScope.$emit('changeTabView',{tabView:$scope.tabView})
2018-05-14 08:05:25 +00:00
$rootScope.$broadcast('updateVis');
checkMetrics($scope.tab, 'panels');
})
.catch(error => errorHandler.handle(error, 'Agents'));
} else {
checkMetrics($scope.tab, subtab);
}
2018-05-14 08:05:25 +00:00
}
2018-05-14 08:05:25 +00:00
// Switch tab
$scope.switchTab = (tab, force = false) => {
2018-05-15 12:01:26 +00:00
tabVisualizations.setTab(tab);
if ($scope.tab === tab && !force) return;
$location.search('tab', tab);
$scope.tab = tab;
2018-03-20 15:20:50 +00:00
2018-05-14 08:05:25 +00:00
if($scope.tab === 'configuration'){
firstLoad();
} else {
2018-05-15 14:11:35 +00:00
$scope.switchSubtab('panels', true);
2018-05-14 08:05:25 +00:00
}
};
2018-05-14 09:02:48 +00:00
2018-05-14 08:05:25 +00:00
// Agent data
$scope.getAgentStatusClass = (agentStatus) => agentStatus === "Active" ? "teal" : "red";
2018-05-14 08:05:25 +00:00
$scope.formatAgentStatus = (agentStatus) => {
return ['Active','Disconnected'].includes(agentStatus) ? agentStatus : 'Never connected';
};
2018-05-14 08:05:25 +00:00
const calculateMinutes = (start,end) => {
let time = new Date(start);
let endTime = new Date(end);
let minutes = ((endTime - time) / 1000) / 60;
return minutes;
}
2018-05-14 08:05:25 +00:00
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;
2018-05-14 08:05:25 +00:00
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';
}
}
2018-05-14 08:05:25 +00:00
}
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';
}
}
2018-05-14 08:05:25 +00:00
}
2018-05-14 08:05:25 +00:00
$scope.getAgent = async (newAgentId,fromAutocomplete) => {
try {
$rootScope.completedAgent = false;
if($scope.tab === 'configuration'){
return $scope.getAgentConfig(newAgentId);
}
2018-05-14 08:05:25 +00:00
let id = null;
2018-05-14 08:05:25 +00:00
// 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);
2018-05-14 08:05:25 +00:00
delete $rootScope.globalAgent;
}
2018-05-14 08:05:25 +00:00
}
2018-05-14 15:12:10 +00:00
2018-05-14 08:05:25 +00:00
if (id === '000' && $scope.tab === 'configuration') {
$scope.tab = 'general';
2018-05-15 14:11:35 +00:00
discoverPendingUpdates.removeAll();
$scope.switchTab('general', true);
2018-05-14 08:05:25 +00:00
}
2018-05-14 08:05:25 +00:00
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;
if ($scope.agent.os) {
$scope.agentOS = $scope.agent.os.name + ' ' + $scope.agent.os.version;
}
else { $scope.agentOS = 'Unkwnown' };
2018-05-14 08:05:25 +00:00
// Syscheck
$scope.agent.syscheck = data[1].data.data;
validateSysCheck();
2017-12-11 08:33:43 +00:00
2018-05-14 08:05:25 +00:00
// Rootcheck
$scope.agent.rootcheck = data[2].data.data;
validateRootCheck();
2017-12-12 16:27:29 +00:00
2018-05-14 08:05:25 +00:00
$rootScope.completedAgent = true;
$scope.switchTab($scope.tab, true);
2018-05-15 09:02:21 +00:00
2018-05-14 08:05:25 +00:00
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();
2018-05-15 14:21:44 +00:00
visHandlers.removeAll();
2018-05-14 08:05:25 +00:00
$rootScope.comeFrom = 'agents';
//$location.search('_a',null);
$location.search('tab', 'groups');
$location.path('/manager');
};
$scope.analyzeAgents = async search => {
try {
2018-05-14 08:05:25 +00:00
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();
}
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
}
//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", () => {
2018-05-15 14:11:35 +00:00
discoverPendingUpdates.removeAll();
rawVisualizations.removeAll();
2018-05-15 12:01:26 +00:00
tabVisualizations.removeAll();
2018-05-15 14:11:35 +00:00
loadedVisualizations.removeAll();
2018-05-14 08:05:25 +00:00
$scope.agentsAutoComplete.reset();
2018-05-15 14:21:44 +00:00
visHandlers.removeAll();
2018-05-14 08:05:25 +00:00
});
//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]
});
}
2018-05-14 08:05:25 +00:00
})
.catch(error => {
errorHandler.handle(error,'Agents');
if(!$rootScope.$$phase) $rootScope.$digest();
});
2018-05-14 08:05:25 +00:00
$scope.tabs = tabs;
$scope.selectedIndex = 0;
2018-01-17 16:29:49 +00:00
2018-05-14 08:05:25 +00:00
$scope.isArray = angular.isArray;
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
const getAgent = newAgentId => {
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
// They passed an id
if (newAgentId) {
$location.search('agent', newAgentId);
}
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
};
$scope.getAgentConfig = newAgentId => {
getAgent(newAgentId);
firstLoad();
}
$scope.goGroup = () => {
$rootScope.globalAgent = $scope.agent;
$rootScope.comeFrom = 'agents';
2018-05-14 15:12:10 +00:00
$location.path('/manager/groups');
2018-05-14 08:05:25 +00:00
};
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;
}
2018-05-14 15:12:10 +00:00
2018-05-14 08:05:25 +00:00
let data = await apiReq.request('GET', `/agents/${id}`, {});
$scope.agent = data.data.data;
$scope.groupName = $scope.agent.group;
2018-05-14 08:05:25 +00:00
if(!$scope.groupName){
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
$scope.configurationError = true;
$scope.load = false;
if($scope.agent.id === '000'){
$scope.configurationError = false;
$scope.tab = 'general';
2018-05-15 14:11:35 +00:00
$scope.switchTab('general', true);
2018-01-15 15:11:45 +00:00
}
2018-05-14 08:05:25 +00:00
if(!$scope.$$phase) $scope.$digest();
return;
}
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
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);
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
data = await Promise.all([
apiReq.request('GET', `/agents/groups?search=${$scope.groupName}`, {}),
apiReq.request('GET', `/agents/groups/${$scope.groupName}`, {})
]);
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
let filtered = data[0].data.data.items.filter(item => item.name === $scope.groupName);
$scope.groupMergedSum = (filtered.length) ? filtered[0].merged_sum : 'Unknown';
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
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;
2018-01-15 15:11:45 +00:00
2018-05-14 08:05:25 +00:00
$scope.load = false;
2018-05-14 09:02:48 +00:00
2018-05-14 08:05:25 +00:00
$rootScope.completedAgent = true;
2018-05-15 14:11:35 +00:00
if($scope.tab !== 'configuration') $scope.switchTab($scope.tab, true);
2018-05-14 08:05:25 +00:00
if(!$scope.$$phase) $scope.$digest();
return;
} catch (error){
errorHandler.handle(error,'Agents');
if(!$rootScope.$$phase) $rootScope.$digest();
}
2018-05-14 08:05:25 +00:00
}
/** End of agent configuration */
});