2019-01-04 11:06:37 -06:00
|
|
|
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 {
|
2019-01-04 12:46:40 -06:00
|
|
|
constructor(ruleSetFiles) {
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Instantiated RulesEngine - RuleSetFiles: " + ruleSetFiles);
|
2019-01-04 12:46:40 -06:00
|
|
|
this.ruleSet = {};
|
|
|
|
|
if (ruleSetFiles === "*") {
|
|
|
|
|
fs.readdirSync("./rules/").forEach(file => {
|
|
|
|
|
if (this.reTest("/.*\.rule\.json$/", file)) {
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Loading rule set file " + file);
|
2019-01-04 12:46:40 -06:00
|
|
|
let newRuleSet = JSON.parse(fs.readFileSync('./rules/' + file, 'utf8'));
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Adding rule set " + Object.keys(newRuleSet)[0]);
|
2019-01-04 12:46:40 -06:00
|
|
|
this.ruleSet[Object.keys(newRuleSet)[0]] = newRuleSet[Object.keys(newRuleSet)[0]]
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else if (ruleSetFiles.indexOf(",") > 1) {
|
|
|
|
|
ruleSetFiles.split(",").forEach(file => {
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Loading rule set file " + file);
|
2019-01-04 12:46:40 -06:00
|
|
|
let newRuleSet = JSON.parse(fs.readFileSync('./rules/' + file + '.rule.json', 'utf8'));
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Adding rule set " + Object.keys(newRuleSet)[0]);
|
2019-01-04 12:46:40 -06:00
|
|
|
this.ruleSet[Object.keys(newRuleSet)[0]] = newRuleSet[Object.keys(newRuleSet)[0]]
|
|
|
|
|
});
|
|
|
|
|
} else {
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Loading rule set file " + ruleSetFiles);
|
2019-01-04 12:46:40 -06:00
|
|
|
this.ruleSet = JSON.parse(fs.readFileSync('./rules/' + ruleSetFiles + '.rule.json', 'utf8'));
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("info", "Adding rule set " + Object.keys(this.ruleSet)[0]);
|
2019-01-04 12:46:40 -06:00
|
|
|
}
|
2019-01-04 11:06:37 -06:00
|
|
|
}
|
|
|
|
|
processData(inputLine) {
|
|
|
|
|
let inputData = inputLine.data;
|
2019-01-04 12:46:40 -06:00
|
|
|
logger.log("debug", "ProcessingType " + inputLine.processingType);
|
2019-01-04 11:06:37 -06:00
|
|
|
let allWhiteFilterRules = this.ruleSet[inputLine.processingType].rules;
|
|
|
|
|
if (this.processLogicOr(allWhiteFilterRules, inputData)) { return (true); }
|
2019-01-14 08:04:41 -06:00
|
|
|
logger.log("debug", "No white listing matched; returning false");
|
2019-01-04 11:06:37 -06:00
|
|
|
return (false);
|
|
|
|
|
}
|
|
|
|
|
processLogicAnd(allWhiteFilterRules, inputData) {
|
|
|
|
|
let retVal = true;
|
|
|
|
|
logger.log("debug", "Logic AND - start");
|
2019-01-14 08:04:41 -06:00
|
|
|
// if one condition is false the other one doens't need checking anymore,
|
|
|
|
|
// therefore including the retVal in the check condition of the below for loop
|
|
|
|
|
for (let i = 0; (i < allWhiteFilterRules.length && retVal); i++) {
|
2019-01-04 11:06:37 -06:00
|
|
|
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 === "&") {
|
2019-01-04 12:46:40 -06:00
|
|
|
if (!this.processLogicAnd(theWhiteFilterRule.rules, inputData) && retVal === true) {
|
2019-01-04 11:06:37 -06:00
|
|
|
logger.log("debug", " Logic AND - AND - Changing Result to false");
|
2019-01-04 12:46:40 -06:00
|
|
|
retVal = false;
|
2019-01-04 11:06:37 -06:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
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];
|
2019-01-04 12:46:40 -06:00
|
|
|
logger.log("debug", " Logic OR - whiteFilterRule: " + JSON.stringify(theWhiteFilterRule));
|
2019-01-04 11:06:37 -06:00
|
|
|
if (theWhiteFilterRule.Logic === "-") {
|
|
|
|
|
if (this.processLogicFlat(theWhiteFilterRule, inputData)) {
|
|
|
|
|
logger.log("debug", " Logic OR - FLAT - RETURNING OUT");
|
2019-01-04 12:46:40 -06:00
|
|
|
return (true);
|
|
|
|
|
};
|
2019-01-04 11:06:37 -06:00
|
|
|
} else if (theWhiteFilterRule.Logic === "|") {
|
2019-01-04 12:46:40 -06:00
|
|
|
if (this.processLogicOr(theWhiteFilterRule.rules, inputData)) {
|
2019-01-04 11:06:37 -06:00
|
|
|
logger.log("debug", " Logic OR - OR - RETURNING OUT");
|
2019-01-04 12:46:40 -06:00
|
|
|
return (true)
|
2019-01-04 11:06:37 -06:00
|
|
|
};
|
|
|
|
|
} else if (theWhiteFilterRule.Logic === "&") {
|
2019-01-04 12:46:40 -06:00
|
|
|
if (this.processLogicAnd(theWhiteFilterRule.rules, inputData)) {
|
2019-01-04 11:06:37 -06:00
|
|
|
logger.log("debug", " Logic OR - AND - RETURNING OUT");
|
2019-01-04 12:46:40 -06:00
|
|
|
return (true)
|
2019-01-04 11:06:37 -06:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
logger.log("debug", "Logic OR - end");
|
2019-01-04 12:46:40 -06:00
|
|
|
return (false);
|
2019-01-04 11:06:37 -06:00
|
|
|
}
|
|
|
|
|
processLogicFlat(theWhiteFilterRule, inputData) {
|
2019-01-04 12:46:40 -06:00
|
|
|
logger.log("debug", "Logic FLAT start - whiteFilterRule: " + JSON.stringify(theWhiteFilterRule));
|
|
|
|
|
let isKnownComp = false;
|
|
|
|
|
let retVal = false;
|
2019-01-18 15:29:21 -06:00
|
|
|
|
|
|
|
|
let dataValue;
|
|
|
|
|
let ruleValue;
|
|
|
|
|
let sDataType = theWhiteFilterRule.dataType || "string";
|
|
|
|
|
|
|
|
|
|
if (sDataType ==="number") {
|
|
|
|
|
dataValue = Number(inputData[theWhiteFilterRule.Field]);
|
|
|
|
|
ruleValue = Number(theWhiteFilterRule.Value);
|
|
|
|
|
} else {
|
|
|
|
|
dataValue = inputData[theWhiteFilterRule.Field];
|
|
|
|
|
ruleValue = theWhiteFilterRule.Value;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-09 06:27:00 -06:00
|
|
|
try {
|
|
|
|
|
if (theWhiteFilterRule.Comp === "===") {
|
2019-01-18 15:29:21 -06:00
|
|
|
isKnownComp = true;
|
|
|
|
|
if (dataValue === ruleValue) {retVal = true;}
|
2019-01-09 06:27:00 -06:00
|
|
|
} else if (theWhiteFilterRule.Comp === "<") {
|
2019-01-18 15:29:21 -06:00
|
|
|
isKnownComp = true;
|
|
|
|
|
if (dataValue < ruleValue) {retVal = true;}
|
2019-01-09 06:27:00 -06:00
|
|
|
} else if (theWhiteFilterRule.Comp === ">") {
|
|
|
|
|
isKnownComp = true;
|
2019-01-18 15:29:21 -06:00
|
|
|
if (dataValue > ruleValue) {retVal = true;}
|
2019-01-09 06:27:00 -06:00
|
|
|
} else if (theWhiteFilterRule.Comp === "<=") {
|
|
|
|
|
isKnownComp = true;
|
2019-01-18 15:29:21 -06:00
|
|
|
if (dataValue <= ruleValue) {retVal = true;}
|
2019-01-09 06:27:00 -06:00
|
|
|
} else if (theWhiteFilterRule.Comp === ">=") {
|
|
|
|
|
isKnownComp = true;
|
2019-01-18 15:29:21 -06:00
|
|
|
if (dataValue >= ruleValue) {retVal = true;}
|
2019-01-09 06:27:00 -06:00
|
|
|
} else if (theWhiteFilterRule.Comp === "~") {
|
|
|
|
|
isKnownComp = true;
|
2019-01-18 15:29:21 -06:00
|
|
|
logger.log("debug", "RegexFilter: " + ruleValue + " || " + ""+dataValue.replace(/\r/g, "\\r").replace(/\n/g, "\\n"));
|
|
|
|
|
retVal = this.reTest(ruleValue, dataValue);
|
2019-01-09 06:27:00 -06:00
|
|
|
}
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
logger.log("error", "LogicFlat-Error " + ex + " WhiteFilterRule: " + JSON.stringify(theWhiteFilterRule) + " InputData " + JSON.stringify(inputData));
|
|
|
|
|
}
|
2019-01-04 11:06:37 -06:00
|
|
|
|
2019-01-04 12:46:40 -06:00
|
|
|
if (!isKnownComp) {
|
|
|
|
|
logger.log("error", "The configured Comp '" + theWhiteFilterRule.Comp + "' is unknown.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (retVal === true) {
|
|
|
|
|
logger.log("debug", "Logic FLAT - Exiting out");
|
2019-01-04 11:06:37 -06:00
|
|
|
}
|
|
|
|
|
logger.log("debug", "Logic FLAT - end");
|
2019-01-04 12:46:40 -06:00
|
|
|
return (retVal);
|
2019-01-04 11:06:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reTest(regex, data) {
|
2019-01-07 06:12:31 -06:00
|
|
|
try {
|
2019-01-04 11:06:37 -06:00
|
|
|
let match = regex.match(new RegExp('^/(.*?)/([giumy]*)$'));
|
|
|
|
|
regex = new RegExp(match[1], match[2]);
|
2019-01-07 06:12:31 -06:00
|
|
|
} catch (err) {
|
|
|
|
|
logger.log("error","Regular Expression processing failed for RegEx " + regex + " is it in the right format?");
|
|
|
|
|
}
|
2019-01-04 11:06:37 -06:00
|
|
|
return regex.test(data);
|
|
|
|
|
}
|
|
|
|
|
}
|