From d19188b0032851d1bae2dc140e970cb82a3ca41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Wed, 25 Apr 2018 16:24:27 +0200 Subject: [PATCH 01/15] Added route to fetch data from the Wazuh api on csv format --- package.json | 1 + server/controllers/wazuh-api.js | 54 ++++++++++++++++++++++++++++++++- server/routes/wazuh-api.js | 4 ++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index da248f73f8..5b5dfa10eb 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "ansicolors": "^0.3.2", "install": "^0.10.1", "js-yaml": "3.10.0", + "json2csv": "^4.1.2", "lodash": "3.10.1", "needle": "^2.0.1", "node-cron": "^1.1.2", diff --git a/server/controllers/wazuh-api.js b/server/controllers/wazuh-api.js index 02e55efb91..af8e184a39 100644 --- a/server/controllers/wazuh-api.js +++ b/server/controllers/wazuh-api.js @@ -21,7 +21,7 @@ import ElasticWrapper from '../lib/elastic-wrapper' import getPath from '../../util/get-path' import packageInfo from '../../package.json' import monitoring from '../monitoring' - +import { Parser } from 'json2csv'; const blueWazuh = colors.blue('wazuh'); export default class WazuhApi { @@ -497,4 +497,56 @@ export default class WazuhApi { return reply(this.genericErrorBuilder(500,6,error.message || error)).code(500) } } + + /** + * Get full data on CSV format from a list Wazuh API endpoint + * @param {*} req + * @param {*} res + */ + async csv(req,res) { + try{ + + if(!req.payload || !req.payload.path) throw new Error('Field path is required') + if(!req.payload.id) throw new Error('Field id is required') + + const config = await this.wzWrapper.getWazuhConfigurationById(req.payload.id) + + let path = req.payload.path; + + if(path && typeof path === 'string'){ + path = path[0] === '/' ? path.substr(1) : path + } + + if(!path) throw new Error('An error occurred parsing path field') + + const output = await needle('get', `${config.url}:${config.port}/${path}`, { limit:99999 }, { + username : config.user, + password : config.password, + rejectUnauthorized: !config.insecure + }) + + if(output && output.body && output.body.data && output.body.data.totalItems) { + const fields = Object.keys(output.body.data.items[0]); + const data = output.body.data.items; + + const json2csvParser = new Parser({ fields }); + + const csv = json2csvParser.parse(data); + + return res(new Buffer(csv)); + + } else if (output && output.body && output.body.data && !output.body.data.totalItems) { + + throw new Error('No results') + + } else { + + throw new Error('An error occurred fetching data from the Wazuh API') + + } + + } catch (error) { + return res({ error: error.message || error }).code(500) + } + } } diff --git a/server/routes/wazuh-api.js b/server/routes/wazuh-api.js index 731d7f7fc0..f482840be2 100644 --- a/server/routes/wazuh-api.js +++ b/server/routes/wazuh-api.js @@ -40,5 +40,7 @@ export default (server, options) => { server.route({ method: 'GET', path: '/api/wazuh-api/configuration', handler: (req,res) => ctrl.getConfigurationFile(req,res) }); // COMMENT HERE - server.route({ method: 'POST',path: '/api/wazuh-api/wlogin', handler: (req,res) => ctrl.login(req,res) }); + server.route({ method: 'POST', path: '/api/wazuh-api/wlogin', handler: (req,res) => ctrl.login(req,res) }); + + server.route({ method: 'POST', path: '/api/wazuh-api/csv', handler: (req,res) => ctrl.csv(req,res)}) }; From 838343db8c7128574fc68e9d1395a4dc17ebdaba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Thu, 26 Apr 2018 13:51:49 +0200 Subject: [PATCH 02/15] Example CSV generated successfully (in progress) --- public/app.js | 1 + public/controllers/osseclog.js | 37 ++++++++++++++++++- public/services/csv-request.js | 27 ++++++++++++++ .../templates/manager/manager-osseclog.html | 1 + server/controllers/wazuh-api.js | 4 +- 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 public/services/csv-request.js diff --git a/public/app.js b/public/app.js index 7bf02e61dd..0ee8c3855e 100644 --- a/public/app.js +++ b/public/app.js @@ -56,6 +56,7 @@ import 'plugins/wazuh/services/data-handler.js'; import 'plugins/wazuh/services/app-state.js'; import 'plugins/wazuh/services/api-tester.js'; import 'plugins/wazuh/services/pattern-handler.js'; +import 'plugins/wazuh/services/csv-request.js'; // Set up routes and views import 'plugins/wazuh/services/routes.js'; diff --git a/public/controllers/osseclog.js b/public/controllers/osseclog.js index df37436aaf..7984759b4e 100644 --- a/public/controllers/osseclog.js +++ b/public/controllers/osseclog.js @@ -13,8 +13,35 @@ import * as modules from 'ui/modules' const app = modules.get('app/wazuh', []); + // Logs controller -app.controller('managerLogController', function ($scope, $rootScope, Logs, apiReq, errorHandler) { +app.controller('managerLogController', function ($scope, $rootScope, Logs, apiReq, errorHandler, csvReq, appState, $window) { + + function CsvGenerator(dataArray, fileName) { + this.dataArray = dataArray; + this.fileName = fileName; + + + this.getLinkElement = function (linkText) { + return this.linkElement = this.linkElement || $('' + (linkText || '') + '', { + href: 'data:attachment/csv;base64,' + encodeURI($window.btoa(this.dataArray)), + target: '_blank', + download: this.fileName + }); + }; + + // call with removeAfterDownload = true if you want the link to be removed after downloading + this.download = function (removeAfterDownload) { + this.getLinkElement().css('display', 'none').appendTo('body'); + this.getLinkElement()[0].click(); + if (removeAfterDownload) { + this.getLinkElement().remove(); + } + }; + } + + + $scope.searchTerm = ''; $scope.loading = true; $scope.logs = Logs; @@ -48,8 +75,14 @@ app.controller('managerLogController', function ($scope, $rootScope, Logs, apiRe if(!$scope.$$phase) $scope.$digest(); } + $scope.downloadCsv = async () => { + const output = await csvReq.fetch('/manager/logs',JSON.parse(appState.getCurrentAPI()).id) + let csvGenerator = new CsvGenerator(output.csv, 'my_table.csv'); + csvGenerator.download(true); + } + const initialize = async () => { - try{ + try{ await $scope.logs.nextPage(); const data = await apiReq.request('GET', '/manager/logs/summary', {}); $scope.summary = data.data.data; diff --git a/public/services/csv-request.js b/public/services/csv-request.js new file mode 100644 index 0000000000..84055d35fa --- /dev/null +++ b/public/services/csv-request.js @@ -0,0 +1,27 @@ +/* + * Wazuh app - API request service + * 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.service('csvReq', function (genericReq) { + return { + fetch: async (path,id) => { + try { + const output = await genericReq.request('POST','/api/wazuh-api/csv',{ path, id }); + return output.data; + } catch (error) { + return Promise.reject(error); + } + } + } +}); \ No newline at end of file diff --git a/public/templates/manager/manager-osseclog.html b/public/templates/manager/manager-osseclog.html index 8d8ec8a298..6f9371b392 100644 --- a/public/templates/manager/manager-osseclog.html +++ b/public/templates/manager/manager-osseclog.html @@ -18,6 +18,7 @@ + DOWNLOAD CSV diff --git a/server/controllers/wazuh-api.js b/server/controllers/wazuh-api.js index af8e184a39..db0a3e1a2e 100644 --- a/server/controllers/wazuh-api.js +++ b/server/controllers/wazuh-api.js @@ -528,12 +528,12 @@ export default class WazuhApi { if(output && output.body && output.body.data && output.body.data.totalItems) { const fields = Object.keys(output.body.data.items[0]); const data = output.body.data.items; - + const json2csvParser = new Parser({ fields }); const csv = json2csvParser.parse(data); - return res(new Buffer(csv)); + return res({ csv }); } else if (output && output.body && output.body.data && !output.body.data.totalItems) { From 1c9b7ca6ad75f1aab46e8f13f3e992534f64ef84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Thu, 26 Apr 2018 14:47:35 +0200 Subject: [PATCH 03/15] Modularized csv generator in a new class --- public/controllers/csv-generator.js | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 public/controllers/csv-generator.js diff --git a/public/controllers/csv-generator.js b/public/controllers/csv-generator.js new file mode 100644 index 0000000000..681ccb7ff3 --- /dev/null +++ b/public/controllers/csv-generator.js @@ -0,0 +1,34 @@ +/* + * Wazuh app - CSV file generator + * 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 CsvGenerator { + + constructor (dataArray, fileName) { + this.dataArray = dataArray; + this.fileName = fileName; + } + + getLinkElement (linkText) { + return this.linkElement = this.linkElement || $('' + (linkText || '') + '', { + href: 'data:attachment/csv;base64,' + encodeURI(btoa(this.dataArray)), + target: '_blank', + download: this.fileName + }); + } + + download (removeAfterDownload) { + this.getLinkElement().css('display', 'none').appendTo('body'); + this.getLinkElement()[0].click(); + if (removeAfterDownload) { + this.getLinkElement().remove(); + } + } +} \ No newline at end of file From 3f428614e02ea8532b662dbe381ae66a4a1026f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Thu, 26 Apr 2018 14:47:56 +0200 Subject: [PATCH 04/15] Minor refactor to use the recently added class to generate CSV files --- public/controllers/osseclog.js | 42 +++++++++------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/public/controllers/osseclog.js b/public/controllers/osseclog.js index 7984759b4e..d2a4f7edd7 100644 --- a/public/controllers/osseclog.js +++ b/public/controllers/osseclog.js @@ -10,38 +10,12 @@ * Find more information about this on the LICENSE file. */ import * as modules from 'ui/modules' +import CsvGenerator from './csv-generator' const app = modules.get('app/wazuh', []); - // Logs controller -app.controller('managerLogController', function ($scope, $rootScope, Logs, apiReq, errorHandler, csvReq, appState, $window) { - - function CsvGenerator(dataArray, fileName) { - this.dataArray = dataArray; - this.fileName = fileName; - - - this.getLinkElement = function (linkText) { - return this.linkElement = this.linkElement || $('' + (linkText || '') + '', { - href: 'data:attachment/csv;base64,' + encodeURI($window.btoa(this.dataArray)), - target: '_blank', - download: this.fileName - }); - }; - - // call with removeAfterDownload = true if you want the link to be removed after downloading - this.download = function (removeAfterDownload) { - this.getLinkElement().css('display', 'none').appendTo('body'); - this.getLinkElement()[0].click(); - if (removeAfterDownload) { - this.getLinkElement().remove(); - } - }; - } - - - +app.controller('managerLogController', function ($scope, $rootScope, Logs, apiReq, errorHandler, csvReq, appState) { $scope.searchTerm = ''; $scope.loading = true; $scope.logs = Logs; @@ -76,9 +50,15 @@ app.controller('managerLogController', function ($scope, $rootScope, Logs, apiRe } $scope.downloadCsv = async () => { - const output = await csvReq.fetch('/manager/logs',JSON.parse(appState.getCurrentAPI()).id) - let csvGenerator = new CsvGenerator(output.csv, 'my_table.csv'); - csvGenerator.download(true); + try { + const currentApi = JSON.parse(appState.getCurrentAPI()).id; + const output = await csvReq.fetch('/manager/logs',currentApi); + const csvGenerator = new CsvGenerator(output.csv, 'my_table.csv'); + csvGenerator.download(true); + } catch (error) { + errorHandler.handle(error,'Download CSV'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } } const initialize = async () => { From 8d89d820e6e21fbbcb8c58d738e9557ff4563878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 11:18:21 +0200 Subject: [PATCH 05/15] Added csv service to osseclogs, rules, decoders --- public/controllers/osseclog.js | 2 +- public/controllers/ruleset.js | 28 +++++++++++++++++-- .../templates/manager/manager-osseclog.html | 6 +++- .../manager/ruleset/ruleset-decoders.html | 4 +++ .../manager/ruleset/ruleset-rules.html | 4 +++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/public/controllers/osseclog.js b/public/controllers/osseclog.js index d2a4f7edd7..0aa38e4336 100644 --- a/public/controllers/osseclog.js +++ b/public/controllers/osseclog.js @@ -53,7 +53,7 @@ app.controller('managerLogController', function ($scope, $rootScope, Logs, apiRe try { const currentApi = JSON.parse(appState.getCurrentAPI()).id; const output = await csvReq.fetch('/manager/logs',currentApi); - const csvGenerator = new CsvGenerator(output.csv, 'my_table.csv'); + const csvGenerator = new CsvGenerator(output.csv, 'logs.csv'); csvGenerator.download(true); } catch (error) { errorHandler.handle(error,'Download CSV'); diff --git a/public/controllers/ruleset.js b/public/controllers/ruleset.js index c7bb58aaca..e575600d04 100644 --- a/public/controllers/ruleset.js +++ b/public/controllers/ruleset.js @@ -10,10 +10,11 @@ * Find more information about this on the LICENSE file. */ import * as modules from 'ui/modules' +import CsvGenerator from './csv-generator' const app = modules.get('app/wazuh', []); -app.controller('rulesController', function ($scope, $rootScope, Rules, RulesAutoComplete, errorHandler, genericReq, appState) { +app.controller('rulesController', function ($scope, $rootScope, Rules, RulesAutoComplete, errorHandler, genericReq, csvReq, appState) { $scope.setRulesTab = tab => $rootScope.globalsubmenuNavItem2 = tab; @@ -63,6 +64,17 @@ app.controller('rulesController', function ($scope, $rootScope, Rules, RulesAuto } }; + $scope.downloadCsv = async () => { + try { + const currentApi = JSON.parse(appState.getCurrentAPI()).id; + const output = await csvReq.fetch('/rules',currentApi); + const csvGenerator = new CsvGenerator(output.csv, 'rules.csv'); + csvGenerator.download(true); + } catch (error) { + errorHandler.handle(error,'Download CSV'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } + } const load = async () => { try { @@ -116,7 +128,7 @@ app.controller('rulesController', function ($scope, $rootScope, Rules, RulesAuto }); }); -app.controller('decodersController', function ($scope, $rootScope, Decoders, DecodersAutoComplete, errorHandler, genericReq, appState) { +app.controller('decodersController', function ($scope, $rootScope, Decoders, DecodersAutoComplete, errorHandler, genericReq, appState, csvReq) { $scope.setRulesTab = tab => $rootScope.globalsubmenuNavItem2 = tab; //Initialization @@ -172,6 +184,18 @@ app.controller('decodersController', function ($scope, $rootScope, Decoders, Dec } } + $scope.downloadCsv = async () => { + try { + const currentApi = JSON.parse(appState.getCurrentAPI()).id; + const output = await csvReq.fetch('/decoders',currentApi); + const csvGenerator = new CsvGenerator(output.csv, 'decoders.csv'); + csvGenerator.download(true); + } catch (error) { + errorHandler.handle(error,'Download CSV'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } + } + const load = async () => { try { $rootScope.rawVisualizations = null; diff --git a/public/templates/manager/manager-osseclog.html b/public/templates/manager/manager-osseclog.html index 6f9371b392..b3b10ae48a 100644 --- a/public/templates/manager/manager-osseclog.html +++ b/public/templates/manager/manager-osseclog.html @@ -18,7 +18,7 @@ - DOWNLOAD CSV + @@ -84,5 +84,9 @@ nopointer="true" noheight="true"> +
+ + Formatted +
diff --git a/public/templates/manager/ruleset/ruleset-decoders.html b/public/templates/manager/ruleset/ruleset-decoders.html index 0e2dd611d0..ada3f7ceab 100644 --- a/public/templates/manager/ruleset/ruleset-decoders.html +++ b/public/templates/manager/ruleset/ruleset-decoders.html @@ -97,5 +97,9 @@ isdecoders="true" class="no-lateral-padding"> +
+ + Formatted +
diff --git a/public/templates/manager/ruleset/ruleset-rules.html b/public/templates/manager/ruleset/ruleset-rules.html index 085a225fc9..26f72429d5 100644 --- a/public/templates/manager/ruleset/ruleset-rules.html +++ b/public/templates/manager/ruleset/ruleset-rules.html @@ -140,5 +140,9 @@ isruleset="true" class="no-lateral-padding"> +
+ + Formatted +
From 784f87a0675548bc0d3f82c579aeeb08a1220be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 11:29:26 +0200 Subject: [PATCH 06/15] Applied csv service to rules and decoders --- public/templates/manager/ruleset/decoders/decoders-list.html | 4 ++++ public/templates/manager/ruleset/rules/rules-list.html | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/public/templates/manager/ruleset/decoders/decoders-list.html b/public/templates/manager/ruleset/decoders/decoders-list.html index 7f2aa64529..a9118e7306 100644 --- a/public/templates/manager/ruleset/decoders/decoders-list.html +++ b/public/templates/manager/ruleset/decoders/decoders-list.html @@ -83,4 +83,8 @@ isdecoders="true" class="no-lateral-padding"> +
+ + Formatted +
diff --git a/public/templates/manager/ruleset/rules/rules-list.html b/public/templates/manager/ruleset/rules/rules-list.html index ee78c55b48..d99ba162b0 100644 --- a/public/templates/manager/ruleset/rules/rules-list.html +++ b/public/templates/manager/ruleset/rules/rules-list.html @@ -103,4 +103,8 @@ isdecoders="false" class="no-lateral-padding"> +
+ + Formatted +
From 6177888937c1210b6583baf31338003909e1c117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:16:30 +0200 Subject: [PATCH 07/15] Added csv report to agents list --- public/controllers/agents-preview.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/public/controllers/agents-preview.js b/public/controllers/agents-preview.js index f7f39c28bd..e4c1d36cf6 100644 --- a/public/controllers/agents-preview.js +++ b/public/controllers/agents-preview.js @@ -10,10 +10,11 @@ * Find more information about this on the LICENSE file. */ import * as modules from 'ui/modules' +import CsvGenerator from './csv-generator' const app = modules.get('app/wazuh', []); -app.controller('agentsPreviewController', function ($scope, $rootScope, $routeParams, genericReq, apiReq, appState, Agents, $location, errorHandler) { +app.controller('agentsPreviewController', function ($scope, $rootScope, $routeParams, genericReq, apiReq, appState, Agents, $location, errorHandler, csvReq) { $scope.loading = true; $scope.agents = Agents; $scope.status = 'all'; @@ -80,6 +81,18 @@ app.controller('agentsPreviewController', function ($scope, $rootScope, $routePa } } + $scope.downloadCsv = async () => { + try { + const currentApi = JSON.parse(appState.getCurrentAPI()).id; + const output = await csvReq.fetch('/agents', currentApi, $scope.agents ? $scope.agents.filters : null); + const csvGenerator = new CsvGenerator(output.csv, 'agents.csv'); + csvGenerator.download(true); + } catch (error) { + errorHandler.handle(error,'Download CSV'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } + } + const load = async () => { try{ const data = await Promise.all([ From a08705e18ac78007ec20b9b23db457ec41d18378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:17:01 +0200 Subject: [PATCH 08/15] Added csv report to groups controller --- public/controllers/groups.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/public/controllers/groups.js b/public/controllers/groups.js index bb6545f9e4..1c34641d9f 100644 --- a/public/controllers/groups.js +++ b/public/controllers/groups.js @@ -11,12 +11,13 @@ */ import beautifier from 'plugins/wazuh/utils/json-beautifier'; import * as modules from 'ui/modules' +import CsvGenerator from './csv-generator' const app = modules.get('app/wazuh', []); // Groups preview controller app.controller('groupsPreviewController', -function ($scope, $rootScope, $location, apiReq, Groups, GroupFiles, GroupAgents, errorHandler) { +function ($scope, $rootScope, $location, apiReq, Groups, GroupFiles, GroupAgents, errorHandler, csvReq, appState) { const reloadWatcher = $rootScope.$watch('groupsIsReloaded',() => { delete $rootScope.groupsIsReloaded; $scope.lookingGroup = false; @@ -31,6 +32,19 @@ function ($scope, $rootScope, $location, apiReq, Groups, GroupFiles, GroupAgents $scope.groupAgents = GroupAgents; $scope.groupFiles = GroupFiles; + $scope.downloadCsv = async dataProvider => { + try { + const path = $scope[dataProvider] ? $scope[dataProvider].path : null; + const currentApi = JSON.parse(appState.getCurrentAPI()).id; + const output = await csvReq.fetch(path, currentApi, $scope[dataProvider] ? $scope[dataProvider].filters : null); + const csvGenerator = new CsvGenerator(output.csv, 'groups.csv'); + csvGenerator.download(true); + } catch (error) { + errorHandler.handle(error,'Download CSV'); + if(!$rootScope.$$phase) $rootScope.$digest(); + } + } + // Store a boolean variable to check if come from agents const fromAgents = ('comeFrom' in $rootScope) && ('globalAgent' in $rootScope) && $rootScope.comeFrom === 'agents'; From 06d146cd7dc8f23cd479cffa4710315528927378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:18:40 +0200 Subject: [PATCH 09/15] Added filters to osseclogs csv report --- public/controllers/osseclog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/controllers/osseclog.js b/public/controllers/osseclog.js index 0aa38e4336..c83f83f854 100644 --- a/public/controllers/osseclog.js +++ b/public/controllers/osseclog.js @@ -52,7 +52,7 @@ app.controller('managerLogController', function ($scope, $rootScope, Logs, apiRe $scope.downloadCsv = async () => { try { const currentApi = JSON.parse(appState.getCurrentAPI()).id; - const output = await csvReq.fetch('/manager/logs',currentApi); + const output = await csvReq.fetch('/manager/logs', currentApi, $scope.logs ? $scope.logs.filters : null); const csvGenerator = new CsvGenerator(output.csv, 'logs.csv'); csvGenerator.download(true); } catch (error) { From 1d69a1227566a9d192220c6d6e06c6fc1a7caa9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:18:54 +0200 Subject: [PATCH 10/15] Added filters to ruleset csv reports --- public/controllers/ruleset.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/controllers/ruleset.js b/public/controllers/ruleset.js index ff550520a1..4f4eacb20a 100644 --- a/public/controllers/ruleset.js +++ b/public/controllers/ruleset.js @@ -70,7 +70,7 @@ app.controller('rulesController', function ($scope, $rootScope, Rules, RulesRela $scope.downloadCsv = async () => { try { const currentApi = JSON.parse(appState.getCurrentAPI()).id; - const output = await csvReq.fetch('/rules',currentApi); + const output = await csvReq.fetch('/rules', currentApi, $scope.rules ? $scope.rules.filters : null); const csvGenerator = new CsvGenerator(output.csv, 'rules.csv'); csvGenerator.download(true); } catch (error) { @@ -273,7 +273,7 @@ app.controller('decodersController', function ($scope, $rootScope, $sce, Decoder $scope.downloadCsv = async () => { try { const currentApi = JSON.parse(appState.getCurrentAPI()).id; - const output = await csvReq.fetch('/decoders',currentApi); + const output = await csvReq.fetch('/decoders', currentApi, $scope.decoders ? $scope.decoders.filters : null); const csvGenerator = new CsvGenerator(output.csv, 'decoders.csv'); csvGenerator.download(true); } catch (error) { @@ -281,7 +281,7 @@ app.controller('decodersController', function ($scope, $rootScope, $sce, Decoder if(!$rootScope.$$phase) $rootScope.$digest(); } } - + /** * This function changes to the decoder detail view */ From e05da655ab8ee74f6f3225377d7652f819fb745a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:19:09 +0200 Subject: [PATCH 11/15] Added new optional parameter (filters) --- public/services/csv-request.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/services/csv-request.js b/public/services/csv-request.js index 84055d35fa..43db0c850e 100644 --- a/public/services/csv-request.js +++ b/public/services/csv-request.js @@ -15,9 +15,9 @@ const app = modules.get('app/wazuh', []); app.service('csvReq', function (genericReq) { return { - fetch: async (path,id) => { + fetch: async (path, id, filters = null) => { try { - const output = await genericReq.request('POST','/api/wazuh-api/csv',{ path, id }); + const output = await genericReq.request('POST','/api/wazuh-api/csv',{ path, id, filters }); return output.data; } catch (error) { return Promise.reject(error); From 16e683c67b8c011ccc50052f21a29f7c39c017bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:19:19 +0200 Subject: [PATCH 12/15] Added new use case --- public/services/error-handler.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/services/error-handler.js b/public/services/error-handler.js index da809bd181..df05746c6a 100644 --- a/public/services/error-handler.js +++ b/public/services/error-handler.js @@ -20,6 +20,7 @@ app.service('errorHandler', function ( Notifier, appState, $location) { if(error.data && error.data.errorData && error.data.errorData.message) return error.data.errorData.message; if(error.errorData && error.errorData.message) return error.errorData.message; if(error.data && typeof error.data === 'string') return error.data; + if(error.data && error.data.error && typeof error.data.error === 'string') return error.data.error; if(error.data && error.data.message && typeof error.data.message === 'string') return error.data.message; if(error.data && error.data.message && error.data.message.msg && typeof error.data.message.msg === 'string') return error.data.message.msg; if(error.data && error.data.data && typeof error.data.data === 'string') return error.data.data; @@ -119,7 +120,7 @@ app.service('errorHandler', function ( Notifier, appState, $location) { if(error.extraMessage) text = error.extraMessage; text = location ? location + '. ' + text : text; if(!silent){ - if(isWarning) notify.warning(text); + if(isWarning || (text && typeof text === 'string' && text.toLowerCase().includes('no results'))) notify.warning(text); else notify.error(text); } if(goSettings) $location.path('/settings'); From 43d10cf9e10ce95f8a83b37ee901a26875b0c57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:19:36 +0200 Subject: [PATCH 13/15] Added buttons to generate the csv report --- public/templates/agents-prev/agents-prev.html | 4 +++ .../manager/groups/groups-preview.html | 26 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/public/templates/agents-prev/agents-prev.html b/public/templates/agents-prev/agents-prev.html index b327adc397..75aef324ec 100644 --- a/public/templates/agents-prev/agents-prev.html +++ b/public/templates/agents-prev/agents-prev.html @@ -109,4 +109,8 @@ class="no-lateral-padding" full="'agent'"> +
+ + Formatted +
diff --git a/public/templates/manager/groups/groups-preview.html b/public/templates/manager/groups/groups-preview.html index 3d9ec6486a..9ea4578a3d 100644 --- a/public/templates/manager/groups/groups-preview.html +++ b/public/templates/manager/groups/groups-preview.html @@ -52,9 +52,12 @@ {name:'MD5 agent.conf'} ]"> - - + + +
+ + Formatted +
+ + + +
+ + Formatted +
+ - - - +
+ + Formatted +
+
From 2ec58d435291b7799eff94e43885aafedd9b4727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:19:50 +0200 Subject: [PATCH 14/15] Parse filters and sanitize them --- server/controllers/wazuh-api.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/server/controllers/wazuh-api.js b/server/controllers/wazuh-api.js index 42493945c9..bf0d30eb8f 100644 --- a/server/controllers/wazuh-api.js +++ b/server/controllers/wazuh-api.js @@ -509,6 +509,10 @@ export default class WazuhApi { if(!req.payload || !req.payload.path) throw new Error('Field path is required') if(!req.payload.id) throw new Error('Field id is required') + const filters = req.payload && req.payload.filters && Array.isArray(req.payload.filters) ? + req.payload.filters : + []; + const config = await this.wzWrapper.getWazuhConfigurationById(req.payload.id) let path = req.payload.path; @@ -518,8 +522,17 @@ export default class WazuhApi { } if(!path) throw new Error('An error occurred parsing path field') + + const params = { limit: 99999 }; + + if(filters.length) { + for(const filter of filters) { + if(!filter.name || !filter.value) continue; + params[filter.name] = filter.value; + } + } - const output = await needle('get', `${config.url}:${config.port}/${path}`, { limit:99999 }, { + const output = await needle('get', `${config.url}:${config.port}/${path}`, params, { username : config.user, password : config.password, rejectUnauthorized: !config.insecure From fd1e9e91f6ee473530bfc4a8612ae225349e552d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=C3=81ngel=20Gonz=C3=A1lez?= Date: Mon, 30 Apr 2018 13:30:09 +0200 Subject: [PATCH 15/15] Fix comment from routes --- server/routes/wazuh-api.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/routes/wazuh-api.js b/server/routes/wazuh-api.js index f482840be2..2b9bb81de7 100644 --- a/server/routes/wazuh-api.js +++ b/server/routes/wazuh-api.js @@ -33,14 +33,15 @@ export default (server, options) => { // Write in debug log server.route({ method: 'POST', path: '/api/wazuh/errlog', handler: (req,res) => ctrl.postErrorLog(req,res) }); - // COMMENT HERE + // Force fetch data to be inserted on wazuh-monitoring indices server.route({ method: 'GET', path: '/api/wazuh-api/fetchAgents', handler: (req,res) => ctrl.fetchAgents(req,res) }); - // COMMENT HERE + // Returns the config.yml file parsed server.route({ method: 'GET', path: '/api/wazuh-api/configuration', handler: (req,res) => ctrl.getConfigurationFile(req,res) }); - // COMMENT HERE + // Experimental feature to simulate a login system server.route({ method: 'POST', path: '/api/wazuh-api/wlogin', handler: (req,res) => ctrl.login(req,res) }); + // Returns data from the Wazuh API on CSV readable format server.route({ method: 'POST', path: '/api/wazuh-api/csv', handler: (req,res) => ctrl.csv(req,res)}) };