Code quality(eslint, mocha, tslint)

This commit is contained in:
Jesús Ángel 2018-09-03 11:46:55 +02:00
parent 513b134c0a
commit 9dd02ea153
52 changed files with 619 additions and 687 deletions

View File

@ -11,17 +11,19 @@
"jsx": true "jsx": true
} }
}, },
"globals": {
"XPACK_RBAC_ENABLED": true
},
"parser": "babel-eslint", "parser": "babel-eslint",
"rules": { "rules": {
"node/exports-style": ["error", "module.exports"], "node/exports-style": ["error", "module.exports"],
"semi": 0, "no-console": "warn",
"no-console": 0, "semi": "off",
"no-process-exit": 0, "no-process-exit": "error",
"no-extra-boolean-cast": "off",
"node/no-unpublished-require": 0, "node/no-unpublished-require": 0,
"node/no-unsupported-features": 0, "node/no-unsupported-features": 0,
"node/no-unsupported-features/es-syntax": 0, "node/no-unsupported-features/es-syntax": 0
"no-extra-boolean-cast": 0,
"no-cond-assign": 0
}, },
"plugins": ["node", "async-await"], "plugins": ["node", "async-await"],
"extends": ["eslint:recommended", "plugin:node/recommended"] "extends": ["eslint:recommended", "plugin:node/recommended"]

2
.tslint.yml Normal file
View File

@ -0,0 +1,2 @@
extends:
- tslint:recommended

View File

@ -11,7 +11,7 @@
*/ */
// Imports the init module // Imports the init module
import init from './init'; import { initApp } from './init';
export default kibana => new kibana.Plugin({ export default kibana => new kibana.Plugin({
id: 'wazuh', id: 'wazuh',
@ -26,6 +26,5 @@ export default kibana => new kibana.Plugin({
main: 'plugins/wazuh/app' main: 'plugins/wazuh/app'
} }
}, },
init: (server,options) => init(server,options) init(server,options) { return initApp(server,options) }
});
});

28
init.js
View File

@ -11,18 +11,18 @@
*/ */
// Imports all server modules // Imports all server modules
import initialize from './server/initialize'; import { Initialize } from './server/initialize';
import wazuhElastic from './server/routes/wazuh-elastic'; import { WazuhElasticRouter } from './server/routes/wazuh-elastic';
import wazuhApiElastic from './server/routes/wazuh-api-elastic'; import { WazuhApiElasticRoutes } from './server/routes/wazuh-api-elastic';
import monitoring from './server/monitoring'; import { Monitoring } from './server/monitoring';
import wazuhApi from './server/routes/wazuh-api'; import { WazuhApiRoutes } from './server/routes/wazuh-api';
import wazuhReporting from './server/routes/wazuh-reporting'; import { WazuhReportingRoutes } from './server/routes/wazuh-reporting';
export default (server, options) => { export function initApp (server) {
initialize(server, options); Initialize(server);
wazuhElastic(server, options); WazuhElasticRouter(server);
wazuhApiElastic(server, options); WazuhApiElasticRoutes(server);
monitoring(server, false); Monitoring(server, false);
wazuhApi(server, options); WazuhApiRoutes(server);
wazuhReporting(server, options); WazuhReportingRoutes(server);
}; }

View File

