From ff880d69d82d216b97639ebb91088c7a87b228a4 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:31:47 +0100 Subject: [PATCH 01/40] Added new service for CSV requests --- .../services/csv-request/csvRequestService.js | 43 +++++++++++++++++++ .../appserver/static/js/services/index.js | 1 + 2 files changed, 44 insertions(+) create mode 100644 SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js new file mode 100644 index 000000000..0609c763f --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -0,0 +1,43 @@ +/* +* 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. +*/ +define(['../module'], function (app) { + class CSVRequest { + + /** + * Constructor + * @param {*} $requestService Service to make requests to our server + */ + constructor($requestService) { + this.httpReq = $requestService.httpReq; + } + + /** + * Fetchs data from /api/csv route using the below parameters. + * @param {string} path Wazuh API route + * @param {number|string} id API ID + * @param {*} filters Array of Wazuh API filters. Optional + */ + async fetch(path, id, filters = null) { + try { + const output = await this.httpReq( + 'POST', + '/api/csv', + { path, id, filters } + ) + return output.data + } catch (error) { + return Promise.reject(error) + } + } + } + app.service('$CSVRequestService', CSVRequest ) + }) \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/services/index.js b/SplunkAppForWazuh/appserver/static/js/services/index.js index a3d405110..3368ad23a 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/index.js +++ b/SplunkAppForWazuh/appserver/static/js/services/index.js @@ -12,6 +12,7 @@ define([ './currentDataService/currentDataService', './beautifier/beautifier-json', './notificationService/notificationService', + './csv-request/csvRequestService', './xml-beautifier/xml-beautifier', './get-ids/getIdService', './token-model/urlTokenModelService' From e17e5c8dde31df08e3fa17a8f53fddf933640398 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:50:47 +0100 Subject: [PATCH 02/40] Including third party file-saver library --- .../js/services/file-saver/file-saver.js | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js diff --git a/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js new file mode 100644 index 000000000..24ddf33a4 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js @@ -0,0 +1,198 @@ +/* eslint-disable */ +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.3.8 + * 2018-03-22 14:03:47 + * + * By Eli Grey, https://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */ + +var saveAs = + saveAs || + (function(view) { + 'use strict'; + // IE <10 is explicitly unsupported + if ( + typeof view === 'undefined' || + (typeof navigator !== 'undefined' && + /MSIE [1-9]\./.test(navigator.userAgent)) + ) { + return; + } + var doc = view.document, + // only get URL when necessary in case Blob.js hasn't overridden it yet + get_URL = function() { + return view.URL || view.webkitURL || view; + }, + save_link = doc.createElementNS('http://www.w3.org/1999/xhtml', 'a'), + can_use_save_link = 'download' in save_link, + click = function(node) { + var event = new MouseEvent('click'); + node.dispatchEvent(event); + }, + is_safari = /constructor/i.test(view.HTMLElement) || view.safari, + is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent), + setImmediate = view.setImmediate || view.setTimeout, + throw_outside = function(ex) { + setImmediate(function() { + throw ex; + }, 0); + }, + force_saveable_type = 'application/octet-stream', + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + arbitrary_revoke_timeout = 1000 * 40, // in ms + revoke = function(file) { + var revoker = function() { + if (typeof file === 'string') { + // file is an object URL + get_URL().revokeObjectURL(file); + } else { + // file is a File + file.remove(); + } + }; + setTimeout(revoker, arbitrary_revoke_timeout); + }, + dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver['on' + event_types[i]]; + if (typeof listener === 'function') { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + }, + auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if ( + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test( + blob.type + ) + ) { + return new Blob([String.fromCharCode(0xfeff), blob], { + type: blob.type + }); + } + return blob; + }, + FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var filesaver = this, + type = blob.type, + force = type === force_saveable_type, + object_url, + dispatch_all = function() { + dispatch( + filesaver, + 'writestart progress write writeend'.split(' ') + ); + }, + // on any filesys errors revert to saving with object URLs + fs_error = function() { + if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var url = is_chrome_ios + ? reader.result + : reader.result.replace( + /^data:[^;]*;/, + 'data:attachment/file;' + ); + var popup = view.open(url, '_blank'); + if (!popup) view.location.href = url; + url = undefined; // release reference before dispatching + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (!object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (force) { + view.location.href = object_url; + } else { + var opened = view.open(object_url, '_blank'); + if (!opened) { + // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html + view.location.href = object_url; + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + }; + filesaver.readyState = filesaver.INIT; + + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setImmediate(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }, 0); + return; + } + + fs_error(); + }, + FS_proto = FileSaver.prototype, + saveAs = function(blob, name, no_auto_bom) { + return new FileSaver( + blob, + name || blob.name || 'download', + no_auto_bom + ); + }; + + // IE 10+ (native saveAs) + if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + name = name || blob.name || 'download'; + + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name); + }; + } + + // todo: detect chrome extensions & packaged apps + //save_link.target = "_blank"; + + FS_proto.abort = function() {}; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; + + return saveAs; + })( + (typeof self !== 'undefined' && self) || + (typeof window !== 'undefined' && window) || + this + ); From 8ee13ecf130d82072d33459086c365260b5bc168 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:15 +0100 Subject: [PATCH 03/40] CSV request service --- .../static/js/services/csv-request/csvRequestService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 0609c763f..fc8c141f6 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -11,7 +11,7 @@ */ define(['../module'], function (app) { class CSVRequest { - + /** * Constructor * @param {*} $requestService Service to make requests to our server @@ -39,5 +39,5 @@ define(['../module'], function (app) { } } } - app.service('$CSVRequestService', CSVRequest ) + app.service('$csvRequestService', CSVRequest ) }) \ No newline at end of file From 8b5cce1b03123f42f6346e7113ba08007cb8a4c5 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:40 +0100 Subject: [PATCH 04/40] Added download csv method to agents controller --- .../controllers/agents/agents/agentsCtrl.js | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index f36e08c92..e473332fe 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -13,9 +13,11 @@ define([ '../../module', '../../../services/visualizations/search/search-handler', + '../../../services/file-saver/file-saver' ],function ( app, - SearchHandler + SearchHandler, + FileSaver ){ 'use strict' @@ -32,17 +34,17 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, agentData){ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') - + this.api = $currentDataService.getApi() this.apiReq = $requestService.apiReq this.state = $state this.toast = $notificationService.showSimpleToast this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() - + this.csvReq = $csvRequestService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ @@ -89,6 +91,30 @@ define([ } + /** + * Exports the table in CSV format + * @param {String} data_path + */ + async downloadCsv(data_path) { + try { + this.toast('Your download should begin automatically...') + const currentApi = this.api.id + const output = await this.csvReq.fetch( + data_path, + currentApi, + this.wzTableFilter.get() + ) + const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line + + FileSaver.saveAs(blob, 'packages.csv') + + return + } catch (error) { + this.toast('Error downloading CSV') + } + return + } + /** * Searches by a term * @param {String} term From 06173ba1ee5d5f1b849cc0209c99ba0c0d4b8770 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 13:06:46 +0100 Subject: [PATCH 05/40] Added scope method, also injecting dependencies --- .../static/js/controllers/agents/agents/agents.html | 6 ++++++ .../js/controllers/agents/agents/agentsCtrl.js | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html index e6c6104df..72e5529a9 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html @@ -105,4 +105,10 @@
+
+ \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index e473332fe..83a6387d5 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -34,7 +34,7 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService,$tableFilterService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') @@ -45,6 +45,7 @@ define([ this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() this.csvReq = $csvRequestService + this.wzTableFilter = $tableFilterService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ @@ -84,7 +85,7 @@ define([ this.scope.version = 'all' this.scope.node_name = 'all' this.scope.versionModel = 'all' - + this.scope.downloadCsv = (dataPath) => this.downloadCsv(dataPath) this.scope.$on('$destroy', () => { this.topAgent.destroy() }) @@ -93,14 +94,15 @@ define([ /** * Exports the table in CSV format - * @param {String} data_path + * @param {String} dataPath */ - async downloadCsv(data_path) { + async downloadCsv(dataPath) { try { + console.log('downloading csv...') this.toast('Your download should begin automatically...') const currentApi = this.api.id const output = await this.csvReq.fetch( - data_path, + dataPath, currentApi, this.wzTableFilter.get() ) @@ -110,6 +112,7 @@ define([ return } catch (error) { + console.error('error ',error) this.toast('Error downloading CSV') } return From f880b3b84f0587bb8cd6ef6946ef0c4f8b8de46b Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:31:47 +0100 Subject: [PATCH 06/40] Added new service for CSV requests --- .../services/csv-request/csvRequestService.js | 43 +++++++++++++++++++ .../appserver/static/js/services/index.js | 1 + 2 files changed, 44 insertions(+) create mode 100644 SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js new file mode 100644 index 000000000..0609c763f --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -0,0 +1,43 @@ +/* +* 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. +*/ +define(['../module'], function (app) { + class CSVRequest { + + /** + * Constructor + * @param {*} $requestService Service to make requests to our server + */ + constructor($requestService) { + this.httpReq = $requestService.httpReq; + } + + /** + * Fetchs data from /api/csv route using the below parameters. + * @param {string} path Wazuh API route + * @param {number|string} id API ID + * @param {*} filters Array of Wazuh API filters. Optional + */ + async fetch(path, id, filters = null) { + try { + const output = await this.httpReq( + 'POST', + '/api/csv', + { path, id, filters } + ) + return output.data + } catch (error) { + return Promise.reject(error) + } + } + } + app.service('$CSVRequestService', CSVRequest ) + }) \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/services/index.js b/SplunkAppForWazuh/appserver/static/js/services/index.js index a3d405110..3368ad23a 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/index.js +++ b/SplunkAppForWazuh/appserver/static/js/services/index.js @@ -12,6 +12,7 @@ define([ './currentDataService/currentDataService', './beautifier/beautifier-json', './notificationService/notificationService', + './csv-request/csvRequestService', './xml-beautifier/xml-beautifier', './get-ids/getIdService', './token-model/urlTokenModelService' From d09b1d586715f89474e370a49434af57bf8b2102 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:50:47 +0100 Subject: [PATCH 07/40] Including third party file-saver library --- .../js/services/file-saver/file-saver.js | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js diff --git a/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js new file mode 100644 index 000000000..24ddf33a4 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js @@ -0,0 +1,198 @@ +/* eslint-disable */ +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.3.8 + * 2018-03-22 14:03:47 + * + * By Eli Grey, https://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */ + +var saveAs = + saveAs || + (function(view) { + 'use strict'; + // IE <10 is explicitly unsupported + if ( + typeof view === 'undefined' || + (typeof navigator !== 'undefined' && + /MSIE [1-9]\./.test(navigator.userAgent)) + ) { + return; + } + var doc = view.document, + // only get URL when necessary in case Blob.js hasn't overridden it yet + get_URL = function() { + return view.URL || view.webkitURL || view; + }, + save_link = doc.createElementNS('http://www.w3.org/1999/xhtml', 'a'), + can_use_save_link = 'download' in save_link, + click = function(node) { + var event = new MouseEvent('click'); + node.dispatchEvent(event); + }, + is_safari = /constructor/i.test(view.HTMLElement) || view.safari, + is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent), + setImmediate = view.setImmediate || view.setTimeout, + throw_outside = function(ex) { + setImmediate(function() { + throw ex; + }, 0); + }, + force_saveable_type = 'application/octet-stream', + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + arbitrary_revoke_timeout = 1000 * 40, // in ms + revoke = function(file) { + var revoker = function() { + if (typeof file === 'string') { + // file is an object URL + get_URL().revokeObjectURL(file); + } else { + // file is a File + file.remove(); + } + }; + setTimeout(revoker, arbitrary_revoke_timeout); + }, + dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver['on' + event_types[i]]; + if (typeof listener === 'function') { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + }, + auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if ( + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test( + blob.type + ) + ) { + return new Blob([String.fromCharCode(0xfeff), blob], { + type: blob.type + }); + } + return blob; + }, + FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var filesaver = this, + type = blob.type, + force = type === force_saveable_type, + object_url, + dispatch_all = function() { + dispatch( + filesaver, + 'writestart progress write writeend'.split(' ') + ); + }, + // on any filesys errors revert to saving with object URLs + fs_error = function() { + if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var url = is_chrome_ios + ? reader.result + : reader.result.replace( + /^data:[^;]*;/, + 'data:attachment/file;' + ); + var popup = view.open(url, '_blank'); + if (!popup) view.location.href = url; + url = undefined; // release reference before dispatching + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (!object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (force) { + view.location.href = object_url; + } else { + var opened = view.open(object_url, '_blank'); + if (!opened) { + // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html + view.location.href = object_url; + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + }; + filesaver.readyState = filesaver.INIT; + + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setImmediate(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }, 0); + return; + } + + fs_error(); + }, + FS_proto = FileSaver.prototype, + saveAs = function(blob, name, no_auto_bom) { + return new FileSaver( + blob, + name || blob.name || 'download', + no_auto_bom + ); + }; + + // IE 10+ (native saveAs) + if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + name = name || blob.name || 'download'; + + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name); + }; + } + + // todo: detect chrome extensions & packaged apps + //save_link.target = "_blank"; + + FS_proto.abort = function() {}; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; + + return saveAs; + })( + (typeof self !== 'undefined' && self) || + (typeof window !== 'undefined' && window) || + this + ); From 1af8675a508ef5eefb143805aa80a3df90d70e99 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:15 +0100 Subject: [PATCH 08/40] CSV request service --- .../static/js/services/csv-request/csvRequestService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 0609c763f..fc8c141f6 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -11,7 +11,7 @@ */ define(['../module'], function (app) { class CSVRequest { - + /** * Constructor * @param {*} $requestService Service to make requests to our server @@ -39,5 +39,5 @@ define(['../module'], function (app) { } } } - app.service('$CSVRequestService', CSVRequest ) + app.service('$csvRequestService', CSVRequest ) }) \ No newline at end of file From f2a4ffa16303494fd5906515f40d872ff4d957a4 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:40 +0100 Subject: [PATCH 09/40] Added download csv method to agents controller --- .../controllers/agents/agents/agentsCtrl.js | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index f36e08c92..e473332fe 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -13,9 +13,11 @@ define([ '../../module', '../../../services/visualizations/search/search-handler', + '../../../services/file-saver/file-saver' ],function ( app, - SearchHandler + SearchHandler, + FileSaver ){ 'use strict' @@ -32,17 +34,17 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, agentData){ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') - + this.api = $currentDataService.getApi() this.apiReq = $requestService.apiReq this.state = $state this.toast = $notificationService.showSimpleToast this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() - + this.csvReq = $csvRequestService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ @@ -89,6 +91,30 @@ define([ } + /** + * Exports the table in CSV format + * @param {String} data_path + */ + async downloadCsv(data_path) { + try { + this.toast('Your download should begin automatically...') + const currentApi = this.api.id + const output = await this.csvReq.fetch( + data_path, + currentApi, + this.wzTableFilter.get() + ) + const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line + + FileSaver.saveAs(blob, 'packages.csv') + + return + } catch (error) { + this.toast('Error downloading CSV') + } + return + } + /** * Searches by a term * @param {String} term From f32f217b08acdcb051f412992e6916ed91ccbc51 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 13:06:46 +0100 Subject: [PATCH 10/40] Added scope method, also injecting dependencies --- .../static/js/controllers/agents/agents/agents.html | 6 ++++++ .../js/controllers/agents/agents/agentsCtrl.js | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html index e6c6104df..72e5529a9 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html @@ -105,4 +105,10 @@
+
+ \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index e473332fe..83a6387d5 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -34,7 +34,7 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService,$tableFilterService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') @@ -45,6 +45,7 @@ define([ this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() this.csvReq = $csvRequestService + this.wzTableFilter = $tableFilterService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ @@ -84,7 +85,7 @@ define([ this.scope.version = 'all' this.scope.node_name = 'all' this.scope.versionModel = 'all' - + this.scope.downloadCsv = (dataPath) => this.downloadCsv(dataPath) this.scope.$on('$destroy', () => { this.topAgent.destroy() }) @@ -93,14 +94,15 @@ define([ /** * Exports the table in CSV format - * @param {String} data_path + * @param {String} dataPath */ - async downloadCsv(data_path) { + async downloadCsv(dataPath) { try { + console.log('downloading csv...') this.toast('Your download should begin automatically...') const currentApi = this.api.id const output = await this.csvReq.fetch( - data_path, + dataPath, currentApi, this.wzTableFilter.get() ) @@ -110,6 +112,7 @@ define([ return } catch (error) { + console.error('error ',error) this.toast('Error downloading CSV') } return From 97a778067896a34f1ecfd6e974ec8bbc7a36908f Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:31:47 +0100 Subject: [PATCH 11/40] Added new service for CSV requests --- .../services/csv-request/csvRequestService.js | 43 +++++++++++++++++++ .../appserver/static/js/services/index.js | 1 + 2 files changed, 44 insertions(+) create mode 100644 SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js new file mode 100644 index 000000000..0609c763f --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -0,0 +1,43 @@ +/* +* 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. +*/ +define(['../module'], function (app) { + class CSVRequest { + + /** + * Constructor + * @param {*} $requestService Service to make requests to our server + */ + constructor($requestService) { + this.httpReq = $requestService.httpReq; + } + + /** + * Fetchs data from /api/csv route using the below parameters. + * @param {string} path Wazuh API route + * @param {number|string} id API ID + * @param {*} filters Array of Wazuh API filters. Optional + */ + async fetch(path, id, filters = null) { + try { + const output = await this.httpReq( + 'POST', + '/api/csv', + { path, id, filters } + ) + return output.data + } catch (error) { + return Promise.reject(error) + } + } + } + app.service('$CSVRequestService', CSVRequest ) + }) \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/services/index.js b/SplunkAppForWazuh/appserver/static/js/services/index.js index a3d405110..3368ad23a 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/index.js +++ b/SplunkAppForWazuh/appserver/static/js/services/index.js @@ -12,6 +12,7 @@ define([ './currentDataService/currentDataService', './beautifier/beautifier-json', './notificationService/notificationService', + './csv-request/csvRequestService', './xml-beautifier/xml-beautifier', './get-ids/getIdService', './token-model/urlTokenModelService' From 580a2250a26114f151728614dbf8d1059f10de7b Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:50:47 +0100 Subject: [PATCH 12/40] Including third party file-saver library --- .../js/services/file-saver/file-saver.js | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js diff --git a/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js new file mode 100644 index 000000000..24ddf33a4 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js @@ -0,0 +1,198 @@ +/* eslint-disable */ +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.3.8 + * 2018-03-22 14:03:47 + * + * By Eli Grey, https://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */ + +var saveAs = + saveAs || + (function(view) { + 'use strict'; + // IE <10 is explicitly unsupported + if ( + typeof view === 'undefined' || + (typeof navigator !== 'undefined' && + /MSIE [1-9]\./.test(navigator.userAgent)) + ) { + return; + } + var doc = view.document, + // only get URL when necessary in case Blob.js hasn't overridden it yet + get_URL = function() { + return view.URL || view.webkitURL || view; + }, + save_link = doc.createElementNS('http://www.w3.org/1999/xhtml', 'a'), + can_use_save_link = 'download' in save_link, + click = function(node) { + var event = new MouseEvent('click'); + node.dispatchEvent(event); + }, + is_safari = /constructor/i.test(view.HTMLElement) || view.safari, + is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent), + setImmediate = view.setImmediate || view.setTimeout, + throw_outside = function(ex) { + setImmediate(function() { + throw ex; + }, 0); + }, + force_saveable_type = 'application/octet-stream', + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + arbitrary_revoke_timeout = 1000 * 40, // in ms + revoke = function(file) { + var revoker = function() { + if (typeof file === 'string') { + // file is an object URL + get_URL().revokeObjectURL(file); + } else { + // file is a File + file.remove(); + } + }; + setTimeout(revoker, arbitrary_revoke_timeout); + }, + dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver['on' + event_types[i]]; + if (typeof listener === 'function') { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + }, + auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if ( + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test( + blob.type + ) + ) { + return new Blob([String.fromCharCode(0xfeff), blob], { + type: blob.type + }); + } + return blob; + }, + FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var filesaver = this, + type = blob.type, + force = type === force_saveable_type, + object_url, + dispatch_all = function() { + dispatch( + filesaver, + 'writestart progress write writeend'.split(' ') + ); + }, + // on any filesys errors revert to saving with object URLs + fs_error = function() { + if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var url = is_chrome_ios + ? reader.result + : reader.result.replace( + /^data:[^;]*;/, + 'data:attachment/file;' + ); + var popup = view.open(url, '_blank'); + if (!popup) view.location.href = url; + url = undefined; // release reference before dispatching + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (!object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (force) { + view.location.href = object_url; + } else { + var opened = view.open(object_url, '_blank'); + if (!opened) { + // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html + view.location.href = object_url; + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + }; + filesaver.readyState = filesaver.INIT; + + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setImmediate(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }, 0); + return; + } + + fs_error(); + }, + FS_proto = FileSaver.prototype, + saveAs = function(blob, name, no_auto_bom) { + return new FileSaver( + blob, + name || blob.name || 'download', + no_auto_bom + ); + }; + + // IE 10+ (native saveAs) + if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + name = name || blob.name || 'download'; + + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name); + }; + } + + // todo: detect chrome extensions & packaged apps + //save_link.target = "_blank"; + + FS_proto.abort = function() {}; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; + + return saveAs; + })( + (typeof self !== 'undefined' && self) || + (typeof window !== 'undefined' && window) || + this + ); From ba9a17434566cb3da1a9248e208d6abd5a03875c Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:15 +0100 Subject: [PATCH 13/40] CSV request service --- .../static/js/services/csv-request/csvRequestService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 0609c763f..fc8c141f6 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -11,7 +11,7 @@ */ define(['../module'], function (app) { class CSVRequest { - + /** * Constructor * @param {*} $requestService Service to make requests to our server @@ -39,5 +39,5 @@ define(['../module'], function (app) { } } } - app.service('$CSVRequestService', CSVRequest ) + app.service('$csvRequestService', CSVRequest ) }) \ No newline at end of file From a18698b19be2c224fb11d90de0517cc66b7299d6 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:40 +0100 Subject: [PATCH 14/40] Added download csv method to agents controller --- .../controllers/agents/agents/agentsCtrl.js | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index f36e08c92..e473332fe 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -13,9 +13,11 @@ define([ '../../module', '../../../services/visualizations/search/search-handler', + '../../../services/file-saver/file-saver' ],function ( app, - SearchHandler + SearchHandler, + FileSaver ){ 'use strict' @@ -32,17 +34,17 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, agentData){ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') - + this.api = $currentDataService.getApi() this.apiReq = $requestService.apiReq this.state = $state this.toast = $notificationService.showSimpleToast this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() - + this.csvReq = $csvRequestService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ @@ -89,6 +91,30 @@ define([ } + /** + * Exports the table in CSV format + * @param {String} data_path + */ + async downloadCsv(data_path) { + try { + this.toast('Your download should begin automatically...') + const currentApi = this.api.id + const output = await this.csvReq.fetch( + data_path, + currentApi, + this.wzTableFilter.get() + ) + const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line + + FileSaver.saveAs(blob, 'packages.csv') + + return + } catch (error) { + this.toast('Error downloading CSV') + } + return + } + /** * Searches by a term * @param {String} term From 75474b8a562e2024f9ceede11c5ede7cdd8d413e Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 13:06:46 +0100 Subject: [PATCH 15/40] Added scope method, also injecting dependencies --- .../static/js/controllers/agents/agents/agents.html | 6 ++++++ .../js/controllers/agents/agents/agentsCtrl.js | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html index e6c6104df..72e5529a9 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agents.html @@ -105,4 +105,10 @@
+
+ \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index e473332fe..83a6387d5 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -34,7 +34,7 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService,$tableFilterService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') @@ -45,6 +45,7 @@ define([ this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() this.csvReq = $csvRequestService + this.wzTableFilter = $tableFilterService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ @@ -84,7 +85,7 @@ define([ this.scope.version = 'all' this.scope.node_name = 'all' this.scope.versionModel = 'all' - + this.scope.downloadCsv = (dataPath) => this.downloadCsv(dataPath) this.scope.$on('$destroy', () => { this.topAgent.destroy() }) @@ -93,14 +94,15 @@ define([ /** * Exports the table in CSV format - * @param {String} data_path + * @param {String} dataPath */ - async downloadCsv(data_path) { + async downloadCsv(dataPath) { try { + console.log('downloading csv...') this.toast('Your download should begin automatically...') const currentApi = this.api.id const output = await this.csvReq.fetch( - data_path, + dataPath, currentApi, this.wzTableFilter.get() ) @@ -110,6 +112,7 @@ define([ return } catch (error) { + console.error('error ',error) this.toast('Error downloading CSV') } return From 18b89d76e07624e9644776a7a8206c32afcb1b4f Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 15:01:51 +0100 Subject: [PATCH 16/40] csv request service back --- .../static/js/services/csv-request/csvRequestService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index fc8c141f6..a81024995 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -11,7 +11,7 @@ */ define(['../module'], function (app) { class CSVRequest { - + /** * Constructor * @param {*} $requestService Service to make requests to our server From c5ec59fd79651f37545502bc59cfa23085f90a8e Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 12:51:15 +0100 Subject: [PATCH 17/40] CSV request service --- .../static/js/services/csv-request/csvRequestService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index a81024995..fc8c141f6 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -11,7 +11,7 @@ */ define(['../module'], function (app) { class CSVRequest { - + /** * Constructor * @param {*} $requestService Service to make requests to our server From 1ef296cdcd84c30dca08fda635d1f6c30f4fa798 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 15:03:44 +0100 Subject: [PATCH 18/40] Fixed conflicts --- .../static/js/controllers/agents/agents/agentsCtrl.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index 83a6387d5..1aaf5c176 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -34,7 +34,11 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ +<<<<<<< HEAD constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService,$tableFilterService, agentData){ +======= + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ +>>>>>>> Added download csv method to agents controller this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') @@ -45,7 +49,10 @@ define([ this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() this.csvReq = $csvRequestService +<<<<<<< HEAD this.wzTableFilter = $tableFilterService +======= +>>>>>>> Added download csv method to agents controller const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ From b47a399a402c8c0c56eebc2f0424e2ef62a9239b Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 15:05:15 +0100 Subject: [PATCH 19/40] Fixed agent class --- .../static/js/controllers/agents/agents/agentsCtrl.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index 1aaf5c176..32e955bf3 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -34,11 +34,8 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ -<<<<<<< HEAD + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService,$tableFilterService, agentData){ -======= - constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService, agentData){ ->>>>>>> Added download csv method to agents controller this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() this.submittedTokenModel.set('activeAgentToken', '-') @@ -49,10 +46,9 @@ define([ this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() this.csvReq = $csvRequestService -<<<<<<< HEAD + + this.wzTableFilter = $tableFilterService this.wzTableFilter = $tableFilterService -======= ->>>>>>> Added download csv method to agents controller const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) const [ From f7b2532b651b8cc1e8b11235c61ec831dc57395e Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 17:23:44 +0100 Subject: [PATCH 20/40] Added csv backend route --- .../appserver/controllers/api.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 4e18f74fb..8e2d4a0bb 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -61,3 +61,35 @@ def request(self, **kwargs): self.logger.error("Error making API request: %s" % (e)) return json.dumps({'error': str(e)}) return result + + + @expose_page(must_login=False, methods=['POST']) + def csv(self, **kwargs): + try: + if 'payload[id]' not in kwargs or 'payload[path]' not in kwargs: + #missing_params = diff_keys_dic_update_api(kwargs) + raise Exception("Invalid arguments, missing params. Already got these params : %s" % str(kwargs)) + filters = {} + if 'payload[filters]' in kwargs: + filters = kwargs['payload[filters]'] + the_id = kwargs['payload[id]'] + api = self.db.get(the_id) + opt_username = api[0]["userapi"] + opt_password = api[0]["passapi"] + opt_base_url = api[0]["url"] + opt_base_port = api[0]["portapi"] + opt_endpoint = kwargs['payload[path]'] + del kwargs['id'] + del kwargs['endpoint'] + url = opt_base_url + ":" + opt_base_port + auth = requests.auth.HTTPBasicAuth(opt_username, opt_password) + verify = False + request = self.session.get( + url + opt_endpoint, params=filters, auth=auth, verify=verify).json() + result = json.dumps(request) + self.logger.info('CSV Params: %s' % str(kwargs)) + parsed_data = json.dumps(request) + except Exception as e: + self.logger.error("Error in CSV generation: %s" % (e)) + return json.dumps({"error":str(e)}) + return parsed_data \ No newline at end of file From a225184a2b06268259aa512a10bcba72ac95f220 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 17:24:15 +0100 Subject: [PATCH 21/40] Added filesaver browser module and loading it at start --- .../static/js/libs/file-saver/file-saver.js | 189 +++++++++++++++++ SplunkAppForWazuh/appserver/static/js/main.js | 2 +- .../js/services/file-saver/file-saver.js | 198 ------------------ 3 files changed, 190 insertions(+), 199 deletions(-) create mode 100644 SplunkAppForWazuh/appserver/static/js/libs/file-saver/file-saver.js delete mode 100644 SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js diff --git a/SplunkAppForWazuh/appserver/static/js/libs/file-saver/file-saver.js b/SplunkAppForWazuh/appserver/static/js/libs/file-saver/file-saver.js new file mode 100644 index 000000000..2983ae6d1 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/libs/file-saver/file-saver.js @@ -0,0 +1,189 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define([], factory); + } else if (typeof exports !== "undefined") { + factory(); + } else { + var mod = { + exports: {} + }; + factory(); + global.FileSaver = mod.exports; + } +})(this, function () { + "use strict"; + + /* + * FileSaver.js + * A saveAs() FileSaver implementation. + * + * By Eli Grey, http://eligrey.com + * + * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) + * source : http://purl.eligrey.com/github/FileSaver.js + */ + // The one and only way of getting global scope in all environments + // https://stackoverflow.com/q/3277182/1008999 + var _global = function () { + // some use content security policy to disable eval + try { + return Function('return this')() || (42, eval)('this'); + } catch (e) { + // every global should have circular reference + // used for checking if someone writes var window = {}; var self = {} + return typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : this; + } + }(); + + function bom(blob, opts) { + if (typeof opts === 'undefined') opts = { + autoBom: false + };else if (typeof opts !== 'object') { + console.warn('Depricated: Expected third argument to be a object'); + opts = { + autoBom: !opts + }; + } // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + + if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xFEFF), blob], { + type: blob.type + }); + } + + return blob; + } + + function download(url, name, opts) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + + xhr.onerror = function () { + console.error('could not download file'); + }; + + xhr.send(); + } + + function corsEnabled(url) { + var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker + + xhr.open('HEAD', url, false); + xhr.send(); + return xhr.status >= 200 && xhr.status <= 299; + } // `a.click()` doesn't work for all browsers (#465) + + + function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } catch (e) { + var evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } + } + + var saveAs = _global.saveAs || // probably in some web worker + typeof window !== 'object' || window !== _global ? function saveAs() {} + /* noop */ + // Use download attribute first if possible (#193 Lumia mobile) + : 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) { + var URL = _global.URL || _global.webkitURL; + var a = document.createElement('a'); + name = name || blob.name || 'download'; + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + + if (a.origin !== location.origin) { + corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank'); + } else { + click(a); + } + } else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4E4); // 40s + + setTimeout(function () { + click(a); + }, 0); + } + } // Use msSaveOrOpenBlob as a second approach + : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) { + name = name || blob.name || 'download'; + + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } else { + var a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } else { + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } + } // Fallback to using FileReader and a popup + : function saveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only avalible on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + + if (typeof blob === 'string') return download(blob, name, opts); + var force = blob.type === 'application/octet-stream'; + + var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; + + var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + + if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + + reader.onloadend = function () { + var url = reader.result; + url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) popup.location.href = url;else location = url; + popup = null; // reverse-tabnabbing #460 + }; + + reader.readAsDataURL(blob); + } else { + var URL = _global.URL || _global.webkitURL; + var url = URL.createObjectURL(blob); + if (popup) popup.location = url;else location.href = url; + popup = null; // reverse-tabnabbing #460 + + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4E4); // 40s + } + }; + _global.saveAs = saveAs.saveAs = saveAs; + + if (typeof module !== 'undefined') { + module.exports = saveAs; + } +}); \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/main.js b/SplunkAppForWazuh/appserver/static/js/main.js index 6b07952b7..a812ce05c 100644 --- a/SplunkAppForWazuh/appserver/static/js/main.js +++ b/SplunkAppForWazuh/appserver/static/js/main.js @@ -22,7 +22,7 @@ require.config({ 'jsonLint': 'js/utils/codemirror/json-lint', 'es6': 'js/libs/es6', 'babel': 'js/libs/babel', - + 'FileSaver' : 'js/libs/file-saver/file-saver' }, config: { diff --git a/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js b/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js deleted file mode 100644 index 24ddf33a4..000000000 --- a/SplunkAppForWazuh/appserver/static/js/services/file-saver/file-saver.js +++ /dev/null @@ -1,198 +0,0 @@ -/* eslint-disable */ -/* FileSaver.js - * A saveAs() FileSaver implementation. - * 1.3.8 - * 2018-03-22 14:03:47 - * - * By Eli Grey, https://eligrey.com - * License: MIT - * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md - */ - -/*global self */ -/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ - -/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */ - -var saveAs = - saveAs || - (function(view) { - 'use strict'; - // IE <10 is explicitly unsupported - if ( - typeof view === 'undefined' || - (typeof navigator !== 'undefined' && - /MSIE [1-9]\./.test(navigator.userAgent)) - ) { - return; - } - var doc = view.document, - // only get URL when necessary in case Blob.js hasn't overridden it yet - get_URL = function() { - return view.URL || view.webkitURL || view; - }, - save_link = doc.createElementNS('http://www.w3.org/1999/xhtml', 'a'), - can_use_save_link = 'download' in save_link, - click = function(node) { - var event = new MouseEvent('click'); - node.dispatchEvent(event); - }, - is_safari = /constructor/i.test(view.HTMLElement) || view.safari, - is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent), - setImmediate = view.setImmediate || view.setTimeout, - throw_outside = function(ex) { - setImmediate(function() { - throw ex; - }, 0); - }, - force_saveable_type = 'application/octet-stream', - // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to - arbitrary_revoke_timeout = 1000 * 40, // in ms - revoke = function(file) { - var revoker = function() { - if (typeof file === 'string') { - // file is an object URL - get_URL().revokeObjectURL(file); - } else { - // file is a File - file.remove(); - } - }; - setTimeout(revoker, arbitrary_revoke_timeout); - }, - dispatch = function(filesaver, event_types, event) { - event_types = [].concat(event_types); - var i = event_types.length; - while (i--) { - var listener = filesaver['on' + event_types[i]]; - if (typeof listener === 'function') { - try { - listener.call(filesaver, event || filesaver); - } catch (ex) { - throw_outside(ex); - } - } - } - }, - auto_bom = function(blob) { - // prepend BOM for UTF-8 XML and text/* types (including HTML) - // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF - if ( - /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test( - blob.type - ) - ) { - return new Blob([String.fromCharCode(0xfeff), blob], { - type: blob.type - }); - } - return blob; - }, - FileSaver = function(blob, name, no_auto_bom) { - if (!no_auto_bom) { - blob = auto_bom(blob); - } - // First try a.download, then web filesystem, then object URLs - var filesaver = this, - type = blob.type, - force = type === force_saveable_type, - object_url, - dispatch_all = function() { - dispatch( - filesaver, - 'writestart progress write writeend'.split(' ') - ); - }, - // on any filesys errors revert to saving with object URLs - fs_error = function() { - if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { - // Safari doesn't allow downloading of blob urls - var reader = new FileReader(); - reader.onloadend = function() { - var url = is_chrome_ios - ? reader.result - : reader.result.replace( - /^data:[^;]*;/, - 'data:attachment/file;' - ); - var popup = view.open(url, '_blank'); - if (!popup) view.location.href = url; - url = undefined; // release reference before dispatching - filesaver.readyState = filesaver.DONE; - dispatch_all(); - }; - reader.readAsDataURL(blob); - filesaver.readyState = filesaver.INIT; - return; - } - // don't create more object URLs than needed - if (!object_url) { - object_url = get_URL().createObjectURL(blob); - } - if (force) { - view.location.href = object_url; - } else { - var opened = view.open(object_url, '_blank'); - if (!opened) { - // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html - view.location.href = object_url; - } - } - filesaver.readyState = filesaver.DONE; - dispatch_all(); - revoke(object_url); - }; - filesaver.readyState = filesaver.INIT; - - if (can_use_save_link) { - object_url = get_URL().createObjectURL(blob); - setImmediate(function() { - save_link.href = object_url; - save_link.download = name; - click(save_link); - dispatch_all(); - revoke(object_url); - filesaver.readyState = filesaver.DONE; - }, 0); - return; - } - - fs_error(); - }, - FS_proto = FileSaver.prototype, - saveAs = function(blob, name, no_auto_bom) { - return new FileSaver( - blob, - name || blob.name || 'download', - no_auto_bom - ); - }; - - // IE 10+ (native saveAs) - if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) { - return function(blob, name, no_auto_bom) { - name = name || blob.name || 'download'; - - if (!no_auto_bom) { - blob = auto_bom(blob); - } - return navigator.msSaveOrOpenBlob(blob, name); - }; - } - - // todo: detect chrome extensions & packaged apps - //save_link.target = "_blank"; - - FS_proto.abort = function() {}; - FS_proto.readyState = FS_proto.INIT = 0; - FS_proto.WRITING = 1; - FS_proto.DONE = 2; - - FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; - - return saveAs; - })( - (typeof self !== 'undefined' && self) || - (typeof window !== 'undefined' && window) || - this - ); From 9f6a65f18773282310d79d90c30d55781de47f54 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 17:24:29 +0100 Subject: [PATCH 22/40] Communicating service with new backend route --- .../js/services/csv-request/csvRequestService.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index fc8c141f6..4deb59890 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -11,7 +11,7 @@ */ define(['../module'], function (app) { class CSVRequest { - + /** * Constructor * @param {*} $requestService Service to make requests to our server @@ -28,12 +28,18 @@ define(['../module'], function (app) { */ async fetch(path, id, filters = null) { try { + const payload = {path:path,id:id,filters:filters} const output = await this.httpReq( 'POST', '/api/csv', - { path, id, filters } + $.param({ + payload + }) ) - return output.data + if(output.error){ + throw Error(output.error) + } + return output } catch (error) { return Promise.reject(error) } From 1905cfd08e1d779c25de3e206d0b4e2f823ad451 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 17:24:39 +0100 Subject: [PATCH 23/40] Added method to agent class --- .../js/controllers/agents/agents/agentsCtrl.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index 32e955bf3..ad6541511 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -13,7 +13,7 @@ define([ '../../module', '../../../services/visualizations/search/search-handler', - '../../../services/file-saver/file-saver' + 'FileSaver' ],function ( app, SearchHandler, @@ -88,31 +88,27 @@ define([ this.scope.version = 'all' this.scope.node_name = 'all' this.scope.versionModel = 'all' - this.scope.downloadCsv = (dataPath) => this.downloadCsv(dataPath) + this.scope.downloadCsv = () => this.downloadCsv() this.scope.$on('$destroy', () => { this.topAgent.destroy() }) - } /** * Exports the table in CSV format - * @param {String} dataPath */ - async downloadCsv(dataPath) { + async downloadCsv() { try { console.log('downloading csv...') this.toast('Your download should begin automatically...') const currentApi = this.api.id const output = await this.csvReq.fetch( - dataPath, + '/agents', currentApi, this.wzTableFilter.get() ) const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line - - FileSaver.saveAs(blob, 'packages.csv') - + saveAs(blob, 'packages.csv') return } catch (error) { console.error('error ',error) From f94b681557e55e3e26b2086ee08671223f2ed5b4 Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 18:01:42 +0100 Subject: [PATCH 24/40] Attached class method to scope --- .../js/controllers/settings/logs/logsCtrl.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/settings/logs/logsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/settings/logs/logsCtrl.js index c89e20ddd..4bcece8f0 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/settings/logs/logsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/settings/logs/logsCtrl.js @@ -20,28 +20,33 @@ define(['../../module'], function (module) { this.root = $rootScope } - async refreshLogs() { + /** + * Initialize + */ + $onInit() { + this.scope.refreshLogs = () => this.refreshLogs() try { - this.root.$broadcast('loading', { status: true }) - const result = await this.httpReq(`GET`, `/manager/get_log_lines`) - this.scope.logs = result.data.logs.map(item => JSON.parse(item)) - this.root.$broadcast('loading', { status: false }) + this.scope.logs = this.logs.data.logs.map(item => JSON.parse(item)) } catch (error) { - this.root.$broadcast('loading', { status: false }) this.scope.logs = [{ date: new Date(), level: 'error', message: 'Error when loading Wazuh app logs' }] } } /** - * Initialize + * Reloads the logs */ - $onInit() { + async refreshLogs() { try { - this.scope.logs = this.logs.data.logs.map(item => JSON.parse(item)) + this.root.$broadcast('loading', { status: true }) + const result = await this.httpReq(`GET`, `/manager/get_log_lines`) + this.scope.logs = result.data.logs.map(item => JSON.parse(item)) + this.root.$broadcast('loading', { status: false }) } catch (error) { + this.root.$broadcast('loading', { status: false }) this.scope.logs = [{ date: new Date(), level: 'error', message: 'Error when loading Wazuh app logs' }] } } + } // Logs controller module.controller('logsCtrl', Logs) From 2e5557f0ad1f9395fe18df611c1e0a350330530f Mon Sep 17 00:00:00 2001 From: manuasir Date: Tue, 13 Nov 2018 18:01:56 +0100 Subject: [PATCH 25/40] Implementing backend route for exporting csv --- .../appserver/controllers/api.py | 22 +++++++++++-------- .../services/csv-request/csvRequestService.js | 5 +++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 8e2d4a0bb..400c0fd3b 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -66,12 +66,18 @@ def request(self, **kwargs): @expose_page(must_login=False, methods=['POST']) def csv(self, **kwargs): try: + self.logger.info('Entring CSV route') + if 'payload[id]' not in kwargs or 'payload[path]' not in kwargs: #missing_params = diff_keys_dic_update_api(kwargs) raise Exception("Invalid arguments, missing params. Already got these params : %s" % str(kwargs)) filters = {} - if 'payload[filters]' in kwargs: - filters = kwargs['payload[filters]'] + filters['limit'] = 1000 + self.logger.info('Declaring filters route') + + # if 'payload[filters]' in kwargs: + # for key, value in kwargs['payload[filters]'].iteritems(): + # filters[key] = value the_id = kwargs['payload[id]'] api = self.db.get(the_id) opt_username = api[0]["userapi"] @@ -79,17 +85,15 @@ def csv(self, **kwargs): opt_base_url = api[0]["url"] opt_base_port = api[0]["portapi"] opt_endpoint = kwargs['payload[path]'] - del kwargs['id'] - del kwargs['endpoint'] + del kwargs['payload[id]'] + del kwargs['payload[path]'] url = opt_base_url + ":" + opt_base_port auth = requests.auth.HTTPBasicAuth(opt_username, opt_password) verify = False request = self.session.get( url + opt_endpoint, params=filters, auth=auth, verify=verify).json() - result = json.dumps(request) - self.logger.info('CSV Params: %s' % str(kwargs)) - parsed_data = json.dumps(request) + json_response = json.dumps(request) except Exception as e: - self.logger.error("Error in CSV generation: %s" % (e)) + self.logger.error("Error in CSV generation!: %s" % (e)) return json.dumps({"error":str(e)}) - return parsed_data \ No newline at end of file + return json_response \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 4deb59890..a30989c5a 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -36,8 +36,9 @@ define(['../module'], function (app) { payload }) ) - if(output.error){ - throw Error(output.error) + console.log('output ',output) + if(output.data.error){ + throw Error(output.data.error) } return output } catch (error) { From a0c0adc8f23f8ff43e9b35a9c80ee6c946d4fc89 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 12:20:59 +0100 Subject: [PATCH 26/40] Added csv exporter to backend module --- .../appserver/controllers/api.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 400c0fd3b..3600f6d65 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -14,6 +14,8 @@ import json import requests import re +import csv +import cStringIO import splunk.appserver.mrsparkle.controllers as controllers import splunk.appserver.mrsparkle.lib.util as util from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path @@ -90,10 +92,19 @@ def csv(self, **kwargs): url = opt_base_url + ":" + opt_base_port auth = requests.auth.HTTPBasicAuth(opt_username, opt_password) verify = False - request = self.session.get( - url + opt_endpoint, params=filters, auth=auth, verify=verify).json() - json_response = json.dumps(request) + request = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() + final_obj = request["data"]["items"] + keys = final_obj[0].keys() + self.logger.info("Keys!: %s" % (keys)) + output_file = cStringIO.StringIO() + dict_writer = csv.DictWriter(output_file, fieldnames=keys,extrasaction='ignore',lineterminator=' ') + dict_writer.writeheader() + dict_writer.writerows(final_obj) + self.logger.info("Returning this!: %s" % (output_file.getvalue())) + csv_result = output_file.getvalue() + self.logger.info("Returned this!: %s" % (output_file.getvalue())) + output_file.close() except Exception as e: self.logger.error("Error in CSV generation!: %s" % (e)) return json.dumps({"error":str(e)}) - return json_response \ No newline at end of file + return csv_result From c10f63b96044b6152092ccc57412f31d059e9360 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 12:21:13 +0100 Subject: [PATCH 27/40] Debugging csv output --- .../controllers/agents/agents/agentsCtrl.js | 1 + .../services/csv-request/csvRequestService.js | 28 ++++++++----------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index e37a30a65..549ea48ad 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -34,6 +34,7 @@ define([ * @param {Object} $requestService * @param {Object} agentData */ + constructor($urlTokenModel, $scope, $currentDataService, $state, $notificationService, $requestService, $csvRequestService,$tableFilterService, agentData){ this.scope = $scope this.submittedTokenModel = $urlTokenModel.getSubmittedTokenModel() diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index a30989c5a..619f3d825 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -17,7 +17,7 @@ define(['../module'], function (app) { * @param {*} $requestService Service to make requests to our server */ constructor($requestService) { - this.httpReq = $requestService.httpReq; + this.httpReq = $requestService.httpReq } /** @@ -29,22 +29,16 @@ define(['../module'], function (app) { async fetch(path, id, filters = null) { try { const payload = {path:path,id:id,filters:filters} - const output = await this.httpReq( - 'POST', - '/api/csv', - $.param({ - payload - }) - ) - console.log('output ',output) - if(output.data.error){ - throw Error(output.data.error) - } - return output - } catch (error) { - return Promise.reject(error) + const output = await this.httpReq('POST','/api/csv',$.param({payload})) + console.log('output ',output.data) + if(output.data.error){ + throw Error(output.data.error) } + return JSON.stringify(output.data) + } catch (error) { + return Promise.reject(error) } } - app.service('$csvRequestService', CSVRequest ) - }) \ No newline at end of file + } + app.service('$csvRequestService', CSVRequest ) +}) \ No newline at end of file From 7c7edcf424a13ca9ab9a0ce573167cdae1cfff69 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 13:22:31 +0100 Subject: [PATCH 28/40] Extracting fields with same Kibana delimiters --- SplunkAppForWazuh/appserver/controllers/api.py | 4 +++- .../static/js/services/csv-request/csvRequestService.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 3600f6d65..57d5a9236 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -95,9 +95,11 @@ def csv(self, **kwargs): request = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() final_obj = request["data"]["items"] keys = final_obj[0].keys() + for key in keys: + key = '"'+key+'"' self.logger.info("Keys!: %s" % (keys)) output_file = cStringIO.StringIO() - dict_writer = csv.DictWriter(output_file, fieldnames=keys,extrasaction='ignore',lineterminator=' ') + dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n') dict_writer.writeheader() dict_writer.writerows(final_obj) self.logger.info("Returning this!: %s" % (output_file.getvalue())) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 619f3d825..665e45887 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -34,7 +34,7 @@ define(['../module'], function (app) { if(output.data.error){ throw Error(output.data.error) } - return JSON.stringify(output.data) + return output.data } catch (error) { return Promise.reject(error) } From ecf603273ffe52125897c7296c0fa9f5452d8f24 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 15:41:28 +0100 Subject: [PATCH 29/40] Paginating results in backend --- .../appserver/controllers/api.py | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 57d5a9236..712bbf0c2 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -75,6 +75,7 @@ def csv(self, **kwargs): raise Exception("Invalid arguments, missing params. Already got these params : %s" % str(kwargs)) filters = {} filters['limit'] = 1000 + filters['offset'] = 0 self.logger.info('Declaring filters route') # if 'payload[filters]' in kwargs: @@ -92,19 +93,30 @@ def csv(self, **kwargs): url = opt_base_url + ":" + opt_base_port auth = requests.auth.HTTPBasicAuth(opt_username, opt_password) verify = False + # init csv writer + output_file = cStringIO.StringIO() + # get total items and keys request = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() final_obj = request["data"]["items"] + # for item in final_obj_dict: + # if item typeof + total_items = request["data"]["totalItems"] keys = final_obj[0].keys() - for key in keys: - key = '"'+key+'"' - self.logger.info("Keys!: %s" % (keys)) - output_file = cStringIO.StringIO() + # initializes CSV buffer dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n') + dict_writer.writerow(final_obj) + + # write CSV header dict_writer.writeheader() - dict_writer.writerows(final_obj) - self.logger.info("Returning this!: %s" % (output_file.getvalue())) + offset = 1000 + # get the rest of results + while offset < total_items: + offset+=filters['limit'] + filters['offset']=offset + req = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() + dict_writer.writerow(req['data']['items']) + csv_result = output_file.getvalue() - self.logger.info("Returned this!: %s" % (output_file.getvalue())) output_file.close() except Exception as e: self.logger.error("Error in CSV generation!: %s" % (e)) From a50600cc597f570ed5dee67a32063a1ced2d1860 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 16:23:58 +0100 Subject: [PATCH 30/40] Adjusting pagination to csv route --- SplunkAppForWazuh/appserver/controllers/api.py | 13 +++++++------ .../js/services/csv-request/csvRequestService.js | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 712bbf0c2..f3b01a324 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -103,18 +103,19 @@ def csv(self, **kwargs): total_items = request["data"]["totalItems"] keys = final_obj[0].keys() # initializes CSV buffer + dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n') - dict_writer.writerow(final_obj) - - # write CSV header + # write CSV header dict_writer.writeheader() - offset = 1000 + dict_writer.writerows(final_obj) + + offset = 0 # get the rest of results - while offset < total_items: + while offset <= total_items: offset+=filters['limit'] filters['offset']=offset req = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() - dict_writer.writerow(req['data']['items']) + dict_writer.writerows(req['data']['items']) csv_result = output_file.getvalue() output_file.close() diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 665e45887..864715646 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -30,7 +30,6 @@ define(['../module'], function (app) { try { const payload = {path:path,id:id,filters:filters} const output = await this.httpReq('POST','/api/csv',$.param({payload})) - console.log('output ',output.data) if(output.data.error){ throw Error(output.data.error) } From daa70e22fca55394e60e19bc4f72b4b74884911e Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 18:24:56 +0100 Subject: [PATCH 31/40] Managing filters --- .../appserver/controllers/api.py | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index f3b01a324..9dbe3d02f 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -36,6 +36,22 @@ def __init__(self): except Exception as e: self.logger.error("Error in API module constructor: %s" % (e)) + def format(self,arr): + try: + if isinstance(arr,list): + for item in arr: + if isinstance(item,dict): + for key, value in item.iteritems(): + if isinstance(item[key],dict): + item[key] = '"'+json.dumps(item[key])+'"' + else: + item[key] = '"'+str(item[key])+'"' + else: + item = '"'+str(item)+'"' + return arr + except Exception as e: + raise e + # /custom/SplunkAppForWazuh/api/node # This will perform an HTTP request to Wazuh API # It will return the full API response with including its error codes @@ -68,28 +84,27 @@ def request(self, **kwargs): @expose_page(must_login=False, methods=['POST']) def csv(self, **kwargs): try: - self.logger.info('Entring CSV route') + self.logger.info('Generating CSV.') - if 'payload[id]' not in kwargs or 'payload[path]' not in kwargs: - #missing_params = diff_keys_dic_update_api(kwargs) - raise Exception("Invalid arguments, missing params. Already got these params : %s" % str(kwargs)) + if 'id' not in kwargs or 'path' not in kwargs: + raise Exception("Invalid arguments or missing params.") filters = {} filters['limit'] = 1000 filters['offset'] = 0 - self.logger.info('Declaring filters route') - # if 'payload[filters]' in kwargs: - # for key, value in kwargs['payload[filters]'].iteritems(): - # filters[key] = value - the_id = kwargs['payload[id]'] + if 'filters' in kwargs: + self.logger.info('Filters route: %s ' % (kwargs['filters'])) + parsed_filters = json.loads(kwargs['filters']) + filters.update(parsed_filters) + the_id = kwargs['id'] api = self.db.get(the_id) opt_username = api[0]["userapi"] opt_password = api[0]["passapi"] opt_base_url = api[0]["url"] opt_base_port = api[0]["portapi"] - opt_endpoint = kwargs['payload[path]'] - del kwargs['payload[id]'] - del kwargs['payload[path]'] + opt_endpoint = kwargs['path'] + del kwargs['id'] + del kwargs['path'] url = opt_base_url + ":" + opt_base_port auth = requests.auth.HTTPBasicAuth(opt_username, opt_password) verify = False @@ -98,16 +113,17 @@ def csv(self, **kwargs): # get total items and keys request = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() final_obj = request["data"]["items"] - # for item in final_obj_dict: - # if item typeof - total_items = request["data"]["totalItems"] keys = final_obj[0].keys() + self.format(keys) + final_obj_dict = self.format(final_obj) + + total_items = request["data"]["totalItems"] # initializes CSV buffer dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n') # write CSV header dict_writer.writeheader() - dict_writer.writerows(final_obj) + dict_writer.writerows(final_obj_dict) offset = 0 # get the rest of results @@ -115,10 +131,14 @@ def csv(self, **kwargs): offset+=filters['limit'] filters['offset']=offset req = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() - dict_writer.writerows(req['data']['items']) + paginated_result = req['data']['items'] + format_paginated_results = self.format(paginated_result) + dict_writer.writerows(format_paginated_results) csv_result = output_file.getvalue() output_file.close() + self.logger.info('CSV generated successfully.') + except Exception as e: self.logger.error("Error in CSV generation!: %s" % (e)) return json.dumps({"error":str(e)}) From 8d68fa4b6b5343c71759efc880c64fee4561d9db Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 18:25:04 +0100 Subject: [PATCH 32/40] Exporting csv with filters --- .../appserver/static/js/config/routes/agents-states.js | 1 + .../static/js/controllers/agents/agents/agentsCtrl.js | 1 + .../static/js/services/csv-request/csvRequestService.js | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/config/routes/agents-states.js b/SplunkAppForWazuh/appserver/static/js/config/routes/agents-states.js index 9067f0632..4d1faeca4 100644 --- a/SplunkAppForWazuh/appserver/static/js/config/routes/agents-states.js +++ b/SplunkAppForWazuh/appserver/static/js/config/routes/agents-states.js @@ -8,6 +8,7 @@ define(['../module'], function (module) { .state('agents', { templateUrl: BASE_URL + '/static/app/SplunkAppForWazuh/js/controllers/agents/agents/agents.html', controller: 'agentsCtrl', + onEnter: ($navigationService) => { $navigationService.storeRoute('agents') }, resolve: { agentData: ['$requestService','$state', async ($requestService, $state) => { try{ diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index 549ea48ad..b68f8d0ae 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -102,6 +102,7 @@ define([ console.log('downloading csv...') this.toast('Your download should begin automatically...') const currentApi = this.api.id + console.log('sending these filters : ',this.wzTableFilter.get()) const output = await this.csvReq.fetch( '/agents', currentApi, diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 864715646..78396662e 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -28,8 +28,13 @@ define(['../module'], function (app) { */ async fetch(path, id, filters = null) { try { - const payload = {path:path,id:id,filters:filters} - const output = await this.httpReq('POST','/api/csv',$.param({payload})) + let filterArr = '{' + filters.map(filter => filterArr+=`"${filter.name}": "${filter.value}",`) + filterArr.slice(filterArr.length,1) + filterArr+='}' + const payload = {'path':path,'id':id,'filters':filterArr} + console.log('payload ',payload) + const output = await this.httpReq('POST','/api/csv',$.param(payload)) if(output.data.error){ throw Error(output.data.error) } From 69d2c996f52b25e5c71b1fe93ee240f578152b5f Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 23:18:30 +0100 Subject: [PATCH 33/40] Downloading csv in agent dashboard --- .../appserver/static/js/controllers/agents/agents/agentsCtrl.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index b68f8d0ae..ca629e28a 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -99,10 +99,8 @@ define([ */ async downloadCsv() { try { - console.log('downloading csv...') this.toast('Your download should begin automatically...') const currentApi = this.api.id - console.log('sending these filters : ',this.wzTableFilter.get()) const output = await this.csvReq.fetch( '/agents', currentApi, From d65c1775ddbc144fa1b2e8f3b563182a132636c0 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 23:18:48 +0100 Subject: [PATCH 34/40] Improved csv method --- SplunkAppForWazuh/appserver/controllers/api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 9dbe3d02f..4e47de73a 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -43,11 +43,11 @@ def format(self,arr): if isinstance(item,dict): for key, value in item.iteritems(): if isinstance(item[key],dict): - item[key] = '"'+json.dumps(item[key])+'"' + item[key] = json.dumps(item[key]) else: - item[key] = '"'+str(item[key])+'"' + item[key] = str(item[key]) else: - item = '"'+str(item)+'"' + item = str(item) return arr except Exception as e: raise e @@ -120,7 +120,7 @@ def csv(self, **kwargs): total_items = request["data"]["totalItems"] # initializes CSV buffer - dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n') + dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n',quotechar='"') # write CSV header dict_writer.writeheader() dict_writer.writerows(final_obj_dict) From 2f4f721d41a294fcb13a5855403a66e895f50cc9 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 23:19:08 +0100 Subject: [PATCH 35/40] Sending a parsed object --- .../services/csv-request/csvRequestService.js | 97 ++++++++++--------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js index 78396662e..d178130e9 100644 --- a/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js +++ b/SplunkAppForWazuh/appserver/static/js/services/csv-request/csvRequestService.js @@ -1,48 +1,51 @@ -/* -* 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. -*/ -define(['../module'], function (app) { - class CSVRequest { - - /** - * Constructor - * @param {*} $requestService Service to make requests to our server - */ - constructor($requestService) { - this.httpReq = $requestService.httpReq - } - - /** - * Fetchs data from /api/csv route using the below parameters. - * @param {string} path Wazuh API route - * @param {number|string} id API ID - * @param {*} filters Array of Wazuh API filters. Optional - */ - async fetch(path, id, filters = null) { - try { - let filterArr = '{' - filters.map(filter => filterArr+=`"${filter.name}": "${filter.value}",`) - filterArr.slice(filterArr.length,1) - filterArr+='}' - const payload = {'path':path,'id':id,'filters':filterArr} - console.log('payload ',payload) - const output = await this.httpReq('POST','/api/csv',$.param(payload)) - if(output.data.error){ - throw Error(output.data.error) - } - return output.data - } catch (error) { - return Promise.reject(error) - } - } - } - app.service('$csvRequestService', CSVRequest ) +/* +* 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. +*/ +define(['../module'], function (app) { + class CSVRequest { + + /** + * Constructor + * @param {*} $requestService Service to make requests to our server + */ + constructor($requestService) { + this.httpReq = $requestService.httpReq + } + + /** + * Fetchs data from /api/csv route using the below parameters. + * @param {string} path Wazuh API route + * @param {number|string} id API ID + * @param {*} filters Array of Wazuh API filters. Optional + */ + async fetch(path, id, filters = null) { + try { + let filterStr = '{' + filters.map(filter => filterStr+=`"${filter.name}": "${filter.value}",`) + console.log('filterstr before ',filterStr) + filterStr = filterStr.slice(0, -1) + console.log('filterstr after ',filterStr) + + filterStr+='}' + const payload = {'path':path,'id':id,'filters':filterStr} + console.log('payload ',payload) + const output = await this.httpReq('POST','/api/csv',$.param(payload)) + if(output.data.error){ + throw Error(output.data.error) + } + return output.data + } catch (error) { + return Promise.reject(error) + } + } + } + app.service('$csvRequestService', CSVRequest ) }) \ No newline at end of file From ce76ba9e411f6459b601f4cb2e31c58ea6544604 Mon Sep 17 00:00:00 2001 From: manuasir Date: Wed, 14 Nov 2018 23:19:28 +0100 Subject: [PATCH 36/40] Deleted console output --- .../management/groups/groupsCtrl.js | 243 +++++++++--------- 1 file changed, 121 insertions(+), 122 deletions(-) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js index de9b33829..d02af332a 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js @@ -1,123 +1,122 @@ - - -define(['../../module'], function (controllers) { - - 'use strict' - - class Groups{ - constructor($scope, $state, $stateParams, $requestService, $beautifierJson, $notificationService){ - this.scope = $scope - this.state = $state - this.beautifier = $beautifierJson - this.stateParams = $stateParams - this.apiReq = $requestService.apiReq - this.toast = $notificationService.showSimpleToast - this.mainGroup = '' - this.scope.lookingGroup = false - this.scope.loadingRing = false - - - this.scope.$watch('lookingGroup', value => { - if (!value) { - this.scope.file = false - this.scope.filename = false - } - }) - - this.scope.$on('groupsIsReloaded', () => { - this.scope.currentGroup = false - this.scope.lookingGroup = false - if (!this.scope.$$phase) this.scope.$digest() - }) - - this.scope.$on('wazuhShowGroup', (event, parameters) => { - return this.loadGroup(parameters.group) - }) - - this.scope.$on('wazuhShowGroupFile', (event, parameters) => { - return this.showFile(parameters.groupName, parameters.fileName) - }) - } - - $onInit(){ - console.log('on init') - this.scope.search = term => { this.scope.$broadcast('wazuhSearch', { term }) } - this.scope.loadGroup = (group,firstLoad) => this.loadGroup(group,firstLoad) - this.scope.toggle = () => this.scope.lookingGroup = true - this.scope.goBackToAgents = () => this.goBackToAgents() - this.scope.reload = () => this.reload() - this.scope.goBackFiles = () => this.goBackFiles() - this.scope.goBackGroups = () => this.goBackGroups() - this.scope.showFile = (groupName, fileName) => this.showFile(groupName, fileName) - if (this.stateParams.group) { - if(this.stateParams && this.stateParams.group && typeof this.stateParams.group === 'object') { - this.mainGroup = this.stateParams.group - this.loadGroup(this.mainGroup) - } - } - if (!this.scope.$$phase) this.scope.$digest() - - } - - async loadGroup (group, firstLoad) { - try { - if (!firstLoad) this.scope.lookingGroup = true - const count = await this.apiReq(`/agents/groups/${group.name}/files`, { limit: 1 }) - this.scope.totalFiles = count.data.data.totalItems - this.scope.fileViewer = false - this.scope.currentGroup = group - this.mainGroup = group - if (!this.scope.$$phase) this.scope.$digest() - } catch (error) { - this.toast('Cannot load group data') - } - return - } - - - goBackToAgents () { - this.scope.groupsSelectedTab = 'agents' - this.scope.file = false - this.scope.filename = false - if (!this.scope.$$phase) this.scope.$digest() - } - - reload () { - if (this.stateParams && this.stateParams.group && typeof this.stateParams.group === 'object') this.state.go('.', {group: undefined} ) - else this.state.reload() - } - - goBackFiles() { - this.scope.groupsSelectedTab = 'files' - this.scope.file = false - this.scope.filename = false - this.scope.fileViewer = false - if (!this.scope.$$phase) this.scope.$digest() - } - - goBackGroups () { - this.scope.currentGroup = false - this.scope.lookingGroup = false - if (!this.scope.$$phase) this.scope.$digest() - } - - async showFile (groupName, fileName) { - try { - if (this.scope.filename) this.scope.filename = '' - if (fileName === '../ar.conf') fileName = 'ar.conf' - this.scope.fileViewer = true - const tmpName = `/agents/groups/${groupName}/files/${fileName}` - const data = await this.apiReq(tmpName) - this.scope.file = this.beautifier.prettyPrint(data.data.data) - this.scope.filename = fileName - - if (!this.scope.$$phase) this.scope.$digest() - } catch (error) { - this.toast('Error showing file ') - } - return - } - - } - controllers.controller('groupsCtrl', Groups) + + +define(['../../module'], function (controllers) { + + 'use strict' + + class Groups{ + constructor($scope, $state, $stateParams, $requestService, $beautifierJson, $notificationService){ + this.scope = $scope + this.state = $state + this.beautifier = $beautifierJson + this.stateParams = $stateParams + this.apiReq = $requestService.apiReq + this.toast = $notificationService.showSimpleToast + this.mainGroup = '' + this.scope.lookingGroup = false + this.scope.loadingRing = false + + + this.scope.$watch('lookingGroup', value => { + if (!value) { + this.scope.file = false + this.scope.filename = false + } + }) + + this.scope.$on('groupsIsReloaded', () => { + this.scope.currentGroup = false + this.scope.lookingGroup = false + if (!this.scope.$$phase) this.scope.$digest() + }) + + this.scope.$on('wazuhShowGroup', (event, parameters) => { + return this.loadGroup(parameters.group) + }) + + this.scope.$on('wazuhShowGroupFile', (event, parameters) => { + return this.showFile(parameters.groupName, parameters.fileName) + }) + } + + $onInit(){ + this.scope.search = term => { this.scope.$broadcast('wazuhSearch', { term }) } + this.scope.loadGroup = (group,firstLoad) => this.loadGroup(group,firstLoad) + this.scope.toggle = () => this.scope.lookingGroup = true + this.scope.goBackToAgents = () => this.goBackToAgents() + this.scope.reload = () => this.reload() + this.scope.goBackFiles = () => this.goBackFiles() + this.scope.goBackGroups = () => this.goBackGroups() + this.scope.showFile = (groupName, fileName) => this.showFile(groupName, fileName) + if (this.stateParams.group) { + if(this.stateParams && this.stateParams.group && typeof this.stateParams.group === 'object') { + this.mainGroup = this.stateParams.group + this.loadGroup(this.mainGroup) + } + } + if (!this.scope.$$phase) this.scope.$digest() + + } + + async loadGroup (group, firstLoad) { + try { + if (!firstLoad) this.scope.lookingGroup = true + const count = await this.apiReq(`/agents/groups/${group.name}/files`, { limit: 1 }) + this.scope.totalFiles = count.data.data.totalItems + this.scope.fileViewer = false + this.scope.currentGroup = group + this.mainGroup = group + if (!this.scope.$$phase) this.scope.$digest() + } catch (error) { + this.toast('Cannot load group data') + } + return + } + + + goBackToAgents () { + this.scope.groupsSelectedTab = 'agents' + this.scope.file = false + this.scope.filename = false + if (!this.scope.$$phase) this.scope.$digest() + } + + reload () { + if (this.stateParams && this.stateParams.group && typeof this.stateParams.group === 'object') this.state.go('.', {group: undefined} ) + else this.state.reload() + } + + goBackFiles() { + this.scope.groupsSelectedTab = 'files' + this.scope.file = false + this.scope.filename = false + this.scope.fileViewer = false + if (!this.scope.$$phase) this.scope.$digest() + } + + goBackGroups () { + this.scope.currentGroup = false + this.scope.lookingGroup = false + if (!this.scope.$$phase) this.scope.$digest() + } + + async showFile (groupName, fileName) { + try { + if (this.scope.filename) this.scope.filename = '' + if (fileName === '../ar.conf') fileName = 'ar.conf' + this.scope.fileViewer = true + const tmpName = `/agents/groups/${groupName}/files/${fileName}` + const data = await this.apiReq(tmpName) + this.scope.file = this.beautifier.prettyPrint(data.data.data) + this.scope.filename = fileName + + if (!this.scope.$$phase) this.scope.$digest() + } catch (error) { + this.toast('Error showing file ') + } + return + } + + } + controllers.controller('groupsCtrl', Groups) }) \ No newline at end of file From 5c16f5151dc15db85777c16a754771ee662ec68d Mon Sep 17 00:00:00 2001 From: "Manuel J. Bernal" Date: Thu, 15 Nov 2018 09:49:07 +0100 Subject: [PATCH 37/40] Improvements after testing --- .../appserver/controllers/api.py | 51 ++++++++------- .../controllers/agents/agents/agentsCtrl.js | 4 +- .../management/logs/manager-logs.html | 6 ++ .../management/logs/managerLogsCtrl.js | 62 +++++++++++++++---- .../services/csv-request/csvRequestService.js | 30 ++++----- 5 files changed, 99 insertions(+), 54 deletions(-) diff --git a/SplunkAppForWazuh/appserver/controllers/api.py b/SplunkAppForWazuh/appserver/controllers/api.py index 4e47de73a..829374719 100644 --- a/SplunkAppForWazuh/appserver/controllers/api.py +++ b/SplunkAppForWazuh/appserver/controllers/api.py @@ -112,32 +112,35 @@ def csv(self, **kwargs): output_file = cStringIO.StringIO() # get total items and keys request = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() - final_obj = request["data"]["items"] - keys = final_obj[0].keys() - self.format(keys) - final_obj_dict = self.format(final_obj) + if 'items' in request: + final_obj = request["data"]["items"] + if isinstance(final_obj,list) and len(final_obj) > 0: + keys = final_obj[0].keys() + self.format(keys) + final_obj_dict = self.format(final_obj) + total_items = request["data"]["totalItems"] + # initializes CSV buffer + if total_items > 0: + dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n',quotechar='"') + # write CSV header + dict_writer.writeheader() + dict_writer.writerows(final_obj_dict) - total_items = request["data"]["totalItems"] - # initializes CSV buffer - - dict_writer = csv.DictWriter(output_file, delimiter=',',fieldnames=keys,extrasaction='ignore',lineterminator='\n',quotechar='"') - # write CSV header - dict_writer.writeheader() - dict_writer.writerows(final_obj_dict) + offset = 0 + # get the rest of results + while offset <= total_items: + offset+=filters['limit'] + filters['offset']=offset + req = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() + paginated_result = req['data']['items'] + format_paginated_results = self.format(paginated_result) + dict_writer.writerows(format_paginated_results) - offset = 0 - # get the rest of results - while offset <= total_items: - offset+=filters['limit'] - filters['offset']=offset - req = self.session.get(url + opt_endpoint, params=filters, auth=auth, verify=verify).json() - paginated_result = req['data']['items'] - format_paginated_results = self.format(paginated_result) - dict_writer.writerows(format_paginated_results) - - csv_result = output_file.getvalue() - output_file.close() - self.logger.info('CSV generated successfully.') + csv_result = output_file.getvalue() + self.logger.info('CSV generated successfully.') + else: + csv_result = [] + output_file.close() except Exception as e: self.logger.error("Error in CSV generation!: %s" % (e)) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js index ca629e28a..560fa4bce 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/agents/agents/agentsCtrl.js @@ -46,8 +46,6 @@ define([ this.currentClusterInfo = $currentDataService.getClusterInfo() this.filters = $currentDataService.getSerializedFilters() this.csvReq = $csvRequestService - - this.wzTableFilter = $tableFilterService this.wzTableFilter = $tableFilterService const parsedResult = agentData.map(item => item && item.data && item.data.data ? item.data.data : false) @@ -107,7 +105,7 @@ define([ this.wzTableFilter.get() ) const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line - saveAs(blob, 'packages.csv') + saveAs(blob, 'agents.csv') return } catch (error) { console.error('error ',error) diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/logs/manager-logs.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/logs/manager-logs.html index c537636d5..3099f59c2 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/logs/manager-logs.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/logs/manager-logs.html @@ -77,6 +77,12 @@ rows-per-page="15"> + - + \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html index 02649e012..7579193b4 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html @@ -56,7 +56,12 @@ allow-click="true" rows-per-page="14"> - + \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersCtrl.js index 44a18f189..6da152f07 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersCtrl.js @@ -3,8 +3,8 @@ define(['../../module', '../rules/ruleset'], function (controllers, Ruleset) { 'use strict' class Decoders extends Ruleset { - constructor($scope, $sce, $notificationService) { - super($scope, $sce, $notificationService, 'decoders') + constructor($scope, $sce, $notificationService, $currentDataService,$tableFilterService,$csvRequestService) { + super($scope, $sce, $notificationService, 'decoders',$currentDataService,$tableFilterService,$csvRequestService) this.scope.typeFilter = 'all' } @@ -13,7 +13,8 @@ define(['../../module', '../rules/ruleset'], function (controllers, Ruleset) { */ $onInit() { // Reloading event listener - this.scope.$broadcast('wazuhSearch', { term:'', removeFilters: true }); + this.scope.$broadcast('wazuhSearch', { term:'', removeFilters: true }) + this.scope.downloadCsv = (path,name) => this.downloadCsv(path,name) this.scope.$on('decodersIsReloaded', () => { this.scope.viewingDetail = false if (!this.scope.$$phase) this.scope.$digest() diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersIdCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersIdCtrl.js index cc8a612cc..290b6680a 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersIdCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/managerDecodersIdCtrl.js @@ -3,8 +3,8 @@ define(['../../module','../rules/ruleset'], function (controllers, Ruleset) { 'use strict' class DecodersId extends Ruleset { - constructor($scope, $sce, $notificationService, $state, currentDecoder) { - super($scope,$sce,$notificationService,'decoders') + constructor($scope, $sce, $notificationService, $state, currentDecoder,$currentDataService,$tableFilterService,$csvRequestService) { + super($scope,$sce,$notificationService,'decoders',$currentDataService,$tableFilterService,$csvRequestService) this.state = $state try { this.filters = JSON.parse(window.localStorage.decoders) || [] @@ -14,6 +14,7 @@ define(['../../module','../rules/ruleset'], function (controllers, Ruleset) { } $onInit(){ + this.scope.downloadCsv = (path,name) => this.downloadCsv(path,name) this.scope.addDetailFilter = (name,value) => this.addDetailFilter(name,value) } diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groups.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groups.html index 17f48b102..9aa52aa88 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groups.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groups.html @@ -81,12 +81,17 @@
-
- +
- +
- +
diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js index d02af332a..6a6c38973 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/groups/groupsCtrl.js @@ -1,15 +1,23 @@ -define(['../../module'], function (controllers) { +define(['../../module', +'FileSaver' +], function (controllers) { 'use strict' class Groups{ - constructor($scope, $state, $stateParams, $requestService, $beautifierJson, $notificationService){ + constructor($scope,$tableFilterService,$csvRequestService, $currentDataService,$state, $stateParams, $requestService, $beautifierJson, $notificationService){ this.scope = $scope this.state = $state this.beautifier = $beautifierJson this.stateParams = $stateParams + this.api = $currentDataService.getApi() + + this.csvReq = $csvRequestService + + this.wzTableFilter = $tableFilterService + this.apiReq = $requestService.apiReq this.toast = $notificationService.showSimpleToast this.mainGroup = '' @@ -47,6 +55,8 @@ define(['../../module'], function (controllers) { this.scope.reload = () => this.reload() this.scope.goBackFiles = () => this.goBackFiles() this.scope.goBackGroups = () => this.goBackGroups() + this.scope.downloadCsv = (path,name) => this.downloadCsv(path,name) + this.scope.showFile = (groupName, fileName) => this.showFile(groupName, fileName) if (this.stateParams.group) { if(this.stateParams && this.stateParams.group && typeof this.stateParams.group === 'object') { @@ -55,9 +65,30 @@ define(['../../module'], function (controllers) { } } if (!this.scope.$$phase) this.scope.$digest() - } - + + /** + * Exports the table in CSV format + */ + async downloadCsv(path,name) { + try { + this.toast('Your download should begin automatically...') + const currentApi = this.api.id + const output = await this.csvReq.fetch( + path, + currentApi, + this.wzTableFilter.get() + ) + const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line + saveAs(blob, name) + return + } catch (error) { + console.error('error ',error) + this.toast('Error downloading CSV') + } + return + } + async loadGroup (group, firstLoad) { try { if (!firstLoad) this.scope.lookingGroup = true @@ -72,8 +103,8 @@ define(['../../module'], function (controllers) { } return } - - + + goBackToAgents () { this.scope.groupsSelectedTab = 'agents' this.scope.file = false @@ -85,7 +116,7 @@ define(['../../module'], function (controllers) { if (this.stateParams && this.stateParams.group && typeof this.stateParams.group === 'object') this.state.go('.', {group: undefined} ) else this.state.reload() } - + goBackFiles() { this.scope.groupsSelectedTab = 'files' this.scope.file = false diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset-id.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset-id.html index 9e061430c..84e08a902 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset-id.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset-id.html @@ -250,7 +250,12 @@

- +
diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html index 229822bfe..88e98fe00 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html @@ -72,4 +72,10 @@ allow-click="true" rows-per-page="14"> + \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetCtrl.js index 20da62dab..16956c591 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetCtrl.js @@ -3,14 +3,15 @@ define(['../../module','./ruleset'], function (controllers,Ruleset) { 'use strict' class Rules extends Ruleset{ - constructor($scope, $sce, $notificationService) { - super($scope,$sce,$notificationService,'ruleset') + constructor($scope, $sce, $notificationService, $currentDataService,$tableFilterService,$csvRequestService) { + super($scope,$sce,$notificationService,'ruleset',$currentDataService,$tableFilterService,$csvRequestService) } /** * On controller load */ $onInit() { + this.scope.downloadCsv = (path,name) => this.downloadCsv(path,name) this.scope.$broadcast('wazuhSearch', { term:'', removeFilters: true }); this.scope.$on('loadedTable', () => { try{ diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetIdCtrl.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetIdCtrl.js index 9ae739327..ca32a8b32 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetIdCtrl.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/managerRulesetIdCtrl.js @@ -3,8 +3,8 @@ define(['../../module','./ruleset'], function (controllers, Ruleset) { 'use strict' class RulesetId extends Ruleset { - constructor($scope, $sce, $notificationService, $state, ruleInfo) { - super($scope,$sce,$notificationService,'ruleset') + constructor($scope, $sce, $notificationService, $state, ruleInfo,$currentDataService,$tableFilterService,$csvRequestService) { + super($scope,$sce,$notificationService,'ruleset',$currentDataService,$tableFilterService,$csvRequestService) this.state = $state try { this.filters = JSON.parse(window.localStorage.ruleset) || [] @@ -14,6 +14,7 @@ define(['../../module','./ruleset'], function (controllers, Ruleset) { } $onInit(){ + this.scope.downloadCsv = (path,name) => this.downloadCsv(path,name) this.scope.addDetailFilter = (name,value) => this.addDetailFilter(name,value) } diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js index e2aa9c785..89c8b0e8e 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js @@ -1,12 +1,17 @@ -define(['../../module'], function (controllers) { - +define(['../../module', +'FileSaver' +], function (app) { + 'use strict' - + class Ruleset { - constructor($scope, $sce, $notificationService, view) { + constructor($scope, $sce, $notificationService, view, $currentDataService,$tableFilterService,$csvRequestService) { this.scope = $scope this.view = view this.toast = $notificationService.showSimpleToast + this.api = $currentDataService.getApi() + this.wzTableFilter = $tableFilterService + this.csvReq = $csvRequestService this.sce = $sce this.colors = [ '#004A65', '#00665F', '#BF4B45', '#BF9037', '#1D8C2E', 'BB3ABF', @@ -24,10 +29,10 @@ define(['../../module'], function (controllers) { this.scope.isArray = angular.isArray this.initialize() } - + /** - * On controller load - */ + * On controller load + */ initialize() { (this.view === 'decoders') ? delete window.localStorage.ruleset : delete window.localStorage.decoders this.scope.search = (term) => this.search(term) @@ -36,6 +41,7 @@ define(['../../module'], function (controllers) { this.scope.removeFilter = (filterName) => this.removeFilter(filterName) this.scope.colorRuleArg = (ruleArg) => this.colorRegex(ruleArg) this.scope.closeDetailView = (clear) => this.closeDetailView(clear) + this.scope.downloadCsv = (path,name) => this.downloadCsv(path,name) if (this.view === 'ruleset') { this.scope.colorRuleArg = (regex) => this.colorRegex(regex) } else { @@ -44,6 +50,29 @@ define(['../../module'], function (controllers) { this.scope.colorOrder = (order) => this.colorOrder(order) } + /** + * Exports the table in CSV format + */ + async downloadCsv(path,name) { + try { + this.toast('Your download should begin automatically...') + const currentApi = this.api.id + const output = await this.csvReq.fetch( + path, + currentApi, + this.wzTableFilter.get() + ) + const blob = new Blob([output], { type: 'text/csv' }) // eslint-disable-line + saveAs(blob, name) + return + } catch (error) { + console.error('error ',error) + this.toast('Error downloading CSV') + } + return + } + + colorRegex(regex) { regex = regex.toString() let valuesArray = regex.match(/\(((?!<\/span>).)*?\)(?!<\/span>)/gmi) @@ -55,7 +84,7 @@ define(['../../module'], function (controllers) { } return this.sce.trustAsHtml(coloredString) } - + colorOrder(order) { order = order.toString() let valuesArray = order.split(',') @@ -65,19 +94,19 @@ define(['../../module'], function (controllers) { } return this.sce.trustAsHtml(coloredString) } - - + + /** * Closes the detail view */ closeDetailView(clear) { if (clear) this.scope.appliedFilters = this.scope.appliedFilters.slice(0, this.scope.appliedFilters.length - 1) this.scope.viewingDetail = false - (this.view === 'ruleset') ? this.scope.currentRule = false : this.scope.currentDecoder = false + (this.view === 'ruleset') ? this.scope.currentRule = false : this.scope.currentDecoder = false if (!this.scope.$$phase) this.scope.$digest() } - - + + /** * Searches a rule * @param {String} term @@ -125,7 +154,7 @@ define(['../../module'], function (controllers) { } return } - + /** * Gets a filter by name * @param {String} filterName @@ -135,7 +164,7 @@ define(['../../module'], function (controllers) { const filtered = this.scope.appliedFilters.filter(item => item.name === filterName) return filtered.length ? filtered[0].value : '' } - + /** * Removes a filter by name * @param {String} filterName @@ -158,7 +187,7 @@ define(['../../module'], function (controllers) { this.toast('Error removing the filter') } } - + /** * Checks if a filter contains the passed string * @param {String} filterName @@ -168,6 +197,6 @@ define(['../../module'], function (controllers) { return this.scope.appliedFilters.map(item => item.name).includes(filterName) } } - controllers.controller('managerRulesetCtrl', Ruleset) + app.controller('managerRulesetCtrl', Ruleset) return Ruleset })