const fs = require('fs'); const winston = require("winston"); const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.printf(info => { return `${info.timestamp} ${info.level}: ${info.message}`; }) ), transports: [ new winston.transports.Console(), new winston.transports.File({ filename: './log/RuleEngineError.log', level: 'error' }), new winston.transports.File({ filename: './log/Combined.log' }) ] }); exports.RuleEngine = class RuleEngine { constructor(ruleSetFiles) { logger.log("info", "Instanciated RulesEngine - RuleSetFiles: " + ruleSetFiles); this.ruleSet = {}; if (ruleSetFiles === "*") { fs.readdirSync("./rules/").forEach(file => { if (this.reTest("/.*\.rule\.json$/", file)) { logger.log("info", "Loading ruleset file " + file); let newRuleSet = JSON.parse(fs.readFileSync('./rules/' + file, 'utf8')); logger.log("info", "Adding ruleset " + Object.keys(newRuleSet)[0]); this.ruleSet[Object.keys(newRuleSet)[0]] = newRuleSet[Object.keys(newRuleSet)[0]] } }); } else if (ruleSetFiles.indexOf(",") > 1) { ruleSetFiles.split(",").forEach(file => { logger.log("info", "Loading ruleset file " + file); let newRuleSet = JSON.parse(fs.readFileSync('./rules/' + file + '.rule.json', 'utf8')); logger.log("info", "Adding ruleset " + Object.keys(newRuleSet)[0]); this.ruleSet[Object.keys(newRuleSet)[0]] = newRuleSet[Object.keys(newRuleSet)[0]] }); } else { logger.log("info", "Loading ruleset file " + ruleSetFiles); this.ruleSet = JSON.parse(fs.readFileSync('./rules/' + ruleSetFiles + '.rule.json', 'utf8')); logger.log("info", "Adding Ruleset " + Object.keys(this.ruleSet)[0]); } } processData(inputLine) { let inputData = inputLine.data; logger.log("debug", "ProcessingType " + inputLine.processingType); logger.log("debug", "InputLine " + JSON.stringify(inputLine)); let allWhiteFilterRules = this.ruleSet[inputLine.processingType].rules; if (this.processLogicOr(allWhiteFilterRules, inputData)) { return (true); } logger.log("debug", "No whitelisting matched; returning false"); return (false); } processLogicAnd(allWhiteFilterRules, inputData) { let retVal = true; logger.log("debug", "Logic AND - start"); for (let i = 0; i < allWhiteFilterRules.length; i++) { let theWhiteFilterRule = allWhiteFilterRules[i]; logger.log("debug", " Logic AND - whiteFilterRule: " + JSON.stringify(theWhiteFilterRule)); if (theWhiteFilterRule.Logic === "-") { if (!this.processLogicFlat(theWhiteFilterRule, inputData) && retVal === true) { logger.log("debug", " Logic AND - FLAT - Changing Result to false"); retVal = false; }; } else if (theWhiteFilterRule.Logic === "|") { if (!this.processLogicOr(theWhiteFilterRule.rules, inputData) && retVal === true) { logger.log("debug", " Logic AND - OR - Changing Result to false"); retVal = false; }; } else if (theWhiteFilterRule.Logic === "&") { if (!this.processLogicAnd(theWhiteFilterRule.rules, inputData) && retVal === true) { logger.log("debug", " Logic AND - AND - Changing Result to false"); retVal = false; }; } }; logger.log("debug", "Logic AND - end - result: " + retVal); return (retVal); } processLogicOr(allWhiteFilterRules, inputData) { logger.log("debug", "Logic OR - start"); for (let i = 0; i < allWhiteFilterRules.length; i++) { let theWhiteFilterRule = allWhiteFilterRules[i]; logger.log("debug", " Logic OR - whiteFilterRule: " + JSON.stringify(theWhiteFilterRule)); if (theWhiteFilterRule.Logic === "-") { if (this.processLogicFlat(theWhiteFilterRule, inputData)) { logger.log("debug", " Logic OR - FLAT - RETURNING OUT"); return (true); }; } else if (theWhiteFilterRule.Logic === "|") { if (this.processLogicOr(theWhiteFilterRule.rules, inputData)) { logger.log("debug", " Logic OR - OR - RETURNING OUT"); return (true) }; } else if (theWhiteFilterRule.Logic === "&") { if (this.processLogicAnd(theWhiteFilterRule.rules, inputData)) { logger.log("debug", " Logic OR - AND - RETURNING OUT"); return (true) }; } }; logger.log("debug", "Logic OR - end"); return (false); } processLogicFlat(theWhiteFilterRule, inputData) { logger.log("debug", "Logic FLAT start - whiteFilterRule: " + JSON.stringify(theWhiteFilterRule)); logger.log("debug", "inputData: " + JSON.stringify(inputData)); let isKnownComp = false; let retVal = false; if (theWhiteFilterRule.Comp === "===") { isKnownComp = true; if (inputData[theWhiteFilterRule.Field] === theWhiteFilterRule.Value) {retVal = true;} } else if (theWhiteFilterRule.Comp === "!==") { isKnownComp = true; if (inputData[theWhiteFilterRule.Field] !== theWhiteFilterRule.Value) {retVal = true;} } else if (theWhiteFilterRule.Comp === "<") { isKnownComp = true; if (inputData[theWhiteFilterRule.Field] < theWhiteFilterRule.Value) {retVal = true;} } else if (theWhiteFilterRule.Comp === ">") { isKnownComp = true; if (inputData[theWhiteFilterRule.Field] > theWhiteFilterRule.Value) {retVal = true;} } else if (theWhiteFilterRule.Comp === "<=") { isKnownComp = true; if (inputData[theWhiteFilterRule.Field] <= theWhiteFilterRule.Value) {retVal = true;} } else if (theWhiteFilterRule.Comp === ">=") { isKnownComp = true; if (inputData[theWhiteFilterRule.Field] >= theWhiteFilterRule.Value) {retVal = true;} } else if (theWhiteFilterRule.Comp === "~") { isKnownComp = true; logger.log("debug", "RegexFilter: " + theWhiteFilterRule.Value + " || " + inputData[theWhiteFilterRule.Field].replace(/\r/g, "\\r").replace(/\n/g, "\\n")); retVal = this.reTest(theWhiteFilterRule.Value, inputData[theWhiteFilterRule.Field]); } if (!isKnownComp) { logger.log("error", "The configured Comp '" + theWhiteFilterRule.Comp + "' is unknown.") } if (retVal === true) { logger.log("debug", "Logic FLAT - Exiting out"); } logger.log("debug", "Logic FLAT - end"); return (retVal); } reTest(regex, data) { try { let match = regex.match(new RegExp('^/(.*?)/([giumy]*)$')); regex = new RegExp(match[1], match[2]); } catch (err) { logger.log("error","Regular Expression processing failed for RegEx " + regex + " is it in the right format?"); } return regex.test(data); } }