@ -26,9 +26,11 @@
}, },
"homepage": "https://www.wazuh.com/", "homepage": "https://www.wazuh.com/",
"scripts": { "scripts": {
"tslint": "tslint -c .tslint.yml server/**/*.ts server/**/*.tsx public/**/*.ts public/**/*.tsx",
"lint": "eslint server/** server/*.js *.js public/**/*.js public/*.js util/*.js -c .eslintrc.json --color", "lint": "eslint server/** server/*.js *.js public/**/*.js public/*.js util/*.js -c .eslintrc.json --color",
"prebuild": "tsc; find . -name \"*.ts*\" -type f -not -path \"./node_modules/*\" -delete", "prebuild": "tsc; find . -name \"*.ts*\" -type f -not -path \"./node_modules/*\" -delete",
"build": "plugin-helpers build" "build": "plugin-helpers build",
"test": "_mocha test/**/*"
}, },
"dependencies": { "dependencies": {
"angular-animate": "1.6.5", "angular-animate": "1.6.5",
@ -53,6 +55,8 @@
"eslint-plugin-async-await": "^0.0.0", "eslint-plugin-async-await": "^0.0.0",
"eslint-plugin-import": "^2.14.0", "eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1", "eslint-plugin-node": "^7.0.1",
"mocha": "^5.2.0",
"chai": "^3.5.0",
"tslint": "^5.11.0", "tslint": "^5.11.0",
"typescript": "^3.0.1", "typescript": "^3.0.1",
"typescript-eslint-parser": "^18.0.0" "typescript-eslint-parser": "^18.0.0"

View File

@ -80,12 +80,12 @@ app.controller('agentsPreviewController', function ($scope, $routeParams, generi
genericReq.request('GET', '/api/wazuh-api/agents-unique/' + api, {}), genericReq.request('GET', '/api/wazuh-api/agents-unique/' + api, {}),
genericReq.request('GET', `/api/wazuh-elastic/top/${firstUrlParam}/${secondUrlParam}/agent.name/${pattern}`) genericReq.request('GET', `/api/wazuh-elastic/top/${firstUrlParam}/${secondUrlParam}/agent.name/${pattern}`)
]); ]);
const [agentsUnique,agentsTop] = data;
const unique = data[0].data.result; const unique = agentsUnique.data.result;
$scope.groups = unique.groups; $scope.groups = unique.groups;
$scope.nodes = unique.nodes.map(item => { return {id: item} }); $scope.nodes = unique.nodes.map(item => ({id: item}));
$scope.versions = unique.versions.map(item => { return {id: item} }); $scope.versions = unique.versions.map(item => ({id: item}));
$scope.osPlatforms = unique.osPlatforms; $scope.osPlatforms = unique.osPlatforms;
$scope.lastAgent = unique.lastAgent; $scope.lastAgent = unique.lastAgent;
$scope.agentsCountActive = unique.summary.agentsCountActive; $scope.agentsCountActive = unique.summary.agentsCountActive;
@ -94,11 +94,11 @@ app.controller('agentsPreviewController', function ($scope, $routeParams, generi
$scope.agentsCountTotal = unique.summary.agentsCountTotal; $scope.agentsCountTotal = unique.summary.agentsCountTotal;
$scope.agentsCoverity = unique.summary.agentsCoverity; $scope.agentsCoverity = unique.summary.agentsCoverity;
if (data[1].data.data === '') { if (agentsTop.data.data === '') {
$scope.mostActiveAgent.name = appState.getClusterInfo().manager; $scope.mostActiveAgent.name = appState.getClusterInfo().manager;
$scope.mostActiveAgent.id = '000'; $scope.mostActiveAgent.id = '000';
} else { } else {
$scope.mostActiveAgent.name = data[1].data.data; $scope.mostActiveAgent.name = agentsTop.data.data;
const info = await genericReq.request('GET', `/api/wazuh-elastic/top/${firstUrlParam}/${secondUrlParam}/agent.id/${pattern}`); const info = await genericReq.request('GET', `/api/wazuh-elastic/top/${firstUrlParam}/${secondUrlParam}/agent.id/${pattern}`);
if (info.data.data === '' && $scope.mostActiveAgent.name !== '') { if (info.data.data === '' && $scope.mostActiveAgent.name !== '') {
$scope.mostActiveAgent.id = '000'; $scope.mostActiveAgent.id = '000';

View File

@ -9,13 +9,13 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import beautifier from '../../utils/json-beautifier'; import beautifier from '../../utils/json-beautifier';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import FilterHandler from '../../utils/filter-handler'; import { FilterHandler } from '../../utils/filter-handler';
import generateMetric from '../../utils/generate-metric'; import generateMetric from '../../utils/generate-metric';
import TabNames from '../../utils/tab-names'; import TabNames from '../../utils/tab-names';
import * as FileSaver from '../../services/file-saver'; import * as FileSaver from '../../services/file-saver';
import TabDescription from '../../../server/reporting/tab-description'; import TabDescription from '../../../server/reporting/tab-description';
import { import {
metricsAudit, metricsAudit,

View File

@ -95,7 +95,7 @@ class Logs {
try{ try{
const data = await this.apiReq.request('GET', '/manager/logs/summary', {}); const data = await this.apiReq.request('GET', '/manager/logs/summary', {});
const daemons = data.data.data; const daemons = data.data.data;
this.$scope.daemons = Object.keys(daemons).map(item => { return { title: item } }) this.$scope.daemons = Object.keys(daemons).map(item => ({ title: item }))
if(!this.$scope.$$phase) this.$scope.$digest(); if(!this.$scope.$$phase) this.$scope.$digest();
return; return;
} catch (error) { } catch (error) {

View File

@ -9,8 +9,8 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import FilterHandler from '../../utils/filter-handler' import { FilterHandler } from '../../utils/filter-handler'
import { uiModules } from 'ui/modules' import { uiModules } from 'ui/modules'
const app = uiModules.get('app/wazuh', []); const app = uiModules.get('app/wazuh', []);

View File

@ -50,23 +50,27 @@ class StatusController {
this.apiReq.request('GET', '/rules', { offset: 0, limit: 1 }), this.apiReq.request('GET', '/rules', { offset: 0, limit: 1 }),
this.apiReq.request('GET', '/decoders', { offset: 0, limit: 1 }) this.apiReq.request('GET', '/decoders', { offset: 0, limit: 1 })
]) ])
const parsedData = data.map(item => item.data.data);
const [stats, daemons, managerInfo, totalRules, totalDecoders] = parsedData;
// Once Wazuh core fixes agent 000 issues, this should be adjusted // Once Wazuh core fixes agent 000 issues, this should be adjusted
const active = data[0].data.data.Active - 1; const active = stats.Active - 1;
const total = data[0].data.data.Total - 1; const total = stats.Total - 1;
this.$scope.agentsCountActive = active; this.$scope.agentsCountActive = active;
this.$scope.agentsCountDisconnected = data[0].data.data.Disconnected; this.$scope.agentsCountDisconnected = stats.Disconnected;
this.$scope.agentsCountNeverConnected = data[0].data.data['Never connected']; this.$scope.agentsCountNeverConnected = stats['Never connected'];
this.$scope.agentsCountTotal = total; this.$scope.agentsCountTotal = total;
this.$scope.agentsCoverity = (active / total) * 100; this.$scope.agentsCoverity = (active / total) * 100;
this.$scope.daemons = data[1].data.data; this.$scope.daemons = daemons;
this.$scope.managerInfo = data[2].data.data; this.$scope.managerInfo = managerInfo;
this.$scope.totalRules = data[3].data.data.totalItems; this.$scope.totalRules = totalRules.totalItems;
this.$scope.totalDecoders = data[4].data.data.totalItems; this.$scope.totalDecoders = totalDecoders.totalItems;
const lastAgent = await this.apiReq.request('GET', '/agents', { limit: 1, sort: '-dateAdd' }); const lastAgentRaw = await this.apiReq.request('GET', '/agents', { limit: 1, sort: '-dateAdd' });
const agentInfo = await this.apiReq.request('GET', `/agents/${lastAgent.data.data.items[0].id}`, {}); const [lastAgent] = lastAgentRaw.data.data.items;
const agentInfo = await this.apiReq.request('GET', `/agents/${lastAgent.id}`, {});
this.$scope.agentInfo = agentInfo.data.data; this.$scope.agentInfo = agentInfo.data.data;
this.$scope.load = false; this.$scope.load = false;

View File

@ -9,14 +9,23 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import { uiModules } from 'ui/modules' import { uiModules } from 'ui/modules';
import FilterHandler from '../../utils/filter-handler' import { FilterHandler } from '../../utils/filter-handler';
import generateMetric from '../../utils/generate-metric' import generateMetric from '../../utils/generate-metric';
import TabNames from '../../utils/tab-names' import TabNames from '../../utils/tab-names';
import { metricsGeneral, metricsFim, metricsAudit, metricsVulnerability, metricsScap, metricsCiscat, metricsVirustotal, metricsAws } from '../../utils/overview-metrics'
import TabDescription from '../../../server/reporting/tab-description'; import TabDescription from '../../../server/reporting/tab-description';
import {
metricsGeneral,
metricsFim,
metricsAudit,
metricsVulnerability,
metricsScap,
metricsCiscat,
metricsVirustotal,
metricsAws
} from '../../utils/overview-metrics'
const app = uiModules.get('app/wazuh', []); const app = uiModules.get('app/wazuh', []);
app.controller('overviewController', app.controller('overviewController',

View File

@ -17,7 +17,7 @@ app.directive('wzDynamic', function($compile) {
return { return {
restrict: 'A', restrict: 'A',
replace: true, replace: true,
link: function(scope, ele, attrs) { link(scope, ele, attrs) {
scope.$watch(attrs.wzDynamic, function(html) { scope.$watch(attrs.wzDynamic, function(html) {
ele.html(html); ele.html(html);
$compile(ele.contents())(scope); $compile(ele.contents())(scope);

View File

@ -29,7 +29,7 @@ app.directive('wzTable', function() {
rowSizes: '=rowSizes', rowSizes: '=rowSizes',
extraLimit: '=extraLimit' extraLimit: '=extraLimit'
}, },
controller: function($scope, apiReq, $timeout, shareAgent, $location, errorHandler, wzTableFilter, $window) { controller($scope, apiReq, $timeout, shareAgent, $location, errorHandler, wzTableFilter, $window) {
/** /**
* Calculate number of table rows depending on the screen height * Calculate number of table rows depending on the screen height
*/ */
@ -322,13 +322,13 @@ app.directive('wzTable', function() {
checkIfArray(item[key.value || key]) || '---'; checkIfArray(item[key.value || key]) || '---';
}; };
}, },
template: template template
} }
}) })
.service('wzTableFilter',() => { .service('wzTableFilter',() => {
const filters = []; const filters = [];
return { return {
set: array => { if(Array.isArray(array)) { filters.length = 0; filters.push(...array); } }, set (array) { if(Array.isArray(array)) { filters.length = 0; filters.push(...array); } },
get: () => filters get () { return filters }
}; };
}); });

View File

@ -69,14 +69,13 @@ import { BasicResponseHandlerProvider } from 'ui/vis/response_handlers/basic';
import { DocTitleProvider } from 'ui/doc_title'; import { DocTitleProvider } from 'ui/doc_title';
import PluginsKibanaDiscoverHitSortFnProvider from 'plugins/kibana/discover/_hit_sort_fn'; import PluginsKibanaDiscoverHitSortFnProvider from 'plugins/kibana/discover/_hit_sort_fn';
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter'; import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
import { intervalOptions } from 'ui/agg_types/buckets/_interval_options';
import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory'; import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery'; import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery';
import { FilterManagerProvider } from 'ui/filter_manager'; import { FilterManagerProvider } from 'ui/filter_manager';
import { visualizationLoader } from 'ui/visualize/loader/visualization_loader'; import { visualizationLoader } from 'ui/visualize/loader/visualization_loader';
import { getDocLink } from 'ui/documentation_links'; import { getDocLink } from 'ui/documentation_links';
import 'ui/courier/search_strategy/default_search_strategy' import 'ui/courier/search_strategy/default_search_strategy';
const app = uiModules.get('apps/discover', [ const app = uiModules.get('apps/discover', [
'kibana/notify', 'kibana/notify',
@ -413,7 +412,7 @@ $scope.toggleRefresh = () => {
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
$state.save(); $state.save();
}).catch(console.error); }).catch(console.error); // eslint-disable-line
}); });
// update data source when hitting forward/back and the query changes // update data source when hitting forward/back and the query changes
@ -689,7 +688,7 @@ $scope.toggleRefresh = () => {
const fields = _.keys(indexPattern.flattenHit(hit)); const fields = _.keys(indexPattern.flattenHit(hit));
let n = fields.length; let n = fields.length;
let field; let field;
while (field = fields[--n]) { while (field = fields[--n]) { // eslint-disable-line
if (counts[field]) counts[field] += 1; if (counts[field]) counts[field] += 1;
else counts[field] = 1; else counts[field] = 1;
} }
@ -921,7 +920,7 @@ $scope.toggleRefresh = () => {
queryFilter.addFilters(wzCurrentFilters) queryFilter.addFilters(wzCurrentFilters)
.then(() => { }) .then(() => { })
.catch(error => console.log(error.message || error)); .catch(error => console.log(error.message || error)); // eslint-disable-line
} }
}; };

View File

@ -9,20 +9,21 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import $ from 'jquery'; import $ from 'jquery';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { getVisualizeLoader } from './loader'; import { getVisualizeLoader } from './loader';
import { timefilter } from 'ui/timefilter' import { timefilter } from 'ui/timefilter';
const app = uiModules.get('apps/webinar_app', []); const app = uiModules.get('apps/webinar_app', []);
app.directive('kbnVis', [function () { app.directive('kbnVis', function () {
return { return {
restrict: 'E', restrict: 'E',
scope: { scope: {
visID: '=visId', visID: '=visId',
specificTimeRange: '=specificTimeRange' specificTimeRange: '=specificTimeRange'
}, },
controller: function VisController($scope, $rootScope, wzsavedVisualizations, errorHandler, rawVisualizations, loadedVisualizations, tabVisualizations, discoverPendingUpdates, visHandlers) { controller($scope, $rootScope, wzsavedVisualizations, errorHandler, rawVisualizations, loadedVisualizations, tabVisualizations, discoverPendingUpdates, visHandlers) {
let implicitFilter = ''; let implicitFilter = '';
let rawFilters = []; let rawFilters = [];
@ -132,7 +133,7 @@ app.directive('kbnVis', [function () {
$rootScope.rendered = thereIsData; $rootScope.rendered = thereIsData;
if(!thereIsData) $rootScope.resultState = 'none'; if(!thereIsData) $rootScope.resultState = 'none';
else $rootScope.resultState = 'ready'; else $rootScope.resultState = 'ready';
} }
// Forcing a digest cycle // Forcing a digest cycle
if(!$rootScope.$$phase) $rootScope.$digest(); if(!$rootScope.$$phase) $rootScope.$digest();
} }
@ -143,4 +144,4 @@ app.directive('kbnVis', [function () {
let loader = null; let loader = null;
} }
}; };
}]); });

View File

@ -2,7 +2,7 @@ import _ from 'lodash'
import { Scanner } from 'ui/utils/scanner'; import { Scanner } from 'ui/utils/scanner';
import { StringUtils } from 'ui/utils/string_utils'; import { StringUtils } from 'ui/utils/string_utils';
import { SavedObjectsClient } from 'ui/saved_objects'; import { SavedObjectsClient } from 'ui/saved_objects';
import { SavedObjectProvider } from './saved-objects';
export class SavedObjectLoader { export class SavedObjectLoader {
constructor(SavedObjectClass, kbnIndex, kbnUrl, $http, chrome ) { constructor(SavedObjectClass, kbnIndex, kbnUrl, $http, chrome ) {
this.type = SavedObjectClass.type; this.type = SavedObjectClass.type;
@ -52,7 +52,7 @@ export class SavedObjectLoader {
// just assign the defaults and be done // just assign the defaults and be done
_.assign(instance, instance.defaults); _.assign(instance, instance.defaults);
return instance.hydrateIndexPattern().then(() => { return instance.hydrateIndexPattern().then(() => {
return afterESResp.call(instance); return afterESResp.call(instance); // eslint-disable-line
}); });
} }
return this.processFunc() return this.processFunc()

View File

@ -1,399 +0,0 @@
/**
* @name SavedObject
*
* NOTE: SavedObject seems to track a reference to an object in ES,
* and surface methods for CRUD functionality (save and delete). This seems
* similar to how Backbone Models work.
*
* This class seems to interface with ES primarily through the es Angular
* service and the saved object api.
*/
import angular from 'angular';
import _ from 'lodash';
import { SavedObjectNotFound } from 'ui/errors';
import MappingSetupProvider from 'ui/utils/mapping_setup';
import { SearchSourceProvider } from 'ui/courier';
import { SavedObjectsClientProvider, findObjectByTitle } from 'ui/saved_objects';
import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery.js';
import { recentlyAccessed } from 'ui/persisted_log';
/**
* An error message to be used when the user rejects a confirm overwrite.
* @type {string}
*/
const OVERWRITE_REJECTED = 'Overwrite confirmation was rejected';
/**
* An error message to be used when the user rejects a confirm save with duplicate title.
* @type {string}
*/
const SAVE_DUPLICATE_REJECTED = 'Save with duplicate title confirmation was rejected';
/**
* @param error {Error} the error
* @return {boolean}
*/
function isErrorNonFatal(error) {
if (!error) return false;
return error.message === OVERWRITE_REJECTED || error.message === SAVE_DUPLICATE_REJECTED;
}
export function SavedObjectProvider(Promise, Private, Notifier, confirmModalPromise, indexPatterns) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
const SearchSource = Private(SearchSourceProvider);
const mappingSetup = Private(MappingSetupProvider);
function SavedObject(config) {
if (!_.isObject(config)) config = {};
/************
* Initialize config vars
************/
// type name for this object, used as the ES-type
const esType = config.type;
this.getDisplayName = function () {
return esType;
};
// NOTE: this.type (not set in this file, but somewhere else) is the sub type, e.g. 'area' or
// 'data table', while esType is the more generic type - e.g. 'visualization' or 'saved search'.
this.getEsType = function () {
return esType;
};
/**
* Flips to true during a save operation, and back to false once the save operation
* completes.
* @type {boolean}
*/
this.isSaving = false;
this.defaults = config.defaults || {};
// mapping definition for the fields that this object will expose
const mapping = mappingSetup.expandShorthand(config.mapping);
const afterESResp = config.afterESResp || _.noop;
const customInit = config.init || _.noop;
// optional search source which this object configures
this.searchSource = config.searchSource ? new SearchSource() : undefined;
// the id of the document
this.id = config.id || void 0;
// Whether to create a copy when the object is saved. This should eventually go away
// in favor of a better rename/save flow.
this.copyOnSave = false;
const parseSearchSource = (searchSourceJson) => {
if (!this.searchSource) return;
// if we have a searchSource, set its values based on the searchSourceJson field
let searchSourceValues;
try {
searchSourceValues = JSON.parse(searchSourceJson);
} catch (e) {
searchSourceValues = {};
}
const searchSourceFields = this.searchSource.getFields();
const fnProps = _.transform(searchSourceFields, function (dynamic, val, name) {
if (_.isFunction(val)) dynamic[name] = val;
}, {});
this.searchSource.setFields(_.defaults(searchSourceValues, fnProps));
if (!_.isUndefined(this.searchSource.getOwnField('query'))) {
this.searchSource.setField('query', migrateLegacyQuery(this.searchSource.getOwnField('query')));
}
};
/**
* After creation or fetching from ES, ensure that the searchSources index indexPattern
* is an bonafide IndexPattern object.
*
* @return {Promise<IndexPattern | null>}
*/
this.hydrateIndexPattern = (id) => {
if (!this.searchSource) {
return Promise.resolve(null);
}
if (config.clearSavedIndexPattern) {
this.searchSource.setField('index', null);
return Promise.resolve(null);
}
let index = id || config.indexPattern || this.searchSource.getOwnField('index');
if (!index) {
return Promise.resolve(null);
}
// If index is not an IndexPattern object at this point, then it's a string id of an index.
if (!(index instanceof indexPatterns.IndexPattern)) {
index = indexPatterns.get(index);
}
// At this point index will either be an IndexPattern, if cached, or a promise that
// will return an IndexPattern, if not cached.
return Promise.resolve(index).then(indexPattern => {
this.searchSource.setField('index', indexPattern);
});
};
/**
* Asynchronously initialize this object - will only run
* once even if called multiple times.
*
* @return {Promise}
* @resolved {SavedObject}
*/
this.init = _.once(() => {
// ensure that the esType is defined
if (!esType) throw new Error('You must define a type name to use SavedObject objects.');
return Promise.resolve()
.then(() => {
// If there is not id, then there is no document to fetch from elasticsearch
if (!this.id) {
// just assign the defaults and be done
_.assign(this, this.defaults);
return this.hydrateIndexPattern().then(() => {
return afterESResp.call(this);
});
}
// fetch the object from ES
return savedObjectsClient.get(esType, this.id)
.then(resp => {
// temporary compatability for savedObjectsClient
return {
_id: resp.id,
_type: resp.type,
_source: _.cloneDeep(resp.attributes),
found: resp._version ? true : false
};
})
.then(this.applyESResp)
.catch(this.applyEsResp);
})
.then(() => customInit.call(this))
.then(() => this);
});
this.applyESResp = (resp) => {
this._source = _.cloneDeep(resp._source);
if (resp.found != null && !resp.found) {
throw new SavedObjectNotFound(esType, this.id);
}
const meta = resp._source.kibanaSavedObjectMeta || {};
delete resp._source.kibanaSavedObjectMeta;
if (!config.indexPattern && this._source.indexPattern) {
config.indexPattern = this._source.indexPattern;
delete this._source.indexPattern;
}
// assign the defaults to the response
_.defaults(this._source, this.defaults);
// transform the source using _deserializers
_.forOwn(mapping, (fieldMapping, fieldName) => {
if (fieldMapping._deserialize) {
this._source[fieldName] = fieldMapping._deserialize(this._source[fieldName], resp, fieldName, fieldMapping);
}
});
// Give obj all of the values in _source.fields
_.assign(this, this._source);
this.lastSavedTitle = this.title;
return Promise.try(() => {
parseSearchSource(meta.searchSourceJSON);
return this.hydrateIndexPattern();
}).then(() => {
return Promise.cast(afterESResp.call(this, resp));
});
};
/**
* Serialize this object
*
* @return {Object}
*/
this.serialize = () => {
const body = {};
_.forOwn(mapping, (fieldMapping, fieldName) => {
if (this[fieldName] != null) {
body[fieldName] = (fieldMapping._serialize)
? fieldMapping._serialize(this[fieldName])
: this[fieldName];
}
});
if (this.searchSource) {
const searchSourceFields = _.omit(this.searchSource.getFields(), ['sort', 'size']);
body.kibanaSavedObjectMeta = {
searchSourceJSON: angular.toJson(searchSourceFields)
};
}
return body;
};
/**
* Returns true if the object's original title has been changed. New objects return false.
* @return {boolean}
*/
this.isTitleChanged = () => {
return this._source && this._source.title !== this.title;
};
/**
* Attempts to create the current object using the serialized source. If an object already
* exists, a warning message requests an overwrite confirmation.
* @param source - serialized version of this object (return value from this.serialize())
* What will be indexed into elasticsearch.
* @returns {Promise} - A promise that is resolved with the objects id if the object is
* successfully indexed. If the overwrite confirmation was rejected, an error is thrown with
* a confirmRejected = true parameter so that case can be handled differently than
* a create or index error.
* @resolved {SavedObject}
*/
const createSource = (source) => {
return savedObjectsClient.create(esType, source, { id: this.id })
.catch(err => {
// record exists, confirm overwriting
if (_.get(err, 'res.status') === 409) {
const confirmMessage = `Are you sure you want to overwrite ${this.title}?`;
return confirmModalPromise(confirmMessage, { confirmButtonText: `Overwrite ${this.getDisplayName()}` })
.then(() => savedObjectsClient.create(esType, source, { id: this.id, overwrite: true }))
.catch(() => Promise.reject(new Error(OVERWRITE_REJECTED)));
}
return Promise.reject(err);
});
};
const displayDuplicateTitleConfirmModal = () => {
const confirmMessage =
`A ${this.getDisplayName()} with the title '${this.title}' already exists. Would you like to save anyway?`;
return confirmModalPromise(confirmMessage, { confirmButtonText: `Save ${this.getDisplayName()}` })
.catch(() => Promise.reject(new Error(SAVE_DUPLICATE_REJECTED)));
};
const checkForDuplicateTitle = (isTitleDuplicateConfirmed, onTitleDuplicate) => {
// Don't check for duplicates if user has already confirmed save with duplicate title
if (isTitleDuplicateConfirmed) {
return Promise.resolve();
}
// Don't check if the user isn't updating the title, otherwise that would become very annoying to have
// to confirm the save every time, except when copyOnSave is true, then we do want to check.
if (this.title === this.lastSavedTitle && !this.copyOnSave) {
return Promise.resolve();
}
return findObjectByTitle(savedObjectsClient, this.getEsType(), this.title)
.then(duplicate => {
if (!duplicate) return true;
if (duplicate.id === this.id) return true;
if (onTitleDuplicate) {
onTitleDuplicate();
return Promise.reject(new Error(SAVE_DUPLICATE_REJECTED));
}
// TODO: make onTitleDuplicate a required prop and remove UI components from this class
// Need to leave here until all users pass onTitleDuplicate.
return displayDuplicateTitleConfirmModal();
});
};
/**
* Saves this object.
*
* @param {object} [options={}]
* @property {boolean} [options.confirmOverwrite=false] - If true, attempts to create the source so it
* can confirm an overwrite if a document with the id already exists.
* @property {boolean} [options.isTitleDuplicateConfirmed=false] - If true, save allowed with duplicate title
* @property {func} [options.onTitleDuplicate] - function called if duplicate title exists.
* When not provided, confirm modal will be displayed asking user to confirm or cancel save.
* @return {Promise}
* @resolved {String} - The id of the doc
*/
this.save = ({ confirmOverwrite = false, isTitleDuplicateConfirmed = false, onTitleDuplicate } = {}) => {
// Save the original id in case the save fails.
const originalId = this.id;
// Read https://github.com/elastic/kibana/issues/9056 and
// https://github.com/elastic/kibana/issues/9012 for some background into why this copyOnSave variable
// exists.
// The goal is to move towards a better rename flow, but since our users have been conditioned
// to expect a 'save as' flow during a rename, we are keeping the logic the same until a better
// UI/UX can be worked out.
if (this.copyOnSave) {
this.id = null;
}
const source = this.serialize();
this.isSaving = true;
return checkForDuplicateTitle(isTitleDuplicateConfirmed, onTitleDuplicate)
.then(() => {
if (confirmOverwrite) {
return createSource(source);
} else {
return savedObjectsClient.create(esType, source, { id: this.id, overwrite: true });
}
})
.then((resp) => {
this.id = resp.id;
})
.then(() => {
if (this.showInRecentlyAccessed && this.getFullPath) {
recentlyAccessed.add(this.getFullPath(), this.title, this.id);
}
this.isSaving = false;
this.lastSavedTitle = this.title;
return this.id;
})
.catch((err) => {
this.isSaving = false;
this.id = originalId;
if (isErrorNonFatal(err)) {
return;
}
return Promise.reject(err);
});
};
this.destroy = () => {
if (this.searchSource) {
this.searchSource.cancelQueued();
}
};
/**
* Delete this object from Elasticsearch
* @return {promise}
*/
this.delete = () => {
return savedObjectsClient.delete(esType, this.id);
};
}
return SavedObject;
}

View File

@ -1,3 +1,4 @@
/* eslint-disable */
/* FileSaver.js /* FileSaver.js
* A saveAs() FileSaver implementation. * A saveAs() FileSaver implementation.
* 1.3.8 * 1.3.8

View File

@ -18,20 +18,20 @@ app
.service('regionmapsConfig', function () { .service('regionmapsConfig', function () {
return { return {
// Intended noop function and empty array // Intended noop function and empty array
noop: () => {}, noop() {},
layers: [] layers: []
} }
}) })
.service('mapConfig', function () { .service('mapConfig', function () {
return { return {
// Intended noop function // Intended noop function
noop: () => {} noop() {}
} }
}) })
.service('tilemapsConfig', function () { .service('tilemapsConfig', function () {
return { return {
// Intended noop function and false properties // Intended noop function and false properties
noop: () => {}, noop() {},
deprecated: { deprecated: {
config: { config: {
options: false options: false

View File

@ -1,7 +1,7 @@
export default { export default {
encode: text => { encode: text => {
const textRegex = /([^\u0000-\u00ff])/; // eslint-disable-line
if (/([^\u0000-\u00ff])/.test(text)){ if (textRegex.test(text)){
throw new Error("Can't base64 encode non-ASCII characters."); throw new Error("Can't base64 encode non-ASCII characters.");
} }
@ -46,8 +46,8 @@ export default {
decode: text => { decode: text => {
text = text.replace(/\s/g,""); text = text.replace(/\s/g,"");
const textRegex = /^[a-z0-9\-_\s]+\={0,2}$/i; // eslint-disable-line
if(!(/^[a-z0-9\-_\s]+\={0,2}$/i.test(text)) || text.length % 4 > 0){ if(!(textRegex.test(text)) || text.length % 4 > 0){
throw new Error("Not a base64-encoded string."); throw new Error("Not a base64-encoded string.");
} }

View File

@ -9,7 +9,7 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
export default class FilterHandler { export class FilterHandler {
constructor(pattern) { constructor(pattern) {
this.pattern = pattern; this.pattern = pattern;
} }
@ -36,7 +36,7 @@ export default class FilterHandler {
$state: { $state: {
store: 'appState' store: 'appState'
} }
} };
} }
agentQuery(agent) { agentQuery(agent) {
@ -110,7 +110,7 @@ export default class FilterHandler {
result.meta.key = 'rule.pci_dss'; result.meta.key = 'rule.pci_dss';
result.exists = { result.exists = {
field: 'rule.pci_dss' field: 'rule.pci_dss'
} };
delete result.query; delete result.query;
return result; return result;
} }
@ -122,7 +122,7 @@ export default class FilterHandler {
result.meta.key = 'rule.gdpr'; result.meta.key = 'rule.gdpr';
result.exists = { result.exists = {
field: 'rule.gdpr' field: 'rule.gdpr'
} };
delete result.query; delete result.query;
return result; return result;
} }

View File

@ -22,7 +22,7 @@ export default id => {
html.split('ng-non-bindable')[1].split('>')[1].split('</') && html.split('ng-non-bindable')[1].split('>')[1].split('</') &&
html.split('ng-non-bindable')[1].split('>')[1].split('</')[0]) { html.split('ng-non-bindable')[1].split('>')[1].split('</')[0]) {
return html.split('ng-non-bindable')[1].split('>')[1].split('</')[0] return html.split('ng-non-bindable')[1].split('>')[1].split('</')[0];
} }
@ -40,4 +40,4 @@ export default id => {
} }
} }
return ''; return '';
} };

View File

@ -18,7 +18,7 @@
* wazuh-reporting 50XX * wazuh-reporting 50XX
* unknown 1000 * unknown 1000
*/ */
export default (message = null, code = null, statusCode = null, reply) => { export function ErrorResponse (message = null, code = null, statusCode = null, reply) {
let filteredMessage = ''; let filteredMessage = '';
if(code) { if(code) {
const isString = typeof message === 'string'; const isString = typeof message === 'string';
@ -48,4 +48,4 @@ export default (message = null, code = null, statusCode = null, reply) => {
statusCode: statusCode ? statusCode : 500 statusCode: statusCode ? statusCode : 500
}) })
.code(statusCode ? statusCode : 500); .code(statusCode ? statusCode : 500);
}; }

View File

@ -9,9 +9,9 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import WazuhElastic from './wazuh-elastic'; import { WazuhElasticCtrl } from './wazuh-elastic';
import WazuhApiElastic from './wazuh-api-elastic'; import { WazuhApiElasticCtrl } from './wazuh-api-elastic';
import WazuhApi from './wazuh-api'; import { WazuhApiCtrl } from './wazuh-api';
import WazuhReportingCtrl from './wazuh-reporting'; import { WazuhReportingCtrl } from './wazuh-reporting';
export { WazuhElastic, WazuhApiElastic, WazuhApi, WazuhReportingCtrl }; export { WazuhElasticCtrl, WazuhApiElasticCtrl, WazuhApiCtrl, WazuhReportingCtrl };

View File

@ -10,9 +10,9 @@
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import ErrorResponse from './error-response'; import { ErrorResponse } from './error-response';
import log from '../logger'; import { log } from '../logger';
const userRegEx = new RegExp(/^.{3,100}$/); const userRegEx = new RegExp(/^.{3,100}$/);
const passRegEx = new RegExp(/^.{3,100}$/); const passRegEx = new RegExp(/^.{3,100}$/);
@ -20,7 +20,7 @@ const urlRegEx = new RegExp(/^https?:\/\/[a-zA-Z0-9-.]{1,300}$/);
const urlRegExIP = new RegExp(/^https?:\/\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/); const urlRegExIP = new RegExp(/^https?:\/\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/);
const portRegEx = new RegExp(/^[0-9]{2,5}$/); const portRegEx = new RegExp(/^[0-9]{2,5}$/);
export default class WazuhApiElastic { export class WazuhApiElasticCtrl {
constructor(server) { constructor(server) {
this.wzWrapper = new ElasticWrapper(server); this.wzWrapper = new ElasticWrapper(server);
} }

View File

@ -14,23 +14,23 @@
import needle from 'needle'; import needle from 'needle';
import pciRequirementsFile from '../integration-files/pci-requirements'; import pciRequirementsFile from '../integration-files/pci-requirements';
import gdprRequirementsFile from '../integration-files/gdpr-requirements'; import gdprRequirementsFile from '../integration-files/gdpr-requirements';
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import getPath from '../../util/get-path'; import { getPath } from '../../util/get-path';
import packageInfo from '../../package.json'; import packageInfo from '../../package.json';
import monitoring from '../monitoring'; import { Monitoring } from '../monitoring';
import ErrorResponse from './error-response'; import { ErrorResponse } from './error-response';
import { Parser } from 'json2csv'; import { Parser } from 'json2csv';
import getConfiguration from '../lib/get-configuration'; import { getConfiguration } from '../lib/get-configuration';
import { totalmem } from 'os'; import { totalmem } from 'os';
import simpleTail from 'simple-tail'; import simpleTail from 'simple-tail';
import path from 'path'; import path from 'path';
import log from '../logger'; import { log } from '../logger';
import CsvKeys from '../../util/csv-key-equivalence'; import CsvKeys from '../../util/csv-key-equivalence';
export default class WazuhApi { export class WazuhApiCtrl {
constructor(server){ constructor(server){
this.wzWrapper = new ElasticWrapper(server); this.wzWrapper = new ElasticWrapper(server);
this.fetchAgentsExternal = monitoring(server,{disableCron:true}) this.fetchAgentsExternal = Monitoring(server,{disableCron:true})
} }
async checkStoredAPI (req, reply) { async checkStoredAPI (req, reply) {

View File

@ -9,9 +9,9 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import ErrorResponse from './error-response'; import { ErrorResponse } from './error-response';
import log from '../logger'; import { log } from '../logger';
import { import {
AgentsVisualizations, AgentsVisualizations,
@ -20,7 +20,7 @@ import {
} from '../integration-files/visualizations'; } from '../integration-files/visualizations';
export default class WazuhElastic { export class WazuhElasticCtrl {
constructor(server){ constructor(server){
this.wzWrapper = new ElasticWrapper(server); this.wzWrapper = new ElasticWrapper(server);
} }

View File

@ -9,31 +9,35 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import descriptions from '../reporting/tab-description'; import descriptions from '../reporting/tab-description';
import * as TimSort from 'timsort'; import * as TimSort from 'timsort';
import rawParser from '../reporting/raw-parser'; import rawParser from '../reporting/raw-parser';
import PdfPrinter from 'pdfmake/src/printer'; import PdfPrinter from 'pdfmake/src/printer';
import ErrorResponse from './error-response'; import { ErrorResponse } from './error-response';
import VulnerabilityRequest from '../reporting/vulnerability-request'; import { VulnerabilityRequest } from '../reporting/vulnerability-request';
import OverviewRequest from '../reporting/overview-request'; import { OverviewRequest } from '../reporting/overview-request';
import RootcheckRequest from '../reporting/rootcheck-request'; import { RootcheckRequest } from '../reporting/rootcheck-request';
import PciRequest from '../reporting/pci-request'; import { PciRequest } from '../reporting/pci-request';
import GdprRequest from '../reporting/gdpr-request'; import { GdprRequest } from '../reporting/gdpr-request';
import AuditRequest from '../reporting/audit-request'; import { AuditRequest } from '../reporting/audit-request';
import SyscheckRequest from '../reporting/syscheck-request'; import { SyscheckRequest } from '../reporting/syscheck-request';
import PCI from '../integration-files/pci-requirements-pdfmake'; import PCI from '../integration-files/pci-requirements-pdfmake';
import GDPR from '../integration-files/gdpr-requirements-pdfmake'; import GDPR from '../integration-files/gdpr-requirements-pdfmake';
import PdfTable from '../reporting/generic-table'; import PdfTable from '../reporting/generic-table';
import WazuhApi from './wazuh-api'; import { WazuhApiCtrl } from './wazuh-api';
import clockIconRaw from '../reporting/clock-icon-raw'; import clockIconRaw from '../reporting/clock-icon-raw';
import filterIconRaw from '../reporting/filter-icon-raw'; import filterIconRaw from '../reporting/filter-icon-raw';
import { AgentsVisualizations, OverviewVisualizations } from '../integration-files/visualizations';
import {
AgentsVisualizations,
OverviewVisualizations
} from '../integration-files/visualizations';
const REPORTING_PATH = '../../../../optimize/wazuh-reporting'; const REPORTING_PATH = '../../../../optimize/wazuh-reporting';
export default class WazuhReportingCtrl { export class WazuhReportingCtrl {
constructor(server) { constructor(server) {
this.server = server; this.server = server;
this.fonts = { this.fonts = {
@ -103,7 +107,7 @@ export default class WazuhReportingCtrl {
content: [ content: [
], ],
footer: function (currentPage, pageCount) { footer (currentPage, pageCount) {
return { return {
columns: [ columns: [
{ {
@ -115,7 +119,7 @@ export default class WazuhReportingCtrl {
] ]
}; };
}, },
pageBreakBefore: function (currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) { pageBreakBefore (currentNode, followingNodesOnPage) {
if (currentNode.id && currentNode.id.includes('splitvis')) { if (currentNode.id && currentNode.id.includes('splitvis')) {
return followingNodesOnPage.length === 6 || followingNodesOnPage.length === 7; return followingNodesOnPage.length === 6 || followingNodesOnPage.length === 7;
} }
@ -129,7 +133,7 @@ export default class WazuhReportingCtrl {
} }
}; };
this.apiRequest = new WazuhApi(server); this.apiRequest = new WazuhApiCtrl(server);
} }
renderTables(tables) { renderTables(tables) {
@ -151,19 +155,14 @@ export default class WazuhReportingCtrl {
const modifiedRows = []; const modifiedRows = [];
for (const row of rows) { for (const row of rows) {
modifiedRows.push(row.map(cell => { modifiedRows.push(row.map(cell => ({ text: cell, style: 'standard' })));
return { text: cell, style: 'standard' };
}));
} }
const widths = Array(table.columns.length - 1).fill('auto'); const widths = Array(table.columns.length - 1).fill('auto');
widths.push('*'); widths.push('*');
full_body.push( full_body.push(
table.columns.map(col => { table.columns.map(col => ({ text: col, style: 'whiteColor', border: [0, 0, 0, 0]})), ...modifiedRows);
return { text: col, style: 'whiteColor', border: [0, 0, 0, 0] };
})
, ...modifiedRows);
this.dd.content.push({ this.dd.content.push({
fontSize: 8, fontSize: 8,
table: { table: {
@ -586,7 +585,7 @@ export default class WazuhReportingCtrl {
if (section === 'agents' && tab === 'pm') { if (section === 'agents' && tab === 'pm') {
const database = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}`, { limit: 15 }, apiId); const database = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}`, { limit: 15 }, apiId);
const cis = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}/cis`, {}, apiId); //const cis = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}/cis`, {}, apiId);
const pci = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}/pci`, {}, apiId); const pci = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}/pci`, {}, apiId);
const lastScan = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}/last_scan`, {}, apiId); const lastScan = await this.apiRequest.makeGenericRequest('GET', `/rootcheck/${agent}/last_scan`, {}, apiId);
@ -727,7 +726,7 @@ export default class WazuhReportingCtrl {
for (const critical of topCriticalPackages) { for (const critical of topCriticalPackages) {
customul.push({ text: critical.package, style: 'standard' }); customul.push({ text: critical.package, style: 'standard' });
customul.push({ customul.push({
ul: critical.references.map(item => { return { text: item, color: '#1EA5C8' }; }) ul: critical.references.map(item => ({ text: item, color: '#1EA5C8' }))
}); });
} }
this.dd.content.push({ ul: customul }) this.dd.content.push({ ul: customul })
@ -744,7 +743,7 @@ export default class WazuhReportingCtrl {
for (const critical of topHighPackages) { for (const critical of topHighPackages) {
customul.push({ text: critical.package, style: 'standard' }); customul.push({ text: critical.package, style: 'standard' });
customul.push({ customul.push({
ul: critical.references.map(item => { return { text: item, color: '#1EA5C8' }; }) ul: critical.references.map(item => ({ text: item, color: '#1EA5C8' }))
}); });
} }
customul && customul.length && this.dd.content.push({ ul: customul }); customul && customul.length && this.dd.content.push({ ul: customul });

View File

@ -9,17 +9,17 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import needle from 'needle' import needle from 'needle'
import colors from 'ansicolors' import colors from 'ansicolors'
import log from './logger' import { log } from './logger'
import ElasticWrapper from './lib/elastic-wrapper' import { ElasticWrapper } from './lib/elastic-wrapper'
import packageJSON from '../package.json' import packageJSON from '../package.json'
import kibana_template from './integration-files/kibana-template' import kibana_template from './integration-files/kibana-template'
import getConfiguration from './lib/get-configuration' import { getConfiguration } from './lib/get-configuration'
import defaultExt from './lib/default-ext' import defaultExt from './lib/default-ext'
import { BuildBody } from './lib/replicas-shards-helper' import { BuildBody } from './lib/replicas-shards-helper'
export default (server, options) => { export function Initialize(server) {
const blueWazuh = colors.blue('wazuh'); const blueWazuh = colors.blue('wazuh');
// Elastic JS Client // Elastic JS Client
@ -674,4 +674,4 @@ export default (server, options) => {
// Check Kibana index and if it is prepared, start the initialization of Wazuh App. // Check Kibana index and if it is prepared, start the initialization of Wazuh App.
checkStatus(); checkStatus();
}; }

View File

@ -11,19 +11,19 @@
*/ */
export default [ export default [
{ {
"_id": "Wazuh-App-Agents-PCI-Requirements", "_id": "Wazuh-App-Agents-PCI-Requirements",
"_source": { "_source": {
"title": "Requirements", "title": "Requirements",
"visState": "{\"title\":\"Requirements\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"rotate\":0},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"rule.pci_dss\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"rule.pci_dss\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"PCI DSS Requirements\"}}]}", "visState": "{\"title\":\"Requirements\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"rotate\":0},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"rule.pci_dss\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"rule.pci_dss\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"PCI DSS Requirements\"}}]}",
"uiStateJSON": "{}", "uiStateJSON": "{}",
"description": "", "description": "",
"version": 1, "version": 1,
"kibanaSavedObjectMeta": { "kibanaSavedObjectMeta": {
"searchSourceJSON": "searchSourceJSON":
"{\"index\":\"wazuh-alerts\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" "{\"index\":\"wazuh-alerts\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
} }
}, },
"_type": "visualization" "_type": "visualization"
}, },
{ {
"_id": "Wazuh-App-Agents-PCI-Groups", "_id": "Wazuh-App-Agents-PCI-Groups",

View File

@ -14,28 +14,28 @@ export default [
"_id": "Wazuh-App-Cluster-Overview", "_id": "Wazuh-App-Cluster-Overview",
"_type": "visualization", "_type": "visualization",
"_source": { "_source": {
"title": "Wazuh App Cluster Overview", "title": "Wazuh App Cluster Overview",
"visState": "{\"title\":\"Wazuh App Cluster Overview\",\"type\":\"timelion\",\"params\":{\"expression\":\".es(*)\",\"interval\":\"auto\"},\"aggs\":[]}", "visState": "{\"title\":\"Wazuh App Cluster Overview\",\"type\":\"timelion\",\"params\":{\"expression\":\".es(*)\",\"interval\":\"auto\"},\"aggs\":[]}",
"uiStateJSON": "{}", "uiStateJSON": "{}",
"description": "", "description": "",
"version": 1, "version": 1,
"kibanaSavedObjectMeta": { "kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"wazuh-alerts\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" "searchSourceJSON": "{\"index\":\"wazuh-alerts\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
} }
} }
}, },
{ {
"_id": "Wazuh-App-Cluster-Overview-Manager", "_id": "Wazuh-App-Cluster-Overview-Manager",
"_type": "visualization", "_type": "visualization",
"_source": { "_source": {
"title": "Wazuh App Cluster Overview Manager", "title": "Wazuh App Cluster Overview Manager",
"visState": "{\"title\":\"Wazuh App Cluster Overview Manager\",\"type\":\"timelion\",\"params\":{\"expression\":\".es(q=agent.id:000)\",\"interval\":\"auto\"},\"aggs\":[]}", "visState": "{\"title\":\"Wazuh App Cluster Overview Manager\",\"type\":\"timelion\",\"params\":{\"expression\":\".es(q=agent.id:000)\",\"interval\":\"auto\"},\"aggs\":[]}",
"uiStateJSON": "{}", "uiStateJSON": "{}",
"description": "", "description": "",
"version": 1, "version": 1,
"kibanaSavedObjectMeta": { "kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"wazuh-alerts\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" "searchSourceJSON": "{\"index\":\"wazuh-alerts\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
} }
} }
}, },
{ {

View File

@ -13,14 +13,14 @@ export default [
{ {
"_id": "Wazuh-App-Overview-General-Agents-status", "_id": "Wazuh-App-Overview-General-Agents-status",
"_source": { "_source": {
"title": "Agents status", "title": "Agents status",
"visState": "{\"title\":\"Agents Status\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"normal\",\"type\":\"line\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"cardinal\",\"lineWidth\":3.5,\"data\":{\"id\":\"4\",\"label\":\"Unique count of id\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"h\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"status\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"_term\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"id\"}}]}", "visState": "{\"title\":\"Agents Status\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"normal\",\"type\":\"line\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"cardinal\",\"lineWidth\":3.5,\"data\":{\"id\":\"4\",\"label\":\"Unique count of id\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"h\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"status\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"_term\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"id\"}}]}",
"uiStateJSON": "{\"vis\":{\"colors\":{\"Never connected\":\"#447EBC\",\"Active\":\"#E5AC0E\"}}}", "uiStateJSON": "{\"vis\":{\"colors\":{\"Never connected\":\"#447EBC\",\"Active\":\"#E5AC0E\"}}}",
"description": "", "description": "",
"version": 1, "version": 1,
"kibanaSavedObjectMeta": { "kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"wazuh-monitoring-3.x-*\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" "searchSourceJSON": "{\"index\":\"wazuh-monitoring-3.x-*\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
} }
}, },
"_type": "visualization" "_type": "visualization"
}, },

View File

@ -11,7 +11,7 @@
*/ */
import knownFields from '../integration-files/known-fields'; import knownFields from '../integration-files/known-fields';
export default class ElasticWrapper { export class ElasticWrapper {
constructor(server){ constructor(server){
this.elasticRequest = server.plugins.elasticsearch.getCluster('data'); this.elasticRequest = server.plugins.elasticsearch.getCluster('data');
this.WZ_KIBANA_INDEX = server && this.WZ_KIBANA_INDEX = server &&
@ -437,7 +437,7 @@ export default class ElasticWrapper {
} catch(error){ } catch(error){
return Promise.reject(error); return Promise.reject(error);
} }
}; }
/** /**
* Usually used to save a new Wazuh API entry * Usually used to save a new Wazuh API entry
@ -526,7 +526,7 @@ export default class ElasticWrapper {
} catch(error){ } catch(error){
return Promise.reject(error); return Promise.reject(error);
} }
}; }
/** /**
* Same as curling the templates from Elasticsearch * Same as curling the templates from Elasticsearch

View File

@ -13,7 +13,7 @@ import fs from 'fs'
import yml from 'js-yaml' import yml from 'js-yaml'
import path from 'path' import path from 'path'
export default () => { export function getConfiguration() {
try { try {
const customPath = path.join(__dirname, '../../config.yml'); const customPath = path.join(__dirname, '../../config.yml');
const raw = fs.readFileSync(customPath, { encoding: 'utf-8' }) const raw = fs.readFileSync(customPath, { encoding: 'utf-8' })

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import log from '../logger' import { log } from '../logger'
import cron from 'node-cron' import cron from 'node-cron'
export default interval => { export function parseCron(interval) {
try { try {
if(!interval) throw new Error('Interval not found'); if(!interval) throw new Error('Interval not found');

View File

@ -97,7 +97,7 @@ const checkFiles = () => {
* @param {*} message Message to show * @param {*} message Message to show
* @param {*} level Optional, default is 'error' * @param {*} level Optional, default is 'error'
*/ */
export default (location, message, level) => { export function log(location, message, level) {
initDirectory() initDirectory()
.then(() => { .then(() => {
if(allowed){ if(allowed){
@ -110,5 +110,5 @@ export default (location, message, level) => {
}); });
} }
}) })
.catch(error => console.error(`Cannot create the logs directory due to:\n${error.message || error}`)); .catch(error => console.error(`Cannot create the logs directory due to:\n${error.message || error}`)); // eslint-disable-line
}; }

View File

@ -9,19 +9,19 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import cron from 'node-cron' import cron from 'node-cron'
import needle from 'needle' import needle from 'needle'
import getPath from'../util/get-path' import { getPath } from'../util/get-path'
import colors from 'ansicolors' import colors from 'ansicolors'
import log from './logger' import { log } from './logger'
import ElasticWrapper from './lib/elastic-wrapper' import { ElasticWrapper } from './lib/elastic-wrapper'
import monitoringTemplate from './integration-files/monitoring-template' import monitoringTemplate from './integration-files/monitoring-template'
import packageJSON from '../package.json' import packageJSON from '../package.json'
import getConfiguration from './lib/get-configuration' import { getConfiguration } from './lib/get-configuration'
import parseCron from './lib/parse-cron' import { parseCron } from './lib/parse-cron'
import { BuildBody } from './lib/replicas-shards-helper' import { BuildBody } from './lib/replicas-shards-helper'
export default (server, options) => { export function Monitoring (server, options) {
const blueWazuh = colors.blue('wazuh'); const blueWazuh = colors.blue('wazuh');
let ENABLED = true; let ENABLED = true;
@ -280,7 +280,7 @@ export default (server, options) => {
} }
if (body === '') return; if (body === '') return;
const response = await wzWrapper.pushBulkAnyIndex(todayIndex,body); await wzWrapper.pushBulkAnyIndex(todayIndex,body);
agentsArray.length = 0; agentsArray.length = 0;
} }
@ -341,7 +341,7 @@ export default (server, options) => {
try { try {
log('[monitoring][checkTemplate]', 'Updating wazuh-monitoring template...', 'info'); log('[monitoring][checkTemplate]', 'Updating wazuh-monitoring template...', 'info');
server.log([blueWazuh, 'monitoring', 'info'], "Updating wazuh-monitoring template..."); server.log([blueWazuh, 'monitoring', 'info'], "Updating wazuh-monitoring template...");
const data = await wzWrapper.putMonitoringTemplate(monitoringTemplate); await wzWrapper.putMonitoringTemplate(monitoringTemplate);
return; return;
} catch(error){ } catch(error){
log('[monitoring][checkTemplate]', `Something went wrong updating wazuh-monitoring template... ${error.message || error}`); log('[monitoring][checkTemplate]', `Something went wrong updating wazuh-monitoring template... ${error.message || error}`);
@ -452,4 +452,4 @@ export default (server, options) => {
// Cron tab for getting agent status. // Cron tab for getting agent status.
if(!options && ENABLED) cron.schedule(CRON_FREQ, cronTask, true); if(!options && ENABLED) cron.schedule(CRON_FREQ, cronTask, true);
return fetchAgentsExternal; return fetchAgentsExternal;
}; }

View File

@ -9,11 +9,11 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
import AuditMap from './audit-map'; import AuditMap from './audit-map';
export default class PciRequest { export class AuditRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana
@ -176,7 +176,7 @@ export default class PciRequest {
const response = await this.wzWrapper.searchWazuhAlertsWithPayload(base); const response = await this.wzWrapper.searchWazuhAlertsWithPayload(base);
const { buckets } = response.aggregations['2']; const { buckets } = response.aggregations['2'];
return buckets.map(item => { return { id:item.key, syscall:AuditMap[item.key] };}); return buckets.map(item => ({ id:item.key, syscall:AuditMap[item.key] }));
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
export default class GdprRequest { export class GdprRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
export default class VulnerabilityRequest { export class OverviewRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
export default class PciRequest { export class PciRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
export default class RootcheckRequest { export class RootcheckRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
export default class SyscheckRequest { export class SyscheckRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana

View File

@ -9,10 +9,10 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import ElasticWrapper from '../lib/elastic-wrapper'; import { ElasticWrapper } from '../lib/elastic-wrapper';
import Base from './base-query'; import Base from './base-query';
export default class VulnerabilityRequest { export class VulnerabilityRequest {
/** /**
* Constructor * Constructor
* @param {*} server Hapi.js server object provided by Kibana * @param {*} server Hapi.js server object provided by Kibana
@ -174,7 +174,7 @@ export default class VulnerabilityRequest {
const response = await this.wzWrapper.searchWazuhAlertsWithPayload(base); const response = await this.wzWrapper.searchWazuhAlertsWithPayload(base);
const { buckets } = response.aggregations['2']; const { buckets } = response.aggregations['2'];
return buckets.map(item => {return {package: item.key, severity: severity};}); return buckets.map(item => ({package: item.key, severity: severity}));
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
@ -221,17 +221,13 @@ export default class VulnerabilityRequest {
const response = await this.wzWrapper.searchWazuhAlertsWithPayload(base); const response = await this.wzWrapper.searchWazuhAlertsWithPayload(base);
const { buckets } = response.aggregations['2']; const { buckets } = response.aggregations['2'];
return buckets.map(item => { return buckets.map(item => ({
return { package: item.key,
package: item.key, references: item['3'].buckets.map(ref => ref.key)
references: item['3'].buckets.map(ref => ref.key) }));
};
});
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
} }
} }
} }

View File

@ -9,26 +9,26 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import { WazuhApiElastic } from '../controllers'; import { WazuhApiElasticCtrl } from '../controllers';
export default (server, options) => { export function WazuhApiElasticRoutes(server) {
const ctrl = new WazuhApiElastic(server); const ctrl = new WazuhApiElasticCtrl(server);
// Save the given API into elasticsearch // Save the given API into elasticsearch
server.route({ method: 'PUT', path: '/api/wazuh-api/settings', handler: (req,reply) => ctrl.saveAPI(req,reply) }); server.route({ method: 'PUT', path: '/api/wazuh-api/settings', handler(req, reply) { return ctrl.saveAPI(req, reply) } });
// Update the given API into elasticsearch // Update the given API into elasticsearch
server.route({ method: 'PUT', path: '/api/wazuh-api/update-settings', handler: (req,reply) => ctrl.updateFullAPI(req,reply) }); server.route({ method: 'PUT', path: '/api/wazuh-api/update-settings', handler(req, reply) { return ctrl.updateFullAPI(req, reply) } });
// Get Wazuh-API entries list (Multimanager) from elasticsearch index // Get Wazuh-API entries list (Multimanager) from elasticsearch index
server.route({ method: 'GET', path: '/api/wazuh-api/apiEntries', handler: (req,reply) => ctrl.getAPIEntries(req,reply) }); server.route({ method: 'GET', path: '/api/wazuh-api/apiEntries', handler(req, reply) { return ctrl.getAPIEntries(req, reply) } });
// Delete Wazuh-API entry (multimanager) from elasticsearch index // Delete Wazuh-API entry (multimanager) from elasticsearch index
server.route({ method: 'DELETE', path: '/api/wazuh-api/apiEntries/{id}', handler: (req,reply) => ctrl.deleteAPIEntries(req,reply) }); server.route({ method: 'DELETE', path: '/api/wazuh-api/apiEntries/{id}', handler(req, reply) { return ctrl.deleteAPIEntries(req, reply) } });
// Set Wazuh-API as default (multimanager) on elasticsearch index // Set Wazuh-API as default (multimanager) on elasticsearch index
server.route({ method: 'PUT', path: '/api/wazuh-api/apiEntries/{id}', handler: (req,reply) => ctrl.setAPIEntryDefault(req,reply) }); server.route({ method: 'PUT', path: '/api/wazuh-api/apiEntries/{id}', handler(req, reply) { return ctrl.setAPIEntryDefault(req, reply) } });
// Update the API hostname // Update the API hostname
server.route({ method: 'PUT', path: '/api/wazuh-api/updateApiHostname/{id}', handler: (req,reply) => ctrl.updateAPIHostname(req,reply) }); server.route({ method: 'PUT', path: '/api/wazuh-api/updateApiHostname/{id}', handler(req, reply) { return ctrl.updateAPIHostname(req, reply) } });
}; }

View File

@ -9,42 +9,42 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import { WazuhApi } from '../controllers'; import { WazuhApiCtrl } from '../controllers';
export default (server, options) => { export function WazuhApiRoutes (server) {
const ctrl = new WazuhApi(server); const ctrl = new WazuhApiCtrl(server);
// Returns if the wazuh-api configuration is working // Returns if the wazuh-api configuration is working
server.route({ method: 'POST', path: '/api/wazuh-api/checkStoredAPI', handler: (req, reply) => ctrl.checkStoredAPI(req, reply) }); server.route({ method: 'POST', path: '/api/wazuh-api/checkStoredAPI', handler(req, reply) { return ctrl.checkStoredAPI(req, reply)} });
// Check if credentials on POST connect to Wazuh API. Not storing them! // Check if credentials on POST connect to Wazuh API. Not storing them!
// Returns if the wazuh-api configuration received in the POST body will work // Returns if the wazuh-api configuration received in the POST body will work
server.route({ method: 'POST', path: '/api/wazuh-api/checkAPI', handler: (req, reply) => ctrl.checkAPI(req, reply) }); server.route({ method: 'POST', path: '/api/wazuh-api/checkAPI', handler(req, reply) { return ctrl.checkAPI(req, reply) }});
// Returns the request result (With error control) // Returns the request result (With error control)
server.route({ method: 'POST', path: '/api/wazuh-api/request', handler: (req, reply) => ctrl.requestApi(req, reply) }); server.route({ method: 'POST', path: '/api/wazuh-api/request', handler(req, reply) { return ctrl.requestApi(req, reply) }});
// Return a PCI requirement description // Return a PCI requirement description
server.route({ method: 'GET', path: '/api/wazuh-api/pci/{requirement}', handler: (req, reply) => ctrl.getPciRequirement(req, reply) }); server.route({ method: 'GET', path: '/api/wazuh-api/pci/{requirement}', handler(req, reply) { return ctrl.getPciRequirement(req, reply) }});
// Return a GDPR requirement description // Return a GDPR requirement description
server.route({ method: 'GET', path: '/api/wazuh-api/gdpr/{requirement}', handler: (req, reply) => ctrl.getGdprRequirement(req, reply) }); server.route({ method: 'GET', path: '/api/wazuh-api/gdpr/{requirement}', handler(req, reply) { return ctrl.getGdprRequirement(req, reply)} });
// Force fetch data to be inserted on wazuh-monitoring indices // Force fetch data to be inserted on wazuh-monitoring indices
server.route({ method: 'GET', path: '/api/wazuh-api/fetchAgents', handler: (req, reply) => ctrl.fetchAgents(req, reply) }); server.route({ method: 'GET', path: '/api/wazuh-api/fetchAgents', handler(req, reply) { return ctrl.fetchAgents(req, reply) }});
// Returns the config.yml file parsed // Returns the config.yml file parsed
server.route({ method: 'GET', path: '/api/wazuh-api/configuration', handler: (req, reply) => ctrl.getConfigurationFile(req, reply) }); server.route({ method: 'GET', path: '/api/wazuh-api/configuration', handler(req, reply) { return ctrl.getConfigurationFile(req, reply)} });
// Returns data from the Wazuh API on CSV readable format // Returns data from the Wazuh API on CSV readable format
server.route({ method: 'POST', path: '/api/wazuh-api/csv', handler: (req,res) => ctrl.csv(req,res)}) server.route({ method: 'POST', path: '/api/wazuh-api/csv', handler(req,res) { return ctrl.csv(req,res)}})
// Returns total RAM available from the current machine where Kibana is being executed // Returns total RAM available from the current machine where Kibana is being executed
server.route({ method: 'GET', path: '/api/wazuh-api/ram', handler: (req,res) => ctrl.totalRam(req,res)}) server.route({ method: 'GET', path: '/api/wazuh-api/ram', handler(req,res) { return ctrl.totalRam(req,res)}})
// Returns unique fields from the agents such OS, agent version ... // Returns unique fields from the agents such OS, agent version ...
server.route({ method: 'GET', path: '/api/wazuh-api/agents-unique/{api}', handler: (req,res) => ctrl.getAgentsFieldsUniqueCount(req,res)}); server.route({ method: 'GET', path: '/api/wazuh-api/agents-unique/{api}', handler(req,res) { return ctrl.getAgentsFieldsUniqueCount(req,res)}});
// Returns Wazuh app logs ... // Returns Wazuh app logs ...
server.route({ method: 'GET', path: '/api/wazuh-api/logs', handler: (req,res) => ctrl.getAppLogs(req,res)}); server.route({ method: 'GET', path: '/api/wazuh-api/logs', handler(req,res) { return ctrl.getAppLogs(req,res)}});
}; }

View File

@ -9,34 +9,34 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
import { WazuhElastic } from '../controllers'; import { WazuhElasticCtrl } from '../controllers';
export default (server, options) => { export function WazuhElasticRouter(server) {
const ctrl = new WazuhElastic(server); const ctrl = new WazuhElasticCtrl(server);
// Get index patterns list // Get index patterns list
server.route({ method: 'GET', path: '/get-list', handler: (req,res) => ctrl.getlist(req,res) }); server.route({ method: 'GET', path: '/get-list', handler(req, res) { return ctrl.getlist(req, res) } });
// Refresh known fields for specific index pattern // Refresh known fields for specific index pattern
server.route({ method: 'GET', path: '/refresh-fields/{pattern}', handler: (req,res) => ctrl.refreshIndex(req,res) }); server.route({ method: 'GET', path: '/refresh-fields/{pattern}', handler(req, res) { return ctrl.refreshIndex(req, res) } });
// Create visualizations specified in 'tab' parameter and applying to 'pattern' // Create visualizations specified in 'tab' parameter and applying to 'pattern'
server.route({ method: 'GET', path: '/api/wazuh-elastic/create-vis/{tab}/{pattern}', handler: (req,res) => ctrl.createVis(req,res) }); server.route({ method: 'GET', path: '/api/wazuh-elastic/create-vis/{tab}/{pattern}', handler(req, res) { return ctrl.createVis(req, res) } });
server.route({ method: 'POST', path: '/api/wazuh-elastic/create-vis/{tab}/{pattern}', handler: (req,res) => ctrl.createClusterVis(req,res) }); server.route({ method: 'POST', path: '/api/wazuh-elastic/create-vis/{tab}/{pattern}', handler(req, res) { return ctrl.createClusterVis(req, res) } });
// Returns whether a correct template is being applied for the index-pattern // Returns whether a correct template is being applied for the index-pattern
server.route({ method: 'GET', path: '/api/wazuh-elastic/template/{pattern}', handler: (req,res) => ctrl.getTemplate(req,res) }); server.route({ method: 'GET', path: '/api/wazuh-elastic/template/{pattern}', handler(req, res) { return ctrl.getTemplate(req, res) } });
// Returns whether the pattern exists or not // Returns whether the pattern exists or not
server.route({ method: 'GET', path: '/api/wazuh-elastic/pattern/{pattern}', handler: (req,res) => ctrl.checkPattern(req,res) }); server.route({ method: 'GET', path: '/api/wazuh-elastic/pattern/{pattern}', handler(req, res) { return ctrl.checkPattern(req, res) } });
// Returns the agent with most alerts // Returns the agent with most alerts
server.route({ method: 'GET', path: '/api/wazuh-elastic/top/{mode}/{cluster}/{field}/{pattern}', handler: (req,res) => ctrl.getFieldTop(req,res) }); server.route({ method: 'GET', path: '/api/wazuh-elastic/top/{mode}/{cluster}/{field}/{pattern}', handler(req, res) { return ctrl.getFieldTop(req, res) } });
// Return Wazuh Appsetup info // Return Wazuh Appsetup info
server.route({ method: 'GET', path: '/api/wazuh-elastic/setup', handler: (req,res) => ctrl.getSetupInfo(req,res) }); server.route({ method: 'GET', path: '/api/wazuh-elastic/setup', handler(req, res) { return ctrl.getSetupInfo(req, res) } });
// Useful to check cookie consistence // Useful to check cookie consistence
server.route({ method: 'GET', path: '/api/wazuh-elastic/timestamp', handler: (req,res) => ctrl.getTimeStamp(req,res) }); server.route({ method: 'GET', path: '/api/wazuh-elastic/timestamp', handler(req, res) { return ctrl.getTimeStamp(req, res) } });
}; }

View File

@ -11,18 +11,18 @@
*/ */
import { WazuhReportingCtrl } from '../controllers'; import { WazuhReportingCtrl } from '../controllers';
export default (server, options) => { export function WazuhReportingRoutes(server) {
const ctrl = new WazuhReportingCtrl(server); const ctrl = new WazuhReportingCtrl(server);
// Builds a PDF report from multiple PNG images // Builds a PDF report from multiple PNG images
server.route({ method: 'POST', path: '/api/wazuh-reporting/report', handler: (req,res) => ctrl.report(req,res)}); server.route({ method: 'POST', path: '/api/wazuh-reporting/report', handler(req, res) { return ctrl.report(req, res) } });
// Fetch specific report // Fetch specific report
server.route({ method: 'GET', path: '/api/wazuh-reporting/report/{name}', handler: (req,res) => ctrl.getReportByName(req,res)}); server.route({ method: 'GET', path: '/api/wazuh-reporting/report/{name}', handler(req, res) { return ctrl.getReportByName(req, res) } });
// Delete specific report // Delete specific report
server.route({ method: 'DELETE', path: '/api/wazuh-reporting/report/{name}', handler: (req,res) => ctrl.deleteReportByName(req,res)}); server.route({ method: 'DELETE', path: '/api/wazuh-reporting/report/{name}', handler(req, res) { return ctrl.deleteReportByName(req, res) } });
// Fetch the reports list // Fetch the reports list
server.route({ method: 'GET', path: '/api/wazuh-reporting/reports', handler: (req,res) => ctrl.getReports(req,res)}); server.route({ method: 'GET', path: '/api/wazuh-reporting/reports', handler(req, res) { return ctrl.getReports(req, res) } });
}; }

View File

@ -0,0 +1,116 @@
const chai = require('chai');
const needle = require('needle')
chai.should();
const headers = {headers: {'kbn-xsrf': 'kibana', 'Content-Type': 'application/json'}}
let API_ID = null;
let API_PORT = null;
let API_URL = null;
let API_USER = null;
const EXAMPLE_API = {};
describe('wazuh-api-elastic', () => {
/*
// Save the given API into elasticsearch
server.route({ method: 'PUT', path: '/api/wazuh-api/settings', handler: (req,reply) => ctrl.saveAPI(req,reply) });
// Update the given API into elasticsearch
server.route({ method: 'PUT', path: '/api/wazuh-api/update-settings', handler: (req,reply) => ctrl.updateFullAPI(req,reply) });
// Get Wazuh-API entries list (Multimanager) from elasticsearch index
server.route({ method: 'GET', path: '/api/wazuh-api/apiEntries', handler: (req,reply) => ctrl.getAPIEntries(req,reply) });
// Delete Wazuh-API entry (multimanager) from elasticsearch index
server.route({ method: 'DELETE', path: '/api/wazuh-api/apiEntries/{id}', handler: (req,reply) => ctrl.deleteAPIEntries(req,reply) });
// Set Wazuh-API as default (multimanager) on elasticsearch index
server.route({ method: 'PUT', path: '/api/wazuh-api/apiEntries/{id}', handler: (req,reply) => ctrl.setAPIEntryDefault(req,reply) });
// Update the API hostname
server.route({ method: 'PUT', path: '/api/wazuh-api/updateApiHostname/{id}', handler: (req,reply) => ctrl.updateAPIHostname(req,reply) });
*/
before(async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/apiEntries`, {}, {});
if(!res.body || !res.body.length) {
console.log('There are no APIs stored in Elasticsearch, exiting...')
process.exit(1)
}
API_ID = res.body[0]._id;
API_URL = res.body[0]._source.url;
API_PORT = res.body[0]._source.api_port;
API_USER = res.body[0]._source.api_user;
})
it('PUT /api/wazuh-api/settings', async () => {
const res = await needle('put', `localhost:5601/api/wazuh-api/settings`, {
user : 'foo',
password : 'bar',
url : 'http://localhost',
port : 55000,
insecure : true,
component : 'API',
active : true,
cluster_info: {},
extensions : {}
}, headers);
res.body.response.result.should.be.eql('created')
const removed = await needle('delete', `localhost:5601/api/wazuh-api/apiEntries/${res.body.response._id}`, {}, headers);
removed.body.result.should.be.eql('deleted')
})
it('PUT /api/wazuh-api/update-settings', async () => {
const res = await needle('put', `localhost:5601/api/wazuh-api/settings`, {
user : 'foo',
password : 'bar',
url : 'http://localhost',
port : 55000,
insecure : true,
component : 'API',
active : true,
cluster_info: {},
extensions : {}
}, headers);
const updated = await needle('put', `localhost:5601/api/wazuh-api/update-settings`, {user: 'john', password: 'bar', url: 'http://0.0.0.0', port: 55000, id: res.body.response._id}, headers);
await needle('delete', `localhost:5601/api/wazuh-api/apiEntries/${res.body.response._id}`, {}, headers);
updated.body.statusCode.should.be.eql(200)
updated.body.message.should.be.eql('ok')
})
it('GET /api/wazuh-api/apiEntries', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/apiEntries`, {}, headers);
res.body.should.be.a('array')
res.body.length.should.be.gt(0)
})
it('DELETE /api/wazuh-api/apiEntries/{id}', async () => {
const insert = await needle('put', `localhost:5601/api/wazuh-api/settings`, {
user : 'foo',
password : 'bar',
url : 'http://localhost',
port : 55000,
insecure : true,
component : 'API',
active : true,
cluster_info: {},
extensions : {}
}, headers);
const res = await needle('delete', `localhost:5601/api/wazuh-api/apiEntries/${insert.body.response._id}`, {}, headers);
res.body.result.should.be.eql('deleted')
})
it('PUT /api/wazuh-api/apiEntries/{id}', async () => {
const res = await needle('put', `localhost:5601/api/wazuh-api/apiEntries/${API_ID}`, {}, headers);
res.body.statusCode.should.be.eql(200)
res.body.message.should.be.eql('ok')
})
it('PUT /api/wazuh-api/updateApiHostname/{id}', async () => {
const res = await needle('put', `localhost:5601/api/wazuh-api/updateApiHostname/${API_ID}`, {}, headers);
res.body.statusCode.should.be.eql(200)
res.body.message.should.be.eql('ok')
})
})

108
test/server/wazuh-api.js Normal file
View File

@ -0,0 +1,108 @@
const chai = require('chai');
const needle = require('needle')
chai.should();
const headers = {headers: {'kbn-xsrf': 'kibana', 'Content-Type': 'application/json'}}
let API_ID = null;
let API_PORT = null;
let API_URL = null;
let API_USER = null;
describe('wazuh-api', () => {
before(async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/apiEntries`, {}, {});
if(!res.body || !res.body.length) {
console.log('There are no APIs stored in Elasticsearch, exiting...')
process.exit(1)
}
API_ID = res.body[0]._id;
API_URL = res.body[0]._source.url;
API_PORT = res.body[0]._source.api_port;
API_USER = res.body[0]._source.api_user;
})
it('POST /api/wazuh-api/csv', async () => {
const res = await needle('post', `localhost:5601/api/wazuh-api/csv`, {path:'/agents', id: API_ID}, headers);
res.body.should.be.a('string')
})
it('POST /api/wazuh-api/checkAPI', async () => {
const res = await needle('post', `localhost:5601/api/wazuh-api/checkAPI`, {user:API_USER, url:API_URL, port:API_PORT, id:API_ID}, headers);
res.body.should.be.a('object')
res.body.manager.should.be.a('string')
res.body.cluster.should.be.a('string')
res.body.status.should.be.a('string')
})
it('POST /api/wazuh-api/checkStoredAPI', async () => {
const res = await needle('post', `localhost:5601/api/wazuh-api/checkStoredAPI`, API_ID, headers);
res.body.should.be.a('object')
res.body.statusCode.should.be.eql(200)
res.body.data.should.be.a('object')
res.body.data.user.should.be.a('string')
res.body.data.password.should.be.a('string')
res.body.data.url.should.be.a('string')
res.body.data.port.should.be.a('string')
res.body.data.extensions.should.be.a('object')
res.body.data.cluster_info.should.be.a('object')
})
it('POST /api/wazuh-api/request', async () => {
const res = await needle('post', `localhost:5601/api/wazuh-api/request`, {method:'GET', path:'/agents/000', body:{ }, id:API_ID }, headers);
res.body.should.be.a('object')
res.body.error.should.be.eql(0)
res.body.data.should.be.a('object')
res.body.data.status.should.be.eql('Active')
res.body.data.id.should.be.eql('000')
})
it('GET /api/wazuh-api/pci/{requirement}', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/pci/all`, {}, {});
res.body.should.be.a('object')
res.body['1.1.1'].should.be.eql('A formal process for approving and testing all network connections and changes to the firewall and router configurations')
})
it('GET /api/wazuh-api/gdpr/{requirement}', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/gdpr/all`, {}, {});
res.body.should.be.a('object')
res.body['II_5.1.f'].should.be.eql('Ensure the ongoing confidentiality, integrity, availability and resilience of processing systems and services, verifying its modifications, accesses, locations and guarantee the safety of them.<br>File sharing protection and file sharing technologies that meet the requirements of data protection.')
})
it('GET /api/wazuh-api/configuration', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/configuration`, {}, {});
res.body.should.be.a('object')
res.body.error.should.be.eql(0)
res.body.statusCode.should.be.eql(200)
res.body.data.should.be.a('object')
})
it('GET /api/wazuh-api/ram', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/ram`, {}, {});
res.body.should.be.a('object')
res.body.error.should.be.eql(0)
res.body.ram.should.be.gt(1)
})
it('GET /api/wazuh-api/agents-unique/{api}', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/agents-unique/${API_ID}`, {}, {});
res.body.should.be.a('object')
res.body.error.should.be.eql(0)
res.body.result.should.be.a('object')
res.body.result.groups.should.be.a('array')
res.body.result.nodes.should.be.a('array')
res.body.result.versions.should.be.a('array')
res.body.result.osPlatforms.should.be.a('array')
res.body.result.lastAgent.should.be.a('object')
res.body.result.summary.should.be.a('object')
})
it('GET /api/wazuh-api/logs', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-api/logs`, {}, {});
res.body.should.be.a('object')
res.body.lastLogs.should.be.a('array')
res.body.error.should.be.eql(0)
})
})

View File

@ -0,0 +1,91 @@
const chai = require('chai');
const needle = require('needle')
chai.should();
const headers = {headers: {'kbn-xsrf': 'kibana', 'Content-Type': 'application/json'}}
describe('wazuh-elastic', () => {
describe('Checking index patterns', () => {
it('GET /get-list', async () => {
const res = await needle('get', `localhost:5601/get-list`, {}, headers);
res.body.data.should.be.a('array')
res.body.data.length.should.be.gt(0)
res.body.data[0].should.be.a('object')
res.body.data[0].id.should.be.a('string')
res.body.data[0].title.should.be.a('string')
})
it('GET /refresh-fields/{pattern}', async () => {
const res = await needle('get', `localhost:5601/refresh-fields/wazuh-alerts-3.x-*`, {}, headers);
res.body.acknowledge.should.be.eql(true)
res.body.output.should.be.a('object')
res.body.output._index.should.be.eql('.kibana')
res.body.output._type.should.be.eql('doc')
res.body.output._id.should.be.eql('index-pattern:wazuh-alerts-3.x-*')
})
})
describe('Checking visualization composers', () => {
it('GET /api/wazuh-elastic/create-vis/{tab}/{pattern}', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-elastic/create-vis/overview-general/wazuh-alerts-3.x-*`, {}, headers);
res.body.acknowledge.should.be.eql(true)
res.body.raw.should.be.a('array')
res.body.raw.length.should.be.eql(15)
res.body.raw[0].attributes.should.be.a('object')
res.body.raw[0].type.should.be.eql('visualization')
res.body.raw[0].id.should.be.a('string')
})
it('POST /api/wazuh-elastic/create-vis/{tab}/{pattern}', async () => {
const res = await needle('post', `localhost:5601/api/wazuh-elastic/create-vis/cluster-monitoring/wazuh-alerts-3.x-*`, {nodes:{items:[],name:'node01'}}, headers);
res.body.acknowledge.should.be.eql(true)
res.body.raw.should.be.a('array')
res.body.raw.length.should.be.eql(4)
res.body.raw[0].attributes.should.be.a('object')
res.body.raw[0].type.should.be.eql('visualization')
res.body.raw[0].id.should.be.a('string')
})
})
describe('Checking template and index pattern existance', () => {
it('GET /api/wazuh-elastic/template/{pattern}', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-elastic/template/wazuh-alerts-3.x-*`, {}, headers);
res.body.statusCode.should.be.eql(200)
res.body.status.should.be.eql(true)
res.body.data.should.be.eql('Template found for wazuh-alerts-3.x-*')
})
it('GET /api/wazuh-elastic/pattern/{pattern}', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-elastic/pattern/wazuh-alerts-3.x-*`, {}, headers);
res.body.statusCode.should.be.eql(200)
res.body.status.should.be.eql(true)
res.body.data.should.be.eql('Index pattern found')
})
})
/*it('GET /api/wazuh-elastic/top/{mode}/{cluster}/{field}/{pattern}', async () => {
throw Error('Test not implemented...')
})*/
describe('Checking .wazuh-version index', () => {
it('GET /api/wazuh-elastic/setup', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-elastic/setup`, {}, headers);
res.body.statusCode.should.be.eql(200)
res.body.data.should.be.a('object')
res.body.data.name.should.be.eql('Wazuh App')
res.body.data['app-version'].should.be.eql('3.6.0')
res.body.data.revision.should.be.eql('0407')
res.body.data.installationDate.should.be.a('string')
res.body.data.lastRestart.should.be.a('string')
})
it('GET /api/wazuh-elastic/timestamp', async () => {
const res = await needle('get', `localhost:5601/api/wazuh-elastic/timestamp`, {}, headers);
res.body.installationDate.should.be.a('string')
res.body.lastRestart.should.be.a('string')
})
})
})

View File

@ -9,7 +9,7 @@
* *
* Find more information about this on the LICENSE file. * Find more information about this on the LICENSE file.
*/ */
export default config => { export function getPath (config) {
let path = config.url; let path = config.url;
let protocol; let protocol;
if (config.url.startsWith("https://")) { if (config.url.startsWith("https://")) {
@ -26,4 +26,4 @@ export default config => {
path = `${config.url}:${config.port}`; path = `${config.url}:${config.port}`;
} }
return path; return path;
}; }