From bfabd6de2ae4bb4096ab2c4e1791a3fd44ae00af Mon Sep 17 00:00:00 2001 From: Charlotte Croce Date: Fri, 18 Apr 2025 13:06:09 -0400 Subject: [PATCH] refactor elastic api into multiple files --- src/handlers/sigma/sigma_action_handlers.js | 4 +- src/services/elastic/elastic_api_service.js | 83 ---------------- .../elastic_send_rule_to_siem_service.js | 96 +++++++++++++++++++ 3 files changed, 98 insertions(+), 85 deletions(-) create mode 100644 src/services/elastic/elastic_send_rule_to_siem_service.js diff --git a/src/handlers/sigma/sigma_action_handlers.js b/src/handlers/sigma/sigma_action_handlers.js index 49edcd5..81a0445 100644 --- a/src/handlers/sigma/sigma_action_handlers.js +++ b/src/handlers/sigma/sigma_action_handlers.js @@ -12,9 +12,9 @@ const { getYamlViewBlocks } = require('../../blocks/sigma/sigma_view_yaml_block' const { getSearchResultBlocks } = require('../../blocks/sigma/sigma_search_results_block'); const { getConversionResultBlocks } = require('../../blocks/sigma/sigma_conversion_block'); const { getRuleExplanationBlocks } = require('../../blocks/sigma/sigma_details_block'); -const { sendRuleToSiem } = require('../../services/elastic/elastic_api_service'); -const { getSpaceSelectionBlocks } = require('../../blocks/sigma/sigma_space_selection_block'); +const { sendRuleToSiem } = require('../../services/elastic/elastic_send_rule_to_siem_service'); const { getAllSpaces } = require('../../services/elastic/elastic_api_service'); +const { getSpaceSelectionBlocks } = require('../../blocks/sigma/sigma_space_selection_block'); const { SIGMA_CLI_CONFIG, ELASTICSEARCH_CONFIG } = require('../../config/appConfig'); diff --git a/src/services/elastic/elastic_api_service.js b/src/services/elastic/elastic_api_service.js index 965c36b..79107c6 100644 --- a/src/services/elastic/elastic_api_service.js +++ b/src/services/elastic/elastic_api_service.js @@ -49,88 +49,6 @@ const getAllSpaces = () => { return ELASTICSEARCH_CONFIG.spaces || []; }; -/** - * Send a rule to Elasticsearch SIEM in a specific space - * - * @param {Object} rulePayload - The rule payload to send to Elasticsearch - * @param {string} spaceId - The ID of the space to send the rule to - * @returns {Promise} - Object containing success status and response/error information - */ -const sendRuleToSiem = async (rulePayload, spaceId = 'default') => { - logger.info(`${FILE_NAME}: Sending rule to Elasticsearch SIEM in space: ${spaceId}`); - - try { - const elasticConfig = getElasticConfig(spaceId); - const baseApiUrl = elasticConfig.apiEndpoint; - - // Construct space-specific URL if needed - let apiUrl = baseApiUrl; - if (spaceId && spaceId !== 'default') { - // Insert space ID into URL: http://localhost:5601/api/detection_engine/rules - // becomes http://localhost:5601/s/space-id/api/detection_engine/rules - const urlParts = baseApiUrl.split('/api/'); - apiUrl = `${urlParts[0]}/s/${spaceId}/api/${urlParts[1]}`; - } - - logger.debug(`${FILE_NAME}: Using Elasticsearch API URL: ${apiUrl}`); - - // Add index pattern to rule if provided by space config - if (elasticConfig.space && elasticConfig.space.indexPattern && !rulePayload.index) { - rulePayload.index = Array.isArray(elasticConfig.space.indexPattern) - ? elasticConfig.space.indexPattern - : [elasticConfig.space.indexPattern]; - logger.debug(`${FILE_NAME}: Adding index pattern to rule: ${JSON.stringify(rulePayload.index)}`); - } - - // Send the request to Elasticsearch - const response = await axios({ - method: 'post', - url: apiUrl, - headers: { - 'Content-Type': 'application/json', - 'kbn-xsrf': 'true' - }, - auth: { - username: elasticConfig.username, - password: elasticConfig.password - }, - data: rulePayload - }); - - // Process the response - if (response.status >= 200 && response.status < 300) { - logger.info(`${FILE_NAME}: Successfully sent rule to SIEM in space: ${spaceId}`); - return { - success: true, - status: response.status, - data: response.data, - space: elasticConfig.space - }; - } else { - logger.error(`${FILE_NAME}: Error sending rule to SIEM. Status: ${response.status}, Response: ${JSON.stringify(response.data)}`); - return { - success: false, - status: response.status, - message: `Failed to add rule to SIEM in space ${spaceId}. Status: ${response.status}`, - data: response.data - }; - } - } catch (error) { - logger.error(`${FILE_NAME}: API error sending rule to SIEM: ${error.message}`); - logger.debug(`${FILE_NAME}: API error details: ${error.response ? JSON.stringify(error.response.data) : 'No response data'}`); - - const errorMessage = error.response && error.response.data && error.response.data.message - ? error.response.data.message - : error.message; - - return { - success: false, - message: errorMessage, - error: error - }; - } -}; - /** * Make a generic request to an Elasticsearch API endpoint * @@ -205,7 +123,6 @@ const makeElasticRequest = async (options) => { }; module.exports = { - sendRuleToSiem, makeElasticRequest, getElasticConfig, getAllSpaces diff --git a/src/services/elastic/elastic_send_rule_to_siem_service.js b/src/services/elastic/elastic_send_rule_to_siem_service.js new file mode 100644 index 0000000..aa32d2f --- /dev/null +++ b/src/services/elastic/elastic_send_rule_to_siem_service.js @@ -0,0 +1,96 @@ +/** + * elastic_send_rule_to_siem_service.js + * + * Service for sending rules to Elasticsearch SIEM + */ +const axios = require('axios'); +const logger = require('../../utils/logger'); +const { getElasticConfig } = require('./elastic_api_service'); + +const FILE_NAME = 'elastic_send_rule_to_siem_service.js'; + +/** + * Send a rule to Elasticsearch SIEM in a specific space + * + * @param {Object} rulePayload - The rule payload to send to Elasticsearch + * @param {string} spaceId - The ID of the space to send the rule to + * @returns {Promise} - Object containing success status and response/error information + */ +const sendRuleToSiem = async (rulePayload, spaceId = 'default') => { + logger.info(`${FILE_NAME}: Sending rule to Elasticsearch SIEM in space: ${spaceId}`); + + try { + const elasticConfig = getElasticConfig(spaceId); + const baseApiUrl = elasticConfig.apiEndpoint; + + // Construct space-specific URL if needed + let apiUrl = baseApiUrl; + if (spaceId && spaceId !== 'default') { + // Insert space ID into URL: http://localhost:5601/api/detection_engine/rules + // becomes http://localhost:5601/s/space-id/api/detection_engine/rules + const urlParts = baseApiUrl.split('/api/'); + apiUrl = `${urlParts[0]}/s/${spaceId}/api/${urlParts[1]}`; + } + + logger.debug(`${FILE_NAME}: Using Elasticsearch API URL: ${apiUrl}`); + + // Add index pattern to rule if provided by space config + if (elasticConfig.space && elasticConfig.space.indexPattern && !rulePayload.index) { + rulePayload.index = Array.isArray(elasticConfig.space.indexPattern) + ? elasticConfig.space.indexPattern + : [elasticConfig.space.indexPattern]; + logger.debug(`${FILE_NAME}: Adding index pattern to rule: ${JSON.stringify(rulePayload.index)}`); + } + + // Send the request to Elasticsearch + const response = await axios({ + method: 'post', + url: apiUrl, + headers: { + 'Content-Type': 'application/json', + 'kbn-xsrf': 'true' + }, + auth: { + username: elasticConfig.username, + password: elasticConfig.password + }, + data: rulePayload + }); + + // Process the response + if (response.status >= 200 && response.status < 300) { + logger.info(`${FILE_NAME}: Successfully sent rule to SIEM in space: ${spaceId}`); + return { + success: true, + status: response.status, + data: response.data, + space: elasticConfig.space + }; + } else { + logger.error(`${FILE_NAME}: Error sending rule to SIEM. Status: ${response.status}, Response: ${JSON.stringify(response.data)}`); + return { + success: false, + status: response.status, + message: `Failed to add rule to SIEM in space ${spaceId}. Status: ${response.status}`, + data: response.data + }; + } + } catch (error) { + logger.error(`${FILE_NAME}: API error sending rule to SIEM: ${error.message}`); + logger.debug(`${FILE_NAME}: API error details: ${error.response ? JSON.stringify(error.response.data) : 'No response data'}`); + + const errorMessage = error.response && error.response.data && error.response.data.message + ? error.response.data.message + : error.message; + + return { + success: false, + message: errorMessage, + error: error + }; + } +}; + +module.exports = { + sendRuleToSiem +}; \ No newline at end of file