151 lines
No EOL
4.9 KiB
JavaScript
151 lines
No EOL
4.9 KiB
JavaScript
/**
|
|
* sigma_details_service.js
|
|
*
|
|
* This service provides functionality for retrieving and explaining Sigma rules.
|
|
*/
|
|
const logger = require('../../utils/logger');
|
|
const { convertSigmaRule, extractDetectionCondition } = require('./sigma_converter_service');
|
|
const { debugRuleContent, getRuleYamlContent } = require('../../sigma_db/queries');
|
|
|
|
const { getFileName } = require('../../utils/file_utils');
|
|
const FILE_NAME = getFileName(__filename);
|
|
|
|
/**
|
|
* Explains a Sigma rule by providing a simplified, human-readable format
|
|
* Performs diagnostics before explanation and handles error cases
|
|
*
|
|
* @param {string} ruleId - The ID of the rule to explain
|
|
* @returns {Promise<Object>} Result object with success flag and explanation or error message
|
|
*/
|
|
async function getSigmaRuleDetails(ruleId) {
|
|
if (!ruleId) {
|
|
logger.warn(`${FILE_NAME}: Cannot explain rule: Missing rule ID`);
|
|
return {
|
|
success: false,
|
|
message: 'Missing rule ID'
|
|
};
|
|
}
|
|
|
|
logger.info(`${FILE_NAME}: Running diagnostics for rule: ${ruleId}`);
|
|
logger.info(`${FILE_NAME}: Explaining rule ${ruleId}`);
|
|
|
|
try {
|
|
// Run diagnostics on the rule content first
|
|
const diagnosticResult = await debugRuleContent(ruleId);
|
|
logger.debug(`${FILE_NAME}: Diagnostic result: ${JSON.stringify(diagnosticResult || {})}`);
|
|
|
|
// Convert the rule ID to a structured object
|
|
const conversionResult = await convertSigmaRule(ruleId);
|
|
if (!conversionResult.success) {
|
|
logger.warn(`${FILE_NAME}: Failed to convert rule ${ruleId}: ${conversionResult.message}`);
|
|
return {
|
|
success: false,
|
|
message: conversionResult.message || `Failed to parse rule with ID ${ruleId}`
|
|
};
|
|
}
|
|
|
|
const rule = conversionResult.rule;
|
|
|
|
// Extra safety check
|
|
if (!rule) {
|
|
logger.error(`${FILE_NAME}: Converted rule is null for ID ${ruleId}`);
|
|
return {
|
|
success: false,
|
|
message: `Failed to process rule with ID ${ruleId}`
|
|
};
|
|
}
|
|
|
|
// Create a simplified explanation with safe access to properties
|
|
const explanation = {
|
|
id: rule.id || ruleId,
|
|
title: rule.title || 'Untitled Rule',
|
|
description: rule.description || 'No description provided',
|
|
author: rule.author || 'Unknown author',
|
|
severity: rule.level || 'Unknown',
|
|
logsource: rule.logsource || {}, // Add this line to include logsource info
|
|
detectionExplanation: extractDetectionCondition(rule),
|
|
falsePositives: Array.isArray(rule.falsepositives) ? rule.falsepositives :
|
|
typeof rule.falsepositives === 'string' ? [rule.falsepositives] :
|
|
['None specified'],
|
|
tags: Array.isArray(rule.tags) ? rule.tags : [],
|
|
references: Array.isArray(rule.references) ? rule.references : []
|
|
};
|
|
|
|
logger.info(`${FILE_NAME}: Successfully explained rule ${ruleId}`);
|
|
logger.debug(`${FILE_NAME}: Explanation properties: ${Object.keys(explanation).join(', ')}`);
|
|
|
|
return {
|
|
success: true,
|
|
explanation
|
|
};
|
|
} catch (error) {
|
|
logger.error(`${FILE_NAME}: Error explaining rule: ${error.message}`);
|
|
logger.debug(`${FILE_NAME}: Error stack: ${error.stack}`);
|
|
return {
|
|
success: false,
|
|
message: `Error explaining rule: ${error.message}`
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the raw YAML content of a Sigma rule
|
|
* Retrieves the content from the database
|
|
*
|
|
* @param {string} ruleId - The ID of the rule to get YAML for
|
|
* @returns {Promise<Object>} Result object with success flag and YAML content or error message
|
|
*/
|
|
async function getSigmaRuleYaml(ruleId) {
|
|
if (!ruleId) {
|
|
logger.warn(`${FILE_NAME}: Cannot get YAML: Missing rule ID`);
|
|
return {
|
|
success: false,
|
|
message: 'Missing rule ID'
|
|
};
|
|
}
|
|
|
|
logger.info(`${FILE_NAME}: Getting YAML content for rule: ${ruleId}`);
|
|
|
|
try {
|
|
// Get YAML content from database
|
|
const yamlResult = await getRuleYamlContent(ruleId);
|
|
|
|
if (!yamlResult.success) {
|
|
logger.warn(`${FILE_NAME}: Failed to retrieve YAML for rule ${ruleId}: ${yamlResult.message}`);
|
|
return {
|
|
success: false,
|
|
message: yamlResult.message || `Failed to retrieve YAML for rule with ID ${ruleId}`
|
|
};
|
|
}
|
|
|
|
// Add extra safety check for content
|
|
if (!yamlResult.content) {
|
|
logger.warn(`${FILE_NAME}: YAML content is empty for rule ${ruleId}`);
|
|
return {
|
|
success: true,
|
|
yaml: '',
|
|
warning: 'YAML content is empty for this rule'
|
|
};
|
|
}
|
|
|
|
logger.debug(`${FILE_NAME}: Successfully retrieved YAML content with length: ${yamlResult.content.length}`);
|
|
|
|
// Return the YAML content
|
|
return {
|
|
success: true,
|
|
yaml: yamlResult.content
|
|
};
|
|
} catch (error) {
|
|
logger.error(`${FILE_NAME}: Error retrieving YAML: ${error.message}`);
|
|
logger.debug(`${FILE_NAME}: Error stack: ${error.stack}`);
|
|
return {
|
|
success: false,
|
|
message: `Error retrieving YAML: ${error.message}`
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getSigmaRuleDetails,
|
|
getSigmaRuleYaml
|
|
}; |