wazuh-kibana-app/server/controllers/wazuh-api.js

1428 lines
42 KiB
JavaScript
Raw Normal View History

/*
* Wazuh app - Class for Wazuh-API functions
2019-01-14 16:36:47 +00:00
* Copyright (C) 2015-2019 Wazuh, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Find more information about this on the LICENSE file.
*/
// Require some libraries
2018-09-10 08:32:49 +00:00
import needle from 'needle';
2018-09-11 09:52:54 +00:00
import { pciRequirementsFile } from '../integration-files/pci-requirements';
import { gdprRequirementsFile } from '../integration-files/gdpr-requirements';
2019-08-07 08:31:59 +00:00
import { hipaaRequirementsFile } from '../integration-files/hipaa-requirements';
import { nistRequirementsFile } from '../integration-files/nist-requirements';
2018-09-10 08:32:49 +00:00
import { ElasticWrapper } from '../lib/elastic-wrapper';
import { getPath } from '../../util/get-path';
import { Monitoring } from '../monitoring';
import { ErrorResponse } from './error-response';
import { Parser } from 'json2csv';
2018-09-03 09:46:55 +00:00
import { getConfiguration } from '../lib/get-configuration';
2018-09-10 08:32:49 +00:00
import { log } from '../logger';
import { KeyEquivalence } from '../../util/csv-key-equivalence';
2019-01-21 15:34:27 +00:00
import { ApiErrorEquivalence } from '../../util/api-errors-equivalence';
import { cleanKeys } from '../../util/remove-key';
import { apiRequestList } from '../../util/api-request-list';
2018-12-13 11:30:28 +00:00
import * as ApiHelper from '../lib/api-helper';
import { Queue } from '../jobs/queue';
2019-06-03 11:41:54 +00:00
import querystring from 'querystring';
2019-08-07 08:31:59 +00:00
import fs from 'fs';
import path from 'path';
2018-09-03 09:46:55 +00:00
export class WazuhApiCtrl {
/**
2018-12-13 10:02:53 +00:00
* Constructor
* @param {*} server
*/
2018-09-10 08:32:49 +00:00
constructor(server) {
this.queue = Queue;
2018-09-10 08:32:49 +00:00
this.wzWrapper = new ElasticWrapper(server);
2018-12-13 11:30:28 +00:00
this.monitoringInstance = new Monitoring(server, true);
2019-08-07 08:31:59 +00:00
this.wazuhVersion = path.join(__dirname, '../wazuh-version.json');
2018-09-10 08:32:49 +00:00
}
/**
* Returns if the wazuh-api configuration is working
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
* @returns {Object} status obj or ErrorResponse
*/
2018-09-10 08:32:49 +00:00
async checkStoredAPI(req, reply) {
try {
// Get config from elasticsearch
2018-12-13 11:30:28 +00:00
const api = await this.wzWrapper.getWazuhConfigurationById(req.payload);
2019-07-31 09:38:52 +00:00
// Check Elasticsearch API errors
if (api.error_code) {
throw new Error('Could not find Wazuh API entry on Elasticsearch.');
2018-09-10 08:32:49 +00:00
}
2019-07-31 09:38:52 +00:00
2019-04-15 10:47:45 +00:00
log('wazuh-api:checkStoredAPI', `${req.payload} exists`, 'debug');
2019-07-31 09:38:52 +00:00
// Build credentials object for making a Wazuh API request
2018-12-13 11:30:28 +00:00
const credInfo = ApiHelper.buildOptionsObject(api);
2019-07-31 09:38:52 +00:00
// Fetch needed information about the cluster and the manager itself
const response = await needle(
2018-09-10 08:32:49 +00:00
'get',
2019-07-31 09:38:52 +00:00
`${api.url}:${api.port}/manager/info`,
2018-09-10 08:32:49 +00:00
{},
2018-10-15 10:34:33 +00:00
credInfo
2018-09-10 08:32:49 +00:00
);
2019-07-31 09:38:52 +00:00
// Look for socket-related errors
if (this.checkResponseIsDown(response)) {
return ErrorResponse('ERROR3099', 3099, 500, reply);
}
2019-07-31 09:38:52 +00:00
// Store error and data fields from the Wazuh API into different variables
const { body } = response;
const { error, data, message } = body;
2019-07-31 09:38:52 +00:00
// Check if the response has no errors (error code is zero and there is data)
const validResponse = parseInt(error) === 0 && data;
2018-10-15 10:34:33 +00:00
2019-07-31 09:38:52 +00:00
// If we have a valid response from the Wazuh API
if (validResponse) {
const { name, cluster } = data;
// Clear and update cluster information before being sent back to frontend
delete api.cluster_info;
const clusterEnabled = cluster.enabled === 'yes';
api.cluster_info = {
status: clusterEnabled ? 'enabled' : 'disabled',
manager: name,
node: cluster.node_name,
cluster: clusterEnabled ? cluster.name : 'Disabled'
};
2019-07-31 09:38:52 +00:00
// Update cluster information in Elasticsearch .wazuh document
await this.wzWrapper.updateWazuhIndexDocument(null, req.payload, {
doc: { cluster_info: api.cluster_info }
});
2019-07-31 09:38:52 +00:00
// Hide Wazuh API password
2019-09-10 08:44:48 +00:00
const copied = {...api};
copied.secret = '****';
2017-10-27 08:05:27 +00:00
2019-07-31 09:38:52 +00:00
return {
statusCode: 200,
2019-09-10 08:44:48 +00:00
data: copied,
2019-07-31 09:38:52 +00:00
idChanged: req.idChanged || null
};
2018-09-10 08:32:49 +00:00
}
2019-07-31 09:38:52 +00:00
// If we have an invalid response from the Wazuh API
throw new Error(message || `${api.url}:${api.port} is unreachable`);
2018-09-10 08:32:49 +00:00
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:checkStoredAPI', error.message || error);
if (error.code === 'EPROTO') {
return {
statusCode: 200,
data: { password: '****', apiIsDown: true }
};
} else if (error.code === 'ECONNREFUSED') {
2019-01-31 14:41:51 +00:00
return {
2018-09-10 08:32:49 +00:00
statusCode: 200,
data: { password: '****', apiIsDown: true }
2019-01-31 14:41:51 +00:00
};
2018-09-10 08:32:49 +00:00
} else {
// Check if we can connect to a different API
if (
error &&
error.body &&
typeof error.body.found !== 'undefined' &&
!error.body.found
) {
try {
const apis = await this.wzWrapper.getWazuhAPIEntries();
for (const api of apis.hits.hits) {
try {
2018-12-13 11:30:28 +00:00
const options = ApiHelper.buildOptionsObject(api);
options.password = Buffer.from(
api._source.api_password,
'base64'
).toString('ascii');
2018-09-10 08:32:49 +00:00
const response = await needle(
'get',
`${api._source.url}:${api._source.api_port}/version`,
{},
2018-12-13 11:30:28 +00:00
options
2018-09-10 08:32:49 +00:00
);
if (this.checkResponseIsDown(response)) {
return ErrorResponse('ERROR3099', 3099, 500, reply);
}
2018-09-10 08:32:49 +00:00
if (
2019-01-03 08:28:51 +00:00
((response || {}).body || {}).error === 0 &&
2018-12-28 15:34:38 +00:00
((response || {}).body || {}).data
2018-09-10 08:32:49 +00:00
) {
req.payload = api._id;
req.idChanged = api._id;
return this.checkStoredAPI(req, reply);
2018-03-22 14:50:42 +00:00
}
} catch (error) {} // eslint-disable-line
}
2018-09-10 08:32:49 +00:00
} catch (error) {
return ErrorResponse(error.message || error, 3020, 500, reply);
}
2018-03-22 14:50:42 +00:00
}
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3002, 500, reply);
}
}
2018-09-10 08:32:49 +00:00
}
2016-10-25 19:54:05 +00:00
/**
* This perfoms a validation of API params
* @param {Object} payload API params
*/
2018-09-10 08:32:49 +00:00
validateCheckApiParams(payload) {
if (!('user' in payload)) {
return 'Missing param: API USER';
2018-05-14 10:56:27 +00:00
}
2018-09-10 08:32:49 +00:00
if (!('password' in payload) && !('id' in payload)) {
return 'Missing param: API PASSWORD';
}
2018-09-10 08:32:49 +00:00
if (!('url' in payload)) {
return 'Missing param: API URL';
}
2018-05-14 10:56:27 +00:00
2018-09-10 08:32:49 +00:00
if (!('port' in payload)) {
return 'Missing param: API PORT';
}
2018-05-14 10:56:27 +00:00
2018-09-10 08:32:49 +00:00
if (!payload.url.includes('https://') && !payload.url.includes('http://')) {
return 'protocol_error';
}
2018-05-14 10:56:27 +00:00
2018-09-10 08:32:49 +00:00
return false;
}
/**
* This check the wazuh-api configuration received in the POST body will work
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
* @returns {Object} status obj or ErrorResponse
*/
2018-09-10 08:32:49 +00:00
async checkAPI(req, reply) {
try {
let apiAvailable = null;
const notValid = this.validateCheckApiParams(req.payload);
if (notValid) return ErrorResponse(notValid, 3003, 500, reply);
2019-04-15 10:47:45 +00:00
log('wazuh-api:checkAPI', `${req.payload.id} is valid`, 'debug');
2018-09-10 08:32:49 +00:00
// Check if a Wazuh API id is given (already stored API)
if (req.payload && req.payload.id && !req.payload.password) {
const data = await this.wzWrapper.getWazuhConfigurationById(
req.payload.id
);
2019-04-15 10:47:45 +00:00
if (data) {
apiAvailable = data;
} else {
log('wazuh-api:checkAPI', `API ${req.payload.id} not found`);
2018-09-10 08:32:49 +00:00
return ErrorResponse(
`The API ${req.payload.id} was not found`,
3029,
500,
reply
);
2019-04-15 10:47:45 +00:00
}
2018-09-10 08:32:49 +00:00
// Check if a password is given
} else if (req.payload && req.payload.password) {
apiAvailable = req.payload;
apiAvailable.password = Buffer.from(
req.payload.password,
'base64'
).toString('ascii');
}
let response = await needle(
'get',
`${apiAvailable.url}:${apiAvailable.port}/version`,
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(apiAvailable)
2018-09-10 08:32:49 +00:00
);
// Check wrong credentials
if (parseInt(response.statusCode) === 401) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:checkAPI', `Wrong Wazuh API credentials used`);
2018-09-10 08:32:49 +00:00
return ErrorResponse('Wrong credentials', 3004, 500, reply);
}
2019-04-15 10:47:45 +00:00
log(
'wazuh-api:checkAPI',
`${req.payload.id} credentials are valid`,
'debug'
);
2018-09-10 08:32:49 +00:00
if (parseInt(response.body.error) === 0 && response.body.data) {
response = await needle(
'get',
`${apiAvailable.url}:${apiAvailable.port}/agents/000`,
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(apiAvailable)
2018-09-10 08:32:49 +00:00
);
if (!response.body.error) {
const managerName = response.body.data.name;
response = await needle(
'get',
`${apiAvailable.url}:${apiAvailable.port}/cluster/status`,
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(apiAvailable)
2018-09-10 08:32:49 +00:00
);
if (!response.body.error) {
2019-04-15 10:47:45 +00:00
log(
'wazuh-api:checkStoredAPI',
`Wazuh API response is valid`,
'debug'
);
2018-09-10 08:32:49 +00:00
if (response.body.data.enabled === 'yes') {
// If cluster mode is active
response = await needle(
'get',
`${apiAvailable.url}:${apiAvailable.port}/cluster/node`,
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(apiAvailable)
2018-09-10 08:32:49 +00:00
);
2018-05-14 10:56:27 +00:00
2018-09-10 08:32:49 +00:00
if (!response.body.error) {
2019-01-31 14:41:51 +00:00
return {
2018-09-10 08:32:49 +00:00
manager: managerName,
node: response.body.data.node,
cluster: response.body.data.cluster,
status: 'enabled'
2019-01-31 14:41:51 +00:00
};
2018-09-10 08:32:49 +00:00
}
} else {
// Cluster mode is not active
2019-01-31 14:41:51 +00:00
return {
2018-09-10 08:32:49 +00:00
manager: managerName,
cluster: 'Disabled',
status: 'disabled'
2019-01-31 14:41:51 +00:00
};
2018-05-14 10:56:27 +00:00
}
2018-09-10 08:32:49 +00:00
}
2017-10-27 08:05:27 +00:00
}
2018-09-10 08:32:49 +00:00
}
2018-12-28 15:34:38 +00:00
2018-09-10 08:32:49 +00:00
const tmpMsg =
2019-01-03 08:28:51 +00:00
((response || {}).body || {}).message ||
'Unexpected error checking the Wazuh API';
2018-09-10 08:32:49 +00:00
throw new Error(tmpMsg);
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:checkAPI', error.message || error);
if (error.code === 'EPROTO') {
2019-02-11 09:13:26 +00:00
return ErrorResponse(
'Wrong protocol being used to connect to the Wazuh API',
3005,
500,
reply
);
}
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3005, 500, reply);
}
2018-09-10 08:32:49 +00:00
}
/**
* This get PCI requirements
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
* @returns {Array<Object>} requirements or ErrorResponse
*/
2018-09-10 08:32:49 +00:00
async getPciRequirement(req, reply) {
try {
let pci_description = '';
2016-10-25 19:54:05 +00:00
2018-09-10 08:32:49 +00:00
if (req.params.requirement === 'all') {
if (!req.headers.id) {
2019-01-31 14:41:51 +00:00
return pciRequirementsFile;
2018-03-22 16:10:33 +00:00
}
2018-12-13 11:30:28 +00:00
let api = await this.wzWrapper.getWazuhConfigurationById(
2018-09-10 08:32:49 +00:00
req.headers.id
);
2018-12-13 11:30:28 +00:00
if (api.error_code > 1) {
2019-04-15 10:47:45 +00:00
log(
'wazuh-api:getPciRequirement',
'Elasticsearch unexpected error or cannot connect'
);
2018-09-10 08:32:49 +00:00
// Can not connect to elasticsearch
return ErrorResponse(
'Elasticsearch unexpected error or cannot connect',
3007,
400,
reply
);
2018-12-13 11:30:28 +00:00
} else if (api.error_code > 0) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:getPciRequirement', 'Credentials do not exist');
2018-09-10 08:32:49 +00:00
// Credentials not found
2019-04-15 10:47:45 +00:00
return ErrorResponse('Credentials do not exist', 3008, 400, reply);
}
2018-09-10 08:32:49 +00:00
const response = await needle(
'get',
2018-12-13 11:30:28 +00:00
`${api.url}:${api.port}/rules/pci`,
2018-09-10 08:32:49 +00:00
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(api)
2018-09-10 08:32:49 +00:00
);
2018-12-28 15:34:38 +00:00
if ((((response || {}).body || {}).data || {}).items) {
2018-09-10 08:32:49 +00:00
let PCIobject = {};
2018-12-28 15:34:38 +00:00
for (const item of response.body.data.items) {
2018-09-10 08:32:49 +00:00
if (typeof pciRequirementsFile[item] !== 'undefined')
PCIobject[item] = pciRequirementsFile[item];
}
2019-01-31 14:41:51 +00:00
return PCIobject;
2016-10-25 19:54:05 +00:00
} else {
2019-04-15 10:47:45 +00:00
log(
'wazuh-api:getPciRequirement',
'An error occurred trying to parse PCI DSS requirements'
);
2018-09-10 08:32:49 +00:00
return ErrorResponse(
'An error occurred trying to parse PCI DSS requirements',
3009,
400,
reply
);
2016-10-25 19:54:05 +00:00
}
2018-09-10 08:32:49 +00:00
} else {
if (
typeof pciRequirementsFile[req.params.requirement] !== 'undefined'
) {
pci_description = pciRequirementsFile[req.params.requirement];
}
2017-06-01 15:08:10 +00:00
2019-01-31 14:41:51 +00:00
return {
2018-09-10 08:32:49 +00:00
pci: {
requirement: req.params.requirement,
description: pci_description
}
2019-01-31 14:41:51 +00:00
};
2018-09-10 08:32:49 +00:00
}
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:getPciRequirement', error.message || error);
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3010, 400, reply);
}
2018-09-10 08:32:49 +00:00
}
/**
* This get GDPR Requirements
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
* @returns {Array<Object>} requirements or ErrorResponse
*/
2018-09-10 08:32:49 +00:00
async getGdprRequirement(req, reply) {
try {
let gdpr_description = '';
2018-09-10 08:32:49 +00:00
if (req.params.requirement === 'all') {
if (!req.headers.id) {
2019-01-31 14:41:51 +00:00
return gdprRequirementsFile;
2018-09-10 08:32:49 +00:00
}
2018-12-13 11:30:28 +00:00
const api = await this.wzWrapper.getWazuhConfigurationById(
2018-09-10 08:32:49 +00:00
req.headers.id
);
// Checking for GDPR
const version = await needle(
'get',
2018-12-13 11:30:28 +00:00
`${api.url}:${api.port}/version`,
2018-09-10 08:32:49 +00:00
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(api)
2018-09-10 08:32:49 +00:00
);
const number = version.body.data;
const major = number.split('v')[1].split('.')[0];
const minor = number
.split('v')[1]
.split('.')[1]
.split('.')[0];
const patch = number
.split('v')[1]
.split('.')[1]
.split('.')[1];
if (
(major >= 3 && minor < 2) ||
(major >= 3 && minor >= 2 && patch < 3)
) {
2019-01-31 14:41:51 +00:00
return {};
2018-09-10 08:32:49 +00:00
}
2018-12-13 11:30:28 +00:00
if (api.error_code > 1) {
2019-04-15 10:47:45 +00:00
log(
'wazuh-api:getGdprRequirement',
'Elasticsearch unexpected error or cannot connect'
);
2018-09-10 08:32:49 +00:00
// Can not connect to elasticsearch
return ErrorResponse(
'Elasticsearch unexpected error or cannot connect',
3024,
400,
reply
);
2018-12-13 11:30:28 +00:00
} else if (api.error_code > 0) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:getGdprRequirement', 'Credentials do not exist');
2018-09-10 08:32:49 +00:00
// Credentials not found
2019-04-15 10:47:45 +00:00
return ErrorResponse('Credentials do not exist', 3025, 400, reply);
}
2018-09-10 08:32:49 +00:00
const response = await needle(
'get',
2018-12-13 11:30:28 +00:00
`${api.url}:${api.port}/rules/gdpr`,
2018-09-10 08:32:49 +00:00
{},
2018-12-13 11:30:28 +00:00
ApiHelper.buildOptionsObject(api)
2018-09-10 08:32:49 +00:00
);
2018-12-28 15:34:38 +00:00
if ((((response || {}).body || {}).data || {}).items) {
2018-09-10 08:32:49 +00:00
let GDPRobject = {};
2018-12-28 15:34:38 +00:00
for (const item of response.body.data.items) {
2018-09-10 08:32:49 +00:00
if (typeof gdprRequirementsFile[item] !== 'undefined')
GDPRobject[item] = gdprRequirementsFile[item];
}
2019-01-31 14:41:51 +00:00
return GDPRobject;
2018-09-10 08:32:49 +00:00
} else {
2019-04-15 10:47:45 +00:00
log(
'wazuh-api:getGdprRequirement',
'An error occurred trying to parse GDPR requirements'
);
2018-09-10 08:32:49 +00:00
return ErrorResponse(
'An error occurred trying to parse GDPR requirements',
3026,
400,
reply
);
}
} else {
if (
typeof gdprRequirementsFile[req.params.requirement] !== 'undefined'
) {
gdpr_description = gdprRequirementsFile[req.params.requirement];
}
2019-01-31 14:41:51 +00:00
return {
2018-09-10 08:32:49 +00:00
gdpr: {
requirement: req.params.requirement,
description: gdpr_description
}
2019-01-31 14:41:51 +00:00
};
2018-09-10 08:32:49 +00:00
}
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:getGdprRequirement', error.message || error);
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3027, 400, reply);
}
}
checkResponseIsDown(response) {
const responseBody = (response || {}).body || {};
const responseError = responseBody.error || false;
// Avoid "Error communicating with socket" like errors
const socketErrorCodes = [1013, 1014, 1017, 1018, 1019];
const isDown = socketErrorCodes.includes(responseError || 1);
isDown &&
log(
'wazuh-api:makeRequest',
'Wazuh API is online but Wazuh is not ready yet'
);
return isDown;
}
2019-08-07 08:31:59 +00:00
/**
* This get PCI requirements
* @param {Object} req
* @param {Object} reply
* @returns {Array<Object>} requirements or ErrorResponse
*/
async getHipaaRequirement(req, reply) {
try {
let hipaa_description = '';
if (req.params.requirement === 'all') {
if (!req.headers.id) {
return hipaaRequirementsFile;
}
let api = await this.wzWrapper.getWazuhConfigurationById(
req.headers.id
);
if (api.error_code > 1) {
log(
'wazuh-api:getHipaaRequirement',
'Elasticsearch unexpected error or cannot connect'
);
// Can not connect to elasticsearch
return ErrorResponse(
'Elasticsearch unexpected error or cannot connect',
3007,
400,
reply
);
} else if (api.error_code > 0) {
log('wazuh-api:getHipaaRequirement', 'Credentials do not exist');
// Credentials not found
return ErrorResponse('Credentials do not exist', 3008, 400, reply);
}
const response = await needle(
'get',
`${api.url}:${api.port}/rules/hipaa`,
{},
ApiHelper.buildOptionsObject(api)
);
if ((((response || {}).body || {}).data || {}).items) {
let HIPAAobject = {};
for (const item of response.body.data.items) {
if (typeof hipaaRequirementsFile[item] !== 'undefined')
HIPAAobject[item] = hipaaRequirementsFile[item];
}
return HIPAAobject;
} else {
log(
'wazuh-api:getPciRequirement',
'An error occurred trying to parse HIPAA requirements'
);
return ErrorResponse(
'An error occurred trying to parse HIPAA requirements',
3009,
400,
reply
);
}
} else {
if (
typeof hipaaRequirementsFile[req.params.requirement] !== 'undefined'
) {
hipaa_description = hipaaRequirementsFile[req.params.requirement];
}
return {
hipaa: {
requirement: req.params.requirement,
description: hipaa_description
}
};
}
} catch (error) {
log('wazuh-api:getPciRequirement', error.message || error);
return ErrorResponse(error.message || error, 3010, 400, reply);
}
}
/**
* This get NIST 800-53 requirements
* @param {Object} req
* @param {Object} reply
* @returns {Array<Object>} requirements or ErrorResponse
*/
async getNistRequirement(req, reply) {
try {
let nist_description = '';
if (req.params.requirement === 'all') {
if (!req.headers.id) {
return nistRequirementsFile;
}
let api = await this.wzWrapper.getWazuhConfigurationById(
req.headers.id
);
if (api.error_code > 1) {
log(
'wazuh-api:getNistRequirement',
'Elasticsearch unexpected error or cannot connect'
);
// Can not connect to elasticsearch
return ErrorResponse(
'Elasticsearch unexpected error or cannot connect',
3007,
400,
reply
);
} else if (api.error_code > 0) {
log('wazuh-api:getNistRequirement', 'Credentials do not exist');
// Credentials not found
return ErrorResponse('Credentials do not exist', 3008, 400, reply);
}
const response = await needle(
'get',
`${api.url}:${api.port}/rules/nist-800-53`,
{},
ApiHelper.buildOptionsObject(api)
);
if ((((response || {}).body || {}).data || {}).items) {
let NISTobject = {};
for (const item of response.body.data.items) {
if (typeof nistRequirementsFile[item] !== 'undefined')
NISTobject[item] = nistRequirementsFile[item];
}
return NISTobject;
} else {
log(
'wazuh-api:getNistRequirement',
'An error occurred trying to parse NIST 800-53 requirements'
);
return ErrorResponse(
'An error occurred trying to parse NIST 800-53 requirements',
3009,
400,
reply
);
}
} else {
if (
typeof nistRequirementsFile[req.params.requirement] !== 'undefined'
) {
nist_description = nistRequirementsFile[req.params.requirement];
}
return {
nist: {
requirement: req.params.requirement,
description: nist_description
}
};
}
} catch (error) {
log('wazuh-api:getNistRequirement', error.message || error);
return ErrorResponse(error.message || error, 3010, 400, reply);
}
}
/**
* Check main Wazuh daemons status
* @param {*} api API entry stored in .wazuh
* @param {*} path Optional. Wazuh API target path.
*/
async checkDaemons(api, path) {
try {
const response = await needle(
'GET',
getPath(api) + '/manager/status',
{},
ApiHelper.buildOptionsObject(api)
);
const daemons = ((response || {}).body || {}).data || {};
const isCluster =
((api || {}).cluster_info || {}).status === 'enabled' &&
typeof daemons['wazuh-clusterd'] !== 'undefined';
const wazuhdbExists = typeof daemons['wazuh-db'] !== 'undefined';
const execd = daemons['ossec-execd'] === 'running';
const modulesd = daemons['wazuh-modulesd'] === 'running';
const wazuhdb = wazuhdbExists ? daemons['wazuh-db'] === 'running' : true;
const clusterd = isCluster
? daemons['wazuh-clusterd'] === 'running'
: true;
const isValid = execd && modulesd && wazuhdb && clusterd;
2019-04-15 10:47:45 +00:00
isValid && log('wazuh-api:checkDaemons', `Wazuh is ready`, 'debug');
if (path === '/ping') {
return { isValid };
}
if (!isValid) {
throw new Error('Wazuh not ready yet');
}
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:checkDaemons', error.message || error);
return Promise.reject(error);
}
}
sleep(timeMs) {
2019-04-15 09:10:03 +00:00
// eslint-disable-next-line
return new Promise((resolve, reject) => {
setTimeout(resolve, timeMs);
});
}
/**
* Helper method for Dev Tools.
* https://documentation.wazuh.com/current/user-manual/api/reference.html
* Depending on the method and the path some parameters should be an array or not.
* Since we allow the user to write the request using both comma-separated and array as well,
* we need to check if it should be transformed or not.
* @param {*} method The request method
* @param {*} path The Wazuh API path
*/
shouldKeepArrayAsIt(method, path) {
// Methods that we must respect a do not transform them
const isAgentsRestart = method === 'POST' && path === '/agents/restart';
const isActiveResponse =
method === 'PUT' && path.startsWith('/active-response/');
const isAddingAgentsToGroup =
method === 'POST' && path.startsWith('/agents/group/');
// Returns true only if one of the above conditions is true
return isAgentsRestart || isActiveResponse || isAddingAgentsToGroup;
}
/**
2019-01-14 10:32:36 +00:00
* This performs a request over Wazuh API and returns its response
* @param {String} method Method: GET, PUT, POST, DELETE
* @param {String} path API route
* @param {Object} data data and params to perform the request
* @param {String} id API id
2018-12-13 10:02:53 +00:00
* @param {Object} reply
* @returns {Object} API response or ErrorResponse
*/
async makeRequest(method, path, data, id, reply) {
2019-01-15 09:47:39 +00:00
const devTools = !!(data || {}).devTools;
2018-09-10 08:32:49 +00:00
try {
2018-12-13 11:30:28 +00:00
const api = await this.wzWrapper.getWazuhConfigurationById(id);
2018-09-10 08:32:49 +00:00
2019-01-14 11:12:24 +00:00
if (devTools) {
2019-01-14 10:45:25 +00:00
delete data.devTools;
}
2019-01-14 11:12:24 +00:00
2018-12-13 11:30:28 +00:00
if (api.error_code > 1) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:makeRequest', 'Could not connect with Elasticsearch');
2018-09-10 08:32:49 +00:00
//Can not connect to elasticsearch
return ErrorResponse(
2019-04-15 10:47:45 +00:00
'Could not connect with Elasticsearch',
2018-09-10 08:32:49 +00:00
3011,
404,
reply
);
2018-12-13 11:30:28 +00:00
} else if (api.error_code > 0) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:makeRequest', 'Credentials do not exist');
2018-09-10 08:32:49 +00:00
//Credentials not found
2019-04-15 10:47:45 +00:00
return ErrorResponse('Credentials do not exist', 3012, 404, reply);
2018-09-10 08:32:49 +00:00
}
if (!data) {
data = {};
}
2018-12-13 11:30:28 +00:00
const options = ApiHelper.buildOptionsObject(api);
2018-09-10 08:32:49 +00:00
// Set content type application/xml if needed
if (
typeof (data || {}).content === 'string' &&
(data || {}).origin === 'xmleditor'
) {
options.content_type = 'application/xml';
data = data.content;
}
2019-01-25 12:02:53 +00:00
if (
typeof (data || {}).content === 'string' &&
(data || {}).origin === 'json'
) {
options.content_type = 'application/json';
data = data.content.replace(new RegExp('\\n', 'g'), '');
}
2019-01-29 16:07:43 +00:00
if (
typeof (data || {}).content === 'string' &&
(data || {}).origin === 'raw'
) {
options.content_type = 'application/octet-stream';
data = data.content;
}
const delay = (data || {}).delay || 0;
let fullUrl = getPath(api) + path;
if (delay) {
const current = new Date();
this.queue.addJob({
startAt: new Date(current.getTime() + delay),
type: 'request',
method,
fullUrl,
data,
options
});
return { error: 0, message: 'Success' };
}
if (path === '/ping') {
try {
const check = await this.checkDaemons(api, path);
return check;
} catch (error) {
const isDown = (error || {}).code === 'ECONNREFUSED';
if (!isDown) {
log(
'wazuh-api:makeRequest',
'Wazuh API is online but Wazuh is not ready yet'
);
return ErrorResponse('ERROR3099', 3099, 500, reply);
}
2019-04-15 10:47:45 +00:00
}
}
2019-06-03 11:41:54 +00:00
log('wazuh-api:makeRequest', `${method} ${fullUrl}`, 'debug');
// Extract keys from parameters
const dataProperties = Object.keys(data);
// Transform arrays into comma-separated string if applicable.
// The reason is that we are accepting arrays for comma-separated
// parameters in the Dev Tools
if (!this.shouldKeepArrayAsIt(method, path)) {
for (const key of dataProperties) {
if (Array.isArray(data[key])) {
data[key] = data[key].join();
}
}
2019-06-03 11:41:54 +00:00
}
// DELETE must use URL query but we accept objects in Dev Tools
if (method === 'DELETE' && dataProperties.length) {
const query = querystring.stringify(data);
fullUrl += fullUrl.includes('?') ? `&${query}` : `?${query}`;
data = {};
}
2019-06-03 11:41:54 +00:00
const response = await needle(method, fullUrl, data, options);
2018-09-10 08:32:49 +00:00
const responseIsDown = this.checkResponseIsDown(response);
if (responseIsDown) {
return ErrorResponse('ERROR3099', 3099, 500, reply);
}
const responseBody = (response || {}).body || {};
const responseData = responseBody.data || false;
const responseError = responseBody.error || false;
if (!responseError && responseData) {
cleanKeys(response);
2019-01-31 14:41:51 +00:00
return response.body;
2018-09-10 08:32:49 +00:00
}
if (responseError && devTools) {
2019-01-31 14:41:51 +00:00
return response.body;
2019-01-14 10:32:36 +00:00
}
2019-01-14 10:45:25 +00:00
throw responseError && responseBody.message
? { message: responseBody.message, code: responseError }
2019-01-14 10:32:36 +00:00
: new Error('Unexpected error fetching data from the Wazuh API');
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:makeRequest', error.message || error);
if (devTools) {
2019-01-31 14:41:51 +00:00
return { error: '3013', message: error.message || error };
} else {
2019-01-21 15:34:27 +00:00
if ((error || {}).code && ApiErrorEquivalence[error.code]) {
error.message = ApiErrorEquivalence[error.code];
}
return ErrorResponse(
error.message || error,
error.code ? `Wazuh API error: ${error.code}` : 3013,
500,
reply
);
}
2018-06-01 07:51:24 +00:00
}
2018-09-10 08:32:49 +00:00
}
/**
* This performs a generic request and returs its response
* @param {String} method Method: GET, PUT, POST, DELETE
* @param {String} path API route
* @param {Object} data data and params to perform the request
* @param {String} id API id
*/
2018-09-10 08:32:49 +00:00
async makeGenericRequest(method, path, data, id) {
try {
2018-12-13 11:30:28 +00:00
const api = await this.wzWrapper.getWazuhConfigurationById(id);
2018-09-10 08:32:49 +00:00
2018-12-13 11:30:28 +00:00
if (api.error_code > 1) {
2018-09-10 08:32:49 +00:00
//Can not connect to elasticsearch
throw new Error('Could not connect with elasticsearch');
2018-12-13 11:30:28 +00:00
} else if (api.error_code > 0) {
2018-09-10 08:32:49 +00:00
//Credentials not found
throw new Error('Credentials does not exists');
}
if (!data) {
data = {};
}
2018-12-13 11:30:28 +00:00
const options = ApiHelper.buildOptionsObject(api);
2018-09-10 08:32:49 +00:00
2018-12-13 11:30:28 +00:00
const fullUrl = getPath(api) + path;
2019-04-15 10:47:45 +00:00
log('wazuh-api:makeGenericRequest', `${method} ${fullUrl}`, 'debug');
2018-09-10 08:32:49 +00:00
const response = await needle(method, fullUrl, data, options);
if (
response &&
response.body &&
!response.body.error &&
response.body.data
) {
cleanKeys(response);
2018-09-10 08:32:49 +00:00
return response.body;
}
2019-01-03 08:28:51 +00:00
throw ((response || {}).body || {}).error &&
((response || {}).body || {}).message
2018-09-28 13:23:47 +00:00
? { message: response.body.message, code: response.body.error }
2018-09-10 08:32:49 +00:00
: new Error('Unexpected error fetching data from the Wazuh API');
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:makeGenericRequest', error.message || error);
2018-09-10 08:32:49 +00:00
return Promise.reject(error);
}
}
/**
* This make a request to API
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
* @returns {Object} api response or ErrorResponse
*/
2018-09-10 08:32:49 +00:00
requestApi(req, reply) {
2018-10-30 13:21:00 +00:00
const configuration = getConfiguration();
const adminMode = !(
configuration &&
typeof configuration.admin !== 'undefined' &&
!configuration.admin
);
2018-11-15 08:39:12 +00:00
2018-09-10 08:32:49 +00:00
if (!req.payload.method) {
return ErrorResponse('Missing param: method', 3015, 400, reply);
} else if (!req.payload.path) {
return ErrorResponse('Missing param: path', 3016, 400, reply);
} else {
if (req.payload.method !== 'GET' && !adminMode) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:requestApi', 'Forbidden action, allowed methods: GET');
return ErrorResponse(
req.payload.body && req.payload.body.devTools
? 'Allowed method: [GET]'
: `Forbidden (${req.payload.method} ${req.payload.path}`,
3029,
400,
reply
);
2018-09-10 08:32:49 +00:00
}
if (req.payload.body.devTools) {
2019-01-14 10:45:25 +00:00
//delete req.payload.body.devTools;
2018-09-10 08:32:49 +00:00
const keyRegex = new RegExp(/.*agents\/\d*\/key.*/);
if (
typeof req.payload.path === 'string' &&
2018-10-30 13:21:00 +00:00
keyRegex.test(req.payload.path) &&
!adminMode
2018-09-10 08:32:49 +00:00
) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:makeRequest', 'Forbidden route /agents/:id/key');
2018-09-10 08:32:49 +00:00
return ErrorResponse(
2019-04-15 10:47:45 +00:00
'Forbidden route /agents/:id/key',
2018-09-10 08:32:49 +00:00
3028,
400,
reply
);
}
2018-09-10 08:32:49 +00:00
}
return this.makeRequest(
req.payload.method,
req.payload.path,
req.payload.body,
req.payload.id,
reply
);
}
2018-09-10 08:32:49 +00:00
}
/**
* Fetch agent status and insert it directly on demand
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
2019-04-15 10:47:45 +00:00
* @returns {Object} status obj or ErrorResponseerror.message || error
*/
2018-09-10 08:32:49 +00:00
async fetchAgents(req, reply) {
try {
const output = await this.monitoringInstance.fetchAgentsExternal();
2019-01-31 14:41:51 +00:00
return {
2018-09-10 08:32:49 +00:00
statusCode: 200,
error: '0',
data: '',
output
2019-01-31 14:41:51 +00:00
};
2018-09-10 08:32:49 +00:00
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:fetchAgents', error.message || error);
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3018, 500, reply);
}
}
/**
* Get full data on CSV format from a list Wazuh API endpoint
* @param {Object} req
* @param {Object} res
* @returns {Object} csv or ErrorResponse
2018-09-10 08:32:49 +00:00
*/
async csv(req, reply) {
try {
if (!req.payload || !req.payload.path)
throw new Error('Field path is required');
if (!req.payload.id) throw new Error('Field id is required');
2018-12-18 15:19:05 +00:00
const filters = Array.isArray(((req || {}).payload || {}).filters)
? req.payload.filters
: [];
2018-09-10 08:32:49 +00:00
const config = await this.wzWrapper.getWazuhConfigurationById(
req.payload.id
);
let tmpPath = req.payload.path;
2018-09-10 08:32:49 +00:00
if (tmpPath && typeof tmpPath === 'string') {
tmpPath = tmpPath[0] === '/' ? tmpPath.substr(1) : tmpPath;
2018-09-10 08:32:49 +00:00
}
if (!tmpPath) throw new Error('An error occurred parsing path field');
2018-09-10 08:32:49 +00:00
log('wazuh-api:csv', `Report ${tmpPath}`, 'debug');
2018-09-10 08:32:49 +00:00
// Real limit, regardless the user query
2019-01-15 12:05:06 +00:00
const params = { limit: 500 };
2018-09-10 08:32:49 +00:00
if (filters.length) {
for (const filter of filters) {
if (!filter.name || !filter.value) continue;
params[filter.name] = filter.value;
}
}
2018-12-13 11:30:28 +00:00
const cred = ApiHelper.buildOptionsObject(config);
2018-09-10 08:32:49 +00:00
let itemsArray = [];
2018-09-10 08:32:49 +00:00
const output = await needle(
'get',
`${config.url}:${config.port}/${tmpPath}`,
2018-09-10 08:32:49 +00:00
params,
cred
);
2019-05-02 15:50:25 +00:00
const totalItems = (((output || {}).body || {}).data || {}).totalItems;
if (totalItems) {
2018-09-10 08:32:49 +00:00
params.offset = 0;
itemsArray.push(...output.body.data.items);
while (itemsArray.length < totalItems && params.offset < totalItems) {
2018-09-10 08:32:49 +00:00
params.offset += params.limit;
const tmpData = await needle(
'get',
`${config.url}:${config.port}/${tmpPath}`,
2018-09-10 08:32:49 +00:00
params,
cred
);
itemsArray.push(...tmpData.body.data.items);
}
}
if (totalItems) {
const { path, filters } = req.payload;
const isList = path.includes('/lists') && filters && filters.length;
const isArrayOfLists =
path.includes('/lists') && (!filters || !filters.length);
const isAgents = path.includes('/agents') && !path.includes('groups');
const isAgentsOfGroup = path.startsWith('/agents/groups/');
let fields = Object.keys(output.body.data.items[0]);
if (isAgents || isAgentsOfGroup) {
fields = [
'id',
'status',
'name',
'ip',
'group',
'manager',
'node_name',
'dateAdd',
'version',
'lastKeepAlive',
'os.arch',
'os.build',
'os.codename',
'os.major',
'os.minor',
'os.name',
'os.platform',
'os.uname',
'os.version'
];
}
if (isArrayOfLists) {
const flatLists = [];
for (const list of itemsArray) {
const { path, items } = list;
flatLists.push(
...items.map(item => ({ path, key: item.key, value: item.value }))
);
}
fields = ['path', 'key', 'value'];
itemsArray = [...flatLists];
}
2018-09-10 08:32:49 +00:00
2019-05-02 15:50:25 +00:00
if (isList) {
fields = ['key', 'value'];
itemsArray = itemsArray[0];
2019-05-02 15:50:25 +00:00
}
2019-05-09 10:44:47 +00:00
fields = fields.map(item => ({ value: item, default: '-' }));
const json2csvParser = new Parser({ fields });
let csv = json2csvParser.parse(itemsArray);
2018-09-10 08:32:49 +00:00
for (const field of fields) {
const { value } = field;
if (csv.includes(value)) {
csv = csv.replace(value, KeyEquivalence[value] || value);
2018-09-10 08:32:49 +00:00
}
}
return reply.response(csv).type('text/csv');
2018-09-10 08:32:49 +00:00
} else if (
output &&
output.body &&
output.body.data &&
!output.body.data.totalItems
) {
throw new Error('No results');
} else {
throw new Error('An error occurred fetching data from the Wazuh API');
}
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:csv', error.message || error);
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3034, 500, reply);
}
}
/**
* Get the each filed unique values of agents
2018-12-13 10:02:53 +00:00
* @param {Object} req
* @param {Object} reply
* @returns {Array<Object>} unique fileds or ErrorResponse
*/
2018-09-10 08:32:49 +00:00
async getAgentsFieldsUniqueCount(req, reply) {
try {
if (!req.params || !req.params.api)
throw new Error('Field api is required');
const config = await this.wzWrapper.getWazuhConfigurationById(
req.params.api
);
2018-12-13 11:30:28 +00:00
const headers = ApiHelper.buildOptionsObject(config);
2018-09-10 08:32:49 +00:00
const distinctUrl = `${config.url}:${config.port}/summary/agents`;
2018-09-10 08:32:49 +00:00
const data = await needle('get', distinctUrl, {}, headers);
const response = ((data || {}).body || {}).data || {};
2018-10-22 14:51:20 +00:00
const nodes = response.nodes;
const groups = response.groups;
const osPlatforms = response.agent_os;
const versions = response.agent_version;
const summary = response.agent_status;
const lastAgent = response.last_registered_agent;
2018-10-22 14:51:20 +00:00
2018-09-10 08:32:49 +00:00
const result = {
groups: [],
nodes: [],
versions: [],
osPlatforms: [],
lastAgent: {},
summary: {
agentsCountActive: 0,
agentsCountDisconnected: 0,
agentsCountNeverConnected: 0,
agentsCountTotal: 0,
agentsCoverity: 0
2018-07-17 07:41:53 +00:00
}
2018-09-10 08:32:49 +00:00
};
2018-10-22 14:51:20 +00:00
if (nodes && nodes.items) {
result.nodes = nodes.items
2019-01-16 11:51:57 +00:00
.filter(item => !!item.node_name && item.node_name !== 'unknown')
2018-09-10 08:32:49 +00:00
.map(item => item.node_name);
}
2018-10-22 14:51:20 +00:00
if (groups && groups.items) {
result.groups = groups.items.map(item => item.name);
2018-09-10 08:32:49 +00:00
}
2018-10-22 14:51:20 +00:00
if (osPlatforms && osPlatforms.items) {
result.osPlatforms = osPlatforms.items
2018-09-10 08:32:49 +00:00
.filter(
item =>
!!item.os && item.os.platform && item.os.name && item.os.version
)
.map(item => item.os);
}
2018-10-22 14:51:20 +00:00
if (versions && versions.items) {
result.versions = versions.items
2018-09-10 08:32:49 +00:00
.filter(item => !!item.version)
.map(item => item.version);
}
2018-10-22 14:51:20 +00:00
if (summary) {
2018-09-10 08:32:49 +00:00
Object.assign(result.summary, {
2018-10-22 14:51:20 +00:00
agentsCountActive: summary.Active - 1,
agentsCountDisconnected: summary.Disconnected,
agentsCountNeverConnected: summary['Never connected'],
agentsCountTotal: summary.Total - 1,
2018-09-10 08:32:49 +00:00
agentsCoverity:
2018-10-22 14:51:20 +00:00
summary.Total - 1
? ((summary.Active - 1) / (summary.Total - 1)) * 100
2018-09-10 08:32:49 +00:00
: 0
});
}
if (lastAgent) {
Object.assign(result.lastAgent, lastAgent);
2018-09-10 08:32:49 +00:00
}
2019-01-31 14:41:51 +00:00
return { error: 0, result };
2018-09-10 08:32:49 +00:00
} catch (error) {
2019-04-15 10:47:45 +00:00
log('wazuh-api:getAgentsFieldsUniqueCount', error.message || error);
2018-09-10 08:32:49 +00:00
return ErrorResponse(error.message || error, 3035, 500, reply);
2018-07-17 07:41:53 +00:00
}
2018-09-10 08:32:49 +00:00
}
// Get de list of available requests in the API
2019-01-30 11:36:25 +00:00
getRequestList() {
//Read a static JSON until the api call has implemented
2019-01-30 11:36:25 +00:00
return apiRequestList;
}
2019-08-07 08:31:59 +00:00
/**
* This get the timestamp field
* @param {Object} req
* @param {Object} reply
* @returns {Object} timestamp field or ErrorResponse
*/
2019-08-16 11:12:34 +00:00
getTimeStamp(req, reply) {
2019-08-07 08:31:59 +00:00
try {
const source = JSON.parse(fs.readFileSync(this.wazuhVersion, 'utf8'));
if (source.installationDate && source.lastRestart) {
log(
'wazuh-api:getTimeStamp',
`Installation date: ${source.installationDate}. Last restart: ${source.lastRestart}`,
'debug'
);
return {
installationDate: source.installationDate,
lastRestart: source.lastRestart
};
} else {
throw new Error('Could not fetch wazuh-version registry');
}
} catch (error) {
log('wazuh-api:getTimeStamp', error.message || error);
return ErrorResponse(
error.message || 'Could not fetch wazuh-version registry',
4001,
500,
reply
);
}
}
/**
* This get the wazuh setup settings
* @param {Object} req
* @param {Object} reply
* @returns {Object} setup info or ErrorResponse
*/
async getSetupInfo(req, reply) {
try {
const source = JSON.parse(fs.readFileSync(this.wazuhVersion, 'utf8'));
return !Object.values(source).length
? { statusCode: 200, data: '' }
: { statusCode: 200, data: source };
} catch (error) {
log('wazuh-api:getSetupInfo', error.message || error);
return ErrorResponse(
`Could not get data from wazuh-version registry due to ${error.message ||
error}`,
4005,
500,
reply
);
}
}
/**
* Get basic syscollector information for given agent.
* @param {Object} req
* @param {Object} reply
* @returns {Object} Basic syscollector information
*/
async getSyscollector(req, reply) {
try {
if (!req.params || !req.headers.id || !req.params.agent) {
throw new Error('Agent ID and API ID are required');
}
const { agent } = req.params;
const api = req.headers.id;
const config = await this.wzWrapper.getWazuhConfigurationById(api);
const headers = ApiHelper.buildOptionsObject(config);
const data = await Promise.all([
needle(
'get',
`${config.url}:${config.port}/syscollector/${agent}/hardware`,
{},
headers
),
needle(
'get',
`${config.url}:${config.port}/syscollector/${agent}/os`,
{},
headers
)
]);
const result = data.map(item => (item.body || {}).data || false);
const [hardwareResponse, osResponse] = result;
// Fill syscollector object
const syscollector = {
hardware:
typeof hardwareResponse === 'object' &&
Object.keys(hardwareResponse).length
? { ...hardwareResponse }
: false,
os:
typeof osResponse === 'object' && Object.keys(osResponse).length
? { ...osResponse }
: false
};
return syscollector;
} catch (error) {
log('wazuh-api:getSyscollector', error.message || error);
return ErrorResponse(error.message || error, 3035, 500, reply);
}
}
}