mirror of
https://github.com/valitydev/wazuh-kibana-app.git
synced 2024-11-06 09:55:18 +00:00
564 lines
21 KiB
JavaScript
564 lines
21 KiB
JavaScript
module.exports = function (server, options) {
|
|
// Require some libraries
|
|
const pciRequirementsFile = '';
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const needle = require('needle');
|
|
var fetchAgentsExternal = require(path.resolve(__dirname, "../wazuh-monitoring.js"));
|
|
const wazuh_config_file = '../../configuration/config.json';
|
|
const wazuh_temp_file = '../../configuration/.patch_version';
|
|
var colors = require('ansicolors');
|
|
var blueWazuh = colors.blue('wazuh');
|
|
var wazuh_config = {};
|
|
var app_package = {};
|
|
var wazuh_api_version;
|
|
|
|
// Read Wazuh App configuration file
|
|
try {
|
|
wazuh_config = JSON.parse(fs.readFileSync(path.resolve(__dirname, wazuh_config_file), 'utf8'));
|
|
} catch (e) {
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Could not read the Wazuh configuration file.');
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Path: ' + wazuh_config_file);
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Exception: ' + e);
|
|
};
|
|
|
|
if(fs.existsSync(path.resolve(__dirname, wazuh_temp_file))){
|
|
wazuh_api_version = "v2.0.0";
|
|
} else{
|
|
wazuh_api_version = wazuh_config.wazuhapi.version;
|
|
}
|
|
|
|
// Elastic JS Client
|
|
const serverConfig = server.config();
|
|
const elasticsearch = require('elasticsearch');
|
|
const elasticRequest = server.plugins.elasticsearch.getCluster('data');
|
|
|
|
var appInfo = {}
|
|
elasticRequest.callWithInternalUser('search', { index: '.kibana', type: 'wazuh-setup'}).then(
|
|
function (data) {
|
|
appInfo["app-version"] = data.hits.hits[0]._source['app-version'];
|
|
appInfo["installationDate"] = data.hits.hits[0]._source['installationDate'];
|
|
appInfo["revision"] = data.hits.hits[0]._source['revision'];
|
|
}, function (error) {
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Could not read the Wazuh App version.');
|
|
});
|
|
|
|
//Handlers - Generic
|
|
|
|
var getConfig = function (callback) {
|
|
elasticRequest.callWithInternalUser('search', { index: '.kibana', type: 'wazuh-configuration', q: 'active:true'}).then(
|
|
function (data) {
|
|
if (data.hits.total == 1) {
|
|
callback({ 'user': data.hits.hits[0]._source.api_user, 'password': new Buffer(data.hits.hits[0]._source.api_password, 'base64').toString("ascii"), 'url': data.hits.hits[0]._source.url, 'port': data.hits.hits[0]._source.api_port, 'insecure': data.hits.hits[0]._source.insecure, 'manager': data.hits.hits[0]._source.manager, 'extensions': data.hits.hits[0]._source.extensions });
|
|
} else {
|
|
callback({ 'error': 'no credentials', 'error_code': 1 });
|
|
}
|
|
}, function (error) {
|
|
callback({ 'error': 'no elasticsearch', 'error_code': 2 });
|
|
});
|
|
};
|
|
|
|
var getAPI_entries = function (req,reply) {
|
|
elasticRequest.callWithRequest(req, 'search', { index: '.kibana', type: 'wazuh-configuration'}).then(
|
|
function (data) {
|
|
reply(data.hits.hits);
|
|
}, function (data, error) {
|
|
reply(data);
|
|
});
|
|
};
|
|
|
|
var deleteAPI_entries = function (req,reply) {
|
|
elasticRequest.callWithRequest(req, 'delete', { index: '.kibana', type: 'wazuh-configuration', id: req.params.id}).then(
|
|
function (data) {
|
|
reply(data);
|
|
}, function (data, error) {
|
|
reply(data);
|
|
});
|
|
};
|
|
|
|
var setAPI_entry_default = function (req,reply) {
|
|
// Searching for previous default
|
|
elasticRequest.callWithRequest(req, 'search', { index: '.kibana', type: 'wazuh-configuration', q: 'active:true'}).then(
|
|
function (data) {
|
|
if (data.hits.total == 1) {
|
|
// Setting off previous default
|
|
var idPreviousActive = data.hits.hits[0]._id;
|
|
elasticRequest.callWithRequest(req, 'update', { index: '.kibana', type: 'wazuh-configuration', id: idPreviousActive, body: {doc: {"active": "false"}} }).then(
|
|
function () {
|
|
// Set new default
|
|
elasticRequest.callWithRequest(req, 'update', { index: '.kibana', type: 'wazuh-configuration', id: req.params.id, body: {doc: {"active": "true"}} }).then(
|
|
function () {
|
|
reply({ 'statusCode': 200, 'message': 'ok' });
|
|
}, function (error) {
|
|
reply({ 'statusCode': 500, 'error': 8, 'message': 'Could not save data in elasticsearch' }).code(500);
|
|
});
|
|
}, function (error) {
|
|
reply({ 'statusCode': 500, 'error': 8, 'message': 'Could not save data in elasticsearch' }).code(500);
|
|
});
|
|
}else{
|
|
// Set new default
|
|
elasticRequest.callWithRequest(req, 'update', { index: '.kibana', type: 'wazuh-configuration', id: req.params.id, body: {doc: {"active": "true"}} }).then(
|
|
function () {
|
|
reply({ 'statusCode': 200, 'message': 'ok' });
|
|
}, function (error) {
|
|
reply({ 'statusCode': 500, 'error': 8, 'message': 'Could not save data in elasticsearch' }).code(500);
|
|
});
|
|
}
|
|
}, function () {
|
|
reply({ 'statusCode': 500, 'error': 8, 'message': 'Could not set API default entry' }).code(500);
|
|
});
|
|
|
|
|
|
};
|
|
|
|
var getPciRequirement = function (req,reply) {
|
|
|
|
const pciRequirementsFile = '../startup/integration_files/pci_requirements.json';
|
|
var pciRequirements = {};
|
|
|
|
try {
|
|
pciRequirements = JSON.parse(fs.readFileSync(path.resolve(__dirname, pciRequirementsFile), 'utf8'));
|
|
} catch (e) {
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Could not read the mapping file.');
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Path: ' + pciRequirementsFile);
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Exception: ' + e);
|
|
};
|
|
var pci_description = "";
|
|
|
|
if(req.params.requirement == "all"){
|
|
reply(pciRequirements);
|
|
return;
|
|
}
|
|
|
|
if(pciRequirements[req.params.requirement])
|
|
pci_description = pciRequirements[req.params.requirement];
|
|
reply({pci: {requirement: req.params.requirement, description: pci_description}});
|
|
};
|
|
|
|
var getExtensions = function (req,reply) {
|
|
elasticRequest.callWithRequest(req, 'search', { index: '.kibana', type: 'wazuh-configuration'}).then(
|
|
function (data) {
|
|
reply(data.hits.hits);
|
|
}, function (data, error) {
|
|
reply(data);
|
|
});
|
|
};
|
|
|
|
var toggleExtension = function (req,reply) {
|
|
// Toggle extenion state
|
|
var extension = {};
|
|
extension[req.params.extensionName] = (req.params.extensionValue == "true") ? true : false;
|
|
|
|
elasticRequest.callWithRequest(req, 'update',{ index: '.kibana', type: 'wazuh-configuration', id: req.params.id, body: {doc: {"extensions" : extension}} }).then(
|
|
function () {
|
|
reply({ 'statusCode': 200, 'message': 'ok' });
|
|
}, function (error) {
|
|
reply({ 'statusCode': 500, 'error': 8, 'message': 'Could not save data in elasticsearch' }).code(500);
|
|
});
|
|
};
|
|
|
|
//Handlers - Test API
|
|
|
|
var testApiAux2 = function (error, response, wapi_config) {
|
|
if (!error && response && response.body.data) {
|
|
return { 'statusCode': 200, 'data': 'ok', 'manager' : wapi_config.manager, 'extensions' : wapi_config.extensions };
|
|
} else if (response && response.statusCode == 401) {
|
|
return { 'statusCode': 200, 'error': '1', 'data': 'unauthorized' };
|
|
} else if (!error && response && (!response.body.data) ) {
|
|
return { 'statusCode': 200, 'error': '1', 'data': 'bad_url' };
|
|
} else {
|
|
if (!wapi_config.insecure) {
|
|
return { 'statusCode': 200, 'error': '1', 'data': 'self_signed' };
|
|
} else {
|
|
return { 'statusCode': 200, 'error': '1', 'data': 'not_running' };
|
|
}
|
|
}
|
|
};
|
|
|
|
var testApiAux1 = function (error, response, wapi_config, needle, callback) {
|
|
if (!error && response && response.body.data) {
|
|
callback({ 'statusCode': 200, 'data': 'ok', 'manager' : wapi_config.manager, 'extensions' : wapi_config.extensions});
|
|
} else if (response && response.statusCode == 401) {
|
|
callback({ 'statusCode': 200, 'error': '1', 'data': 'unauthorized' });
|
|
} else if (!error && response && (!response.body.data) ) {
|
|
callback({ 'statusCode': 200, 'error': '1', 'data': 'bad_url' });
|
|
} else {
|
|
needle.request('get', wapi_config.url+":"+wapi_config.port+'/version', {}, { username: wapi_config.user, password: wapi_config.password, rejectUnauthorized: !wapi_config.insecure }, function (error, response) {
|
|
callback(testApiAux2(error, response, wapi_config));
|
|
});
|
|
}
|
|
};
|
|
|
|
var checkStoredAPI = function (req, reply) {
|
|
var needle = require('needle');
|
|
needle.defaults({
|
|
open_timeout: wazuh_config.wazuhapi.requests.timeout
|
|
});
|
|
|
|
//Get config from elasticsearch
|
|
getConfig(function (wapi_config) {
|
|
|
|
if (wapi_config.error_code > 1) {
|
|
//Can not connect to elasticsearch
|
|
reply({ 'statusCode': 200, 'error': '1', 'data': 'no_elasticsearch' });
|
|
return;
|
|
} else if (wapi_config.error_code > 0) {
|
|
//Credentials not found
|
|
reply({ 'statusCode': 200, 'error': '2', 'data': 'no_credentials' });
|
|
return;
|
|
}
|
|
|
|
if ((wapi_config.url.indexOf('https://') == -1) && (wapi_config.url.indexOf('http://') == -1)) {
|
|
reply({ 'statusCode': 200, 'error': '1', 'data': 'protocol_error' });
|
|
} else {
|
|
needle.request('get', wapi_config.url+":"+wapi_config.port+'/version', {}, { username: wapi_config.user, password: wapi_config.password }, function (error, response) {
|
|
testApiAux1(error, response, wapi_config, needle, function (test_result) {
|
|
reply(test_result);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
var checkAPI = function (req, reply) {
|
|
var needle = require('needle');
|
|
needle.defaults({
|
|
open_timeout: 1500
|
|
});
|
|
if (!req.payload.user) {
|
|
reply({ 'statusCode': 400, 'error': 3, 'message': 'Missing param: API USER' }).code(400);
|
|
} else if (!req.payload.password) {
|
|
reply({ 'statusCode': 400, 'error': 4, 'message': 'Missing param: API PASSWORD' }).code(400);
|
|
} else if (!req.payload.url) {
|
|
reply({ 'statusCode': 400, 'error': 4, 'message': 'Missing param: API URL' }).code(400);
|
|
} else if (!req.payload.port) {
|
|
reply({ 'statusCode': 400, 'error': 4, 'message': 'Missing param: API PORT' }).code(400);
|
|
} else {
|
|
req.payload.password = new Buffer(req.payload.password, 'base64').toString("ascii");
|
|
if ((req.payload.url.indexOf('https://') == -1) && (req.payload.url.indexOf('http://') == -1)) {
|
|
reply({ 'statusCode': 200, 'error': '1', 'data': 'protocol_error' });
|
|
} else {
|
|
needle.request('get', req.payload.url+":"+req.payload.port+'/version', {}, { username: req.payload.user, password: req.payload.password, rejectUnauthorized: !req.payload.insecure }, function (error, response) {
|
|
testApiAux1(error, response, req.payload, needle, function (test_result) {
|
|
if(test_result.data == "ok"){
|
|
needle.request('get', req.payload.url+":"+req.payload.port+'/agents/000', {}, { username: req.payload.user, password: req.payload.password, rejectUnauthorized: !req.payload.insecure }, function (error, response) {
|
|
if(!error && !response.body.error)
|
|
reply(response.body.data.name);
|
|
else if(response.body.error)
|
|
reply({ 'statusCode': 500, 'error': 5, 'message': response.body.message }).code(500);
|
|
else
|
|
reply({ 'statusCode': 500, 'error': 5, 'message': 'Error occurred' }).code(500);
|
|
});
|
|
}else{
|
|
reply(test_result);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
//Handlers - Route request
|
|
|
|
var errorControl = function (error, response) {
|
|
if (error) {
|
|
return ({ 'isError': true, 'body': { 'statusCode': 500, 'error': 5, 'message': 'Request error', 'errorMessage': error.message } });
|
|
} else if (!error && response.body.error) {
|
|
return ({ 'isError': true, 'body': { 'statusCode': 500, 'error': 6, 'message': 'Wazuh api error', 'errorData': response.body } });
|
|
}
|
|
return ({ 'isError': false });
|
|
};
|
|
|
|
var makeRequest = function (method, path, data, reply) {
|
|
getConfig(function (wapi_config) {
|
|
if (wapi_config.error_code > 1) {
|
|
//Can not connect to elasticsearch
|
|
reply({ 'statusCode': 404, 'error': 2, 'message': 'Could not connect with elasticsearch' }).code(404);
|
|
return;
|
|
} else if (wapi_config.error_code > 0) {
|
|
//Credentials not found
|
|
reply({ 'statusCode': 404, 'error': 1, 'message': 'Credentials does not exists' }).code(404);
|
|
return;
|
|
}
|
|
var needle = require('needle');
|
|
needle.defaults({
|
|
open_timeout: wazuh_config.wazuhapi.requests.timeout
|
|
});
|
|
|
|
if (!data) {
|
|
data = {};
|
|
}
|
|
|
|
var options = {
|
|
headers: { 'api-version': wazuh_api_version, 'wazuh-app-version': appInfo['app-version'] },
|
|
username: wapi_config.user,
|
|
password: wapi_config.password,
|
|
rejectUnauthorized: !wapi_config.insecure
|
|
};
|
|
|
|
var fullUrl = wapi_config.url + ":" + wapi_config.port + path;
|
|
needle.request(method, fullUrl, data, options, function (error, response) {
|
|
var errorData = errorControl(error, response);
|
|
if (errorData.isError) {
|
|
reply(errorData.body).code(500);
|
|
} else {
|
|
reply(response.body);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
var requestApi = function (req, reply) {
|
|
if (!req.payload.method) {
|
|
reply({ 'statusCode': 400, 'error': 3, 'message': 'Missing param: Method' }).code(400);
|
|
} else if (!req.payload.path) {
|
|
reply({ 'statusCode': 400, 'error': 4, 'message': 'Missing param: Path' }).code(400);
|
|
} else {
|
|
makeRequest(req.payload.method, req.payload.path, req.payload.body, reply);
|
|
}
|
|
};
|
|
|
|
//Handlers - Save config
|
|
|
|
var saveApi = function (req, reply) {
|
|
if (!(req.payload.user && req.payload.password && req.payload.url && req.payload.port)) {
|
|
reply({ 'statusCode': 400, 'error': 7, 'message': 'Missing data' }).code(400);
|
|
return;
|
|
}
|
|
|
|
var options = {
|
|
headers: { 'api-version': wazuh_api_version, 'wazuh-app-version': appInfo['app-version'] },
|
|
username: req.payload.user,
|
|
password: req.payload.password,
|
|
rejectUnauthorized: !req.payload.insecure
|
|
};
|
|
|
|
needle.request('get', req.payload.url + ':' + req.payload.port +'/version', {}, options, function (error, response) {
|
|
if (error || response.error || !response.body.data) {
|
|
options = {
|
|
headers: { 'api-version': 'v2.0.0', 'wazuh-app-version': appInfo['app-version'] },
|
|
username: req.payload.user,
|
|
password: req.payload.password,
|
|
rejectUnauthorized: !req.payload.insecure
|
|
}
|
|
needle.request('get', req.payload.url + ':' + req.payload.port +'/version', {}, options, function (error, response) {
|
|
if (!error && !response.error && response.body.data) {
|
|
fs.writeFile(path.resolve(__dirname, wazuh_temp_file), "#Temporal file to avoid inconsistences when using App 2.0.1 with API 2.0.0",function(err){
|
|
if(err) server.log([blueWazuh, 'initialize', 'error'], err);
|
|
else{
|
|
server.log([blueWazuh, 'initialize', 'info'], 'Temporal file created to use the API 2.0.0');
|
|
}
|
|
});
|
|
|
|
} else {
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Wazuh API credentials not found or are not correct. Open the app in your browser and configure it for start monitoring agents.');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
var settings = { 'api_user': req.payload.user, 'api_password': req.payload.password, 'url': req.payload.url, 'api_port': req.payload.port , 'insecure': req.payload.insecure, 'component' : 'API', 'active' : req.payload.active, 'manager' : req.payload.manager, 'extensions' : req.payload.extensions};
|
|
|
|
elasticRequest.callWithRequest(req, 'index', { index: '.kibana', type: 'wazuh-configuration', body: settings, refresh: true })
|
|
.then(function (response) {
|
|
reply({ 'statusCode': 200, 'message': 'ok', 'response' : response });
|
|
}, function (error) {
|
|
reply({ 'statusCode': 500, 'error': 8, 'message': 'Could not save data in elasticsearch' }).code(500);
|
|
});
|
|
};
|
|
|
|
//Handlers - Get API Settings
|
|
|
|
var getApiSettings = function (req, reply) {
|
|
getConfig(function (wapi_config) {
|
|
|
|
if (wapi_config.error_code > 1) {
|
|
//Can not connect to elasticsearch
|
|
reply({ 'statusCode': 200, 'error': '1', 'data': 'no_elasticsearch' });
|
|
return;
|
|
} else if (wapi_config.error_code > 0) {
|
|
//Credentials not found
|
|
reply({ 'statusCode': 200, 'error': '1', 'data': 'no_credentials' });
|
|
return;
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
// Fetch agent status and insert it directly on demand
|
|
var fetchAgents = function (req, reply){
|
|
fetchAgentsExternal();
|
|
reply({ 'statusCode': 200, 'error': '0', 'data': '' });
|
|
}
|
|
|
|
|
|
|
|
//Handlers - error loggin
|
|
|
|
var postErrorLog = function (req, reply) {
|
|
|
|
if (!req.payload.message) {
|
|
server.log([blueWazuh, 'server', 'error'], 'Error logging failed:');
|
|
server.log([blueWazuh, 'server', 'error'], 'You must provide at least one error message to log');
|
|
reply({ 'statusCode': 500, 'message': 'You must provide at least one error message to log' });
|
|
} else {
|
|
server.log([blueWazuh, 'client', 'error'], req.payload.message);
|
|
if (req.payload.details) {
|
|
server.log([blueWazuh, 'client', 'error'], req.payload.details);
|
|
}
|
|
reply({ 'statusCode': 200, 'message': 'Error logged succesfully' });
|
|
}
|
|
};
|
|
|
|
//Server routes
|
|
|
|
/*
|
|
* GET /api/wazuh-api/test
|
|
* Returns if the wazuh-api configuration is working
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-api/check',
|
|
handler: checkStoredAPI
|
|
});
|
|
|
|
/*
|
|
* POST /api/wazuh-api/test
|
|
* 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
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'POST',
|
|
path: '/api/wazuh-api/check',
|
|
handler: checkAPI
|
|
});
|
|
|
|
/*
|
|
* POST /api/wazuh-api/request
|
|
* Returns the request result (With error control)
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'POST',
|
|
path: '/api/wazuh-api/request',
|
|
handler: requestApi
|
|
});
|
|
|
|
/*
|
|
* PUT /api/wazuh-api/settings
|
|
* Save the given settings into elasticsearch
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'PUT',
|
|
path: '/api/wazuh-api/settings',
|
|
handler: saveApi
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-api/settings
|
|
* Get Wazuh-API settings from elasticsearch index
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-api/settings',
|
|
handler: getApiSettings
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-api/apiEntries
|
|
* Get Wazuh-API entries list (Multimanager) from elasticsearch index
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-api/apiEntries',
|
|
handler: getAPI_entries
|
|
});
|
|
|
|
/*
|
|
* DELETE /api/wazuh-api/settings
|
|
* Delete Wazuh-API entry (multimanager) from elasticsearch index
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'DELETE',
|
|
path: '/api/wazuh-api/apiEntries/{id}',
|
|
handler: deleteAPI_entries
|
|
});
|
|
|
|
/*
|
|
* PUT /api/wazuh-api/settings
|
|
* Set Wazuh-API as default (multimanager) on elasticsearch index
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'PUT',
|
|
path: '/api/wazuh-api/apiEntries/{id}',
|
|
handler: setAPI_entry_default
|
|
});
|
|
|
|
|
|
/*
|
|
* PUT /api/wazuh-api/extension/toggle/documentId/extensionName/trueorfalse
|
|
* Toggle extension state: Enable / Disable
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'PUT',
|
|
path: '/api/wazuh-api/extension/toggle/{id}/{extensionName}/{extensionValue}',
|
|
handler: toggleExtension
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-api/extension
|
|
* Return extension state list
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-api/extension',
|
|
handler: getExtensions
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-api/pci/requirement
|
|
* Return a PCI requirement description
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-api/pci/{requirement}',
|
|
handler: getPciRequirement
|
|
});
|
|
|
|
/*
|
|
* POST /api/wazuh/debug
|
|
* Write in debug log
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'POST',
|
|
path: '/api/wazuh/errlog',
|
|
handler: postErrorLog
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-api/pci/requirement
|
|
* Return a PCI requirement description
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-api/fetchAgents',
|
|
handler: fetchAgents
|
|
});
|
|
|
|
};
|