feat: Add Be and tbd skill, also added Roadmap file

This commit is contained in:
2026-05-10 16:32:12 -04:00
parent 3500ade13f
commit 0bb8885802
29587 changed files with 10611695 additions and 0 deletions

View File

@@ -0,0 +1,520 @@
/*
* Glossy Parser - Parse incoming syslog messages
*
* Copyright Squeeks <privacymyass@gmail.com>.
* This is free software licensed under the MIT License -
* see the LICENSE file that should be included with this package.
*/
/*
* These values replace the integers in message that define the facility.
*/
var FacilityIndex = [
'kern', // kernel messages
'user', // user-level messages
'mail', // mail system
'daemon', // system daemons
'auth', // security/authorization messages
'syslog', // messages generated internally by syslogd
'lpr', // line printer subsystem
'news', // network news subsystem
'uucp', // UUCP subsystem
'clock', // clock daemon
'sec', // security/authorization messages
'ftp', // FTP daemon
'ntp', // NTP subsystem
'audit', // log audit
'alert', // log alert
'clock', // clock daemon (note 2)
'local0', // local use 0 (local0)
'local1', // local use 1 (local1)
'local2', // local use 2 (local2)
'local3', // local use 3 (local3)
'local4', // local use 4 (local4)
'local5', // local use 5 (local5)
'local6', // local use 6 (local6)
'local7' // local use 7 (local7)
];
// Note 1 - Various operating systems have been found to utilize
// Facilities 4, 10, 13 and 14 for security/authorization,
// audit, and alert messages which seem to be similar.
// Note 2 - Various operating systems have been found to utilize
// both Facilities 9 and 15 for clock (cron/at) messages.
/*
* These values replace the integers in message that define the severity.
*/
var SeverityIndex = [
'emerg', // Emergency: system is unusable
'alert', // Alert: action must be taken immediately
'crit', // Critical: critical conditions
'err', // Error: error conditions
'warn', // Warning: warning conditions
'notice', // Notice: normal but significant condition
'info', // Informational: informational messages
'debug' // Debug: debug-level messages
];
/*
* Defines the range matching BSD style months to integers.
*/
var BSDDateIndex = {
'Jan': 0,
'Feb': 1,
'Mar': 2,
'Apr': 3,
'May': 4,
'Jun': 5,
'Jul': 6,
'Aug': 7,
'Sep': 8,
'Oct': 9,
'Nov': 10,
'Dec': 11
};
// These values match the hasing algorithm values as defined in RFC 5848
var signedBlockValues = {
// Section 4.2.1
hashAlgorithm: [
null,
'SHA1',
'SHA256'
],
// Section 5.2.1
keyBlobType: {
'C': 'PKIX Certificate',
'P': 'OpenPGP KeyID',
'K': 'Public Key',
'N': 'No key information',
'U': 'Unknown'
}
};
var GlossyParser = function() {};
/*
* Parse the raw message received.
*
* @param {String/Buffer} rawMessage Raw message received from socket
* @param {Function} callback Callback to run after parse is complete
* @return {Object} map containing all successfully parsed data.
*/
GlossyParser.prototype.parse = function(rawMessage, callback) {
// Are you node.js? Is this a Buffer?
if(typeof Buffer == 'function' && Buffer.isBuffer(rawMessage)) {
rawMessage = rawMessage.toString('utf8', 0);
} else if(typeof rawMessage != 'string') {
return rawMessage;
}
// Always return the original message
var parsedMessage = {
originalMessage: rawMessage
};
var segments = rawMessage.split(' ');
if(segments.length < 2) return parsedMessage;
var priKeys = this.decodePri(segments[0]);
if(priKeys) {
for (var key in priKeys) parsedMessage[key] = priKeys[key];
}
var timeStamp;
//TODO Could our detection between 3164/5424 be improved?
if(segments[0].match(/^(<\d+>\d)$/)) {
segments.shift(); // Shift the prival off
timeStamp = segments.shift();
parsedMessage.type = 'RFC5424';
parsedMessage.time = this.parseTimeStamp(timeStamp);
parsedMessage.host = this.decideValue(segments.shift());
parsedMessage.appName = this.decideValue(segments.shift());
parsedMessage.pid = this.decideValue(segments.shift());
parsedMessage.msgID = this.decideValue(segments.shift());
if(segments[0] !== '-') {
var spliceMarker = 0;
for (i = segments.length -1; i > -1; i--) {
if(segments[i].substr(-1) === ']'){
spliceMarker = i;
spliceMarker++;
break;
}
}
if(spliceMarker !== 0) {
var sd = segments.splice(0, spliceMarker).join(' ');
parsedMessage.structuredData = this.parseStructure(sd);
if(parsedMessage.structuredData.ssign) {
parsedMessage.structuredData.signedBlock =
this.parseSignedBlock(parsedMessage.structuredData);
} else if(parsedMessage.structuredData['ssign-cert']) {
parsedMessage.structuredData.signedBlock =
this.parseSignedCertificate(parsedMessage.structuredData);
}
}
} else {
segments.shift(); // Shift the SD marker off
}
parsedMessage.message = segments.join(' ');
} else if (segments[0].match(/^(<\d+>\d+:)$/)) {
parsedMessage.type = 'RFC3164';
timeStamp = segments.splice(0,1).join(' ').replace(/^(<\d+>)/,'');
parsedMessage.time = this.parseBsdTime(timeStamp);
parsedMessage.message = segments.join(' ');
} else if(segments[0].match(/^(<\d+>\w+)/)) {
parsedMessage.type = 'RFC3164';
if (segments[1] === '') segments.splice(1,1);
timeStamp = segments.splice(0,3).join(' ').replace(/^(<\d+>)/,'');
parsedMessage.time = this.parseBsdTime(timeStamp);
parsedMessage.host = segments.shift();
parsedMessage.message = segments.join(' ');
}
if(callback) {
callback(parsedMessage);
} else {
return parsedMessage;
}
};
/*
* RFC5424 messages are supposed to specify '-' as the null value
* @param {String} a section from an RFC5424 message
* @return {Boolean/String} null if string is entirely '-', or the original value
*/
GlossyParser.prototype.decideValue = function(value) {
return value === '-' ? null : value;
};
/*
* Parses the PRI value from the start of message
*
* @param {String} message Supplied raw primary value and version
* @return {Object} Returns object containing Facility, Severity and Version
* if correctly parsed, empty values on failure.
*/
GlossyParser.prototype.decodePri = function(message) {
if(typeof message != 'string') return;
var privalMatch = message.match(/^<(\d+)>/);
if(!privalMatch) return false;
var returnVal = {
prival: parseInt(privalMatch[1], 10)
};
if(privalMatch[2]) returnVal.versio = parseInt(privalMatch[2], 10);
if(returnVal.prival && returnVal.prival >= 0 && returnVal.prival <= 191) {
returnVal.facilityID = parseInt(returnVal.prival / 8, 10);
returnVal.severityID = returnVal.prival - (returnVal.facilityID * 8);
if(returnVal.facilityID < 24 && returnVal.severityID < 8) {
returnVal.facility = FacilityIndex[returnVal.facilityID];
returnVal.severity = SeverityIndex[returnVal.severityID];
}
} else if(returnVal.prival >= 191) {
return false;
}
return returnVal;
};
/*
* Attempts to parse a given timestamp
* @param {String} timeStamp Supplied timestamp, should only be the timestamp,
* not the entire message
* @return {Object} Date object on success
*/
GlossyParser.prototype.parseTimeStamp = function(timeStamp) {
if(typeof timeStamp != 'string') return;
var parsedTime;
parsedTime = this.parse8601(timeStamp);
if(parsedTime) return parsedTime;
parsedTime = this.parseRfc3339(timeStamp);
if(parsedTime) return parsedTime;
parsedTime = this.parseBsdTime(timeStamp);
if(parsedTime) return parsedTime;
return parsedTime;
};
/*
* Parse RFC3339 style timestamps
* @param {String} timeStamp
* @return {Date/false} Timestamp, if parsed correctly
* @see http://blog.toppingdesign.com/2009/08/13/fast-rfc-3339-date-processing-in-javascript/
*/
GlossyParser.prototype.parseRfc3339 = function(timeStamp){
  var utcOffset, offsetSplitChar, offsetString,
    offsetMultiplier = 1,
    dateTime = timeStamp.split("T");
if(dateTime.length < 2) return false;
    var date = dateTime[0].split("-"),
    time = dateTime[1].split(":"),
    offsetField = time[time.length - 1];
    offsetFieldIdentifier = offsetField.charAt(offsetField.length - 1);
    if (offsetFieldIdentifier === "Z") {
    utcOffset = 0;
        time[time.length - 1] = offsetField.substr(0, offsetField.length - 2);
    } else {
    if (offsetField[offsetField.length - 1].indexOf("+") != -1) {
            offsetSplitChar = "+";
            offsetMultiplier = 1;
        } else {
            offsetSplitChar = "-";
            offsetMultiplier = -1;
        }
        offsetString = offsetField.split(offsetSplitChar);
if(offsetString.length < 2) return false;
        time[(time.length - 1)] = offsetString[0];
        offsetString = offsetString[1].split(":");
        utcOffset = (offsetString[0] * 60) + offsetString[1];
        utcOffset = utcOffset * 60 * 1000;
    }
               
    var parsedTime = new Date(Date.UTC(date[0], date[1] - 1, date[2], time[0], time[1], time[2]) + (utcOffset * offsetMultiplier ));
    return parsedTime;
};
/*
* Parse "BSD style" timestamps, as defined in RFC3164
* @param {String} timeStamp
* @return {Date/false} Timestamp, if parsed correctly
*/
GlossyParser.prototype.parseBsdTime = function(timeStamp) {
var parsedTime;
var d = timeStamp.match(/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2})\s+(\d{2}):(\d{2}):(\d{2})/);
if(d) {
// Years are absent from the specification, use this year
currDate = new Date();
parsedTime = new Date(
currDate.getUTCFullYear(),
BSDDateIndex[ d[1] ],
d[2],
d[3],
d[4],
d[5]);
}
return parsedTime;
};
/*
* Parse ISO 8601 timestamps
* @param {String} timeStamp
* @return {Object/false} Timestamp, if successfully parsed
*/
GlossyParser.prototype.parse8601 = function(timeStamp) {
var parsedTime = new Date(Date.parse(timeStamp));
if(parsedTime.toString() === 'Invalid Date') return; //FIXME not the best
return parsedTime;
};
/*
* Parse the structured data out of RFC5424 messages
* @param {String} msg The STRUCTURED-DATA section
* @return {Object} sdStructure parsed structure
*/
GlossyParser.prototype.parseStructure = function(msg) {
var sdStructure = { };
var state = 0,
ignore = false,
sdId = '',
sdParam = '',
sdValue = '';
/*
* Build the structure using a horrible FSM.
* The states we cycle are as following:
* 0 1 2 34 20
* [sdID sdParam="sdValue"]
*/
for(var i = 0; i < msg.length; i++) {
var c = msg[i];
switch(state) {
case 0: // SD-ELEMENT
state = (c === '[') ? 1 : 0;
break;
case 1: // SD-ID
if(c != ' ') {
sdId += c;
} else {
sdStructure[sdId] = {};
state = 2;
}
break;
case 2: // SD-PARAM
if(c === '=') {
sdStructure[sdId][sdParam] = '';
state = 3;
} else if(c === ']') {
sdId = '';
state = 0;
} else if(c != ' '){
sdParam += c;
}
break;
case 3: // SD-PARAM/SD-VALUE
state = c === '"' ? 4 : null; // FIXME Handle rubbish better
break;
case 4: // SD-VALUE
if(c === '\\' && !ignore) {
ignore = true;
} else if(c === '"' && !ignore) {
sdStructure[sdId][sdParam] = sdValue;
sdParam = '', sdValue = '';
state = 2;
} else {
sdValue += c;
ignore = false;
}
break;
default:
break;
}
}
return sdStructure;
};
/*
* Make sense of signed block messages
* @param {Object} block the parsed structured data containing signed data
* @return {Object} validatedBlock translated and named values, binary
* elements will be Buffer objects, if available
*/
GlossyParser.prototype.parseSignedBlock = function(block) {
if(typeof block != 'object') return false;
var signedBlock = { };
var validatedBlock = { };
// Figure out where in the object the keys live...
if(block.structuredData && block.structuredData.ssign) {
signedBlock = block.structuredData.ssign;
} else if(block.ssign) {
signedBlock = block.ssign;
} else if(block.VER) {
signedBlock = block;
} else {
return false;
}
var versionMatch = signedBlock.VER.match(/^(\d{2})(\d|\w)(\d)$/);
if(versionMatch !== null) {
validatedBlock.version = versionMatch[1];
validatedBlock.hashAlgorithm = parseInt(versionMatch[2], 10);
validatedBlock.hashAlgoString = signedBlockValues.hashAlgorithm[validatedBlock.hashAlgorithm];
validatedBlock.sigScheme = parseInt(versionMatch[3], 10);
}
validatedBlock.rebootSessionID = parseInt(signedBlock.RSID, 10);
validatedBlock.signatureGroup = parseInt(signedBlock.SG, 10);
validatedBlock.signaturePriority = parseInt(signedBlock.SPRI, 10);
validatedBlock.globalBlockCount = parseInt(signedBlock.GBC, 10);
validatedBlock.firstMsgNumber = parseInt(signedBlock.FMN, 10);
validatedBlock.msgCount = parseInt(signedBlock.CNT, 10);
validatedBlock.hashBlock = signedBlock.HB.split(/\s/);
// Check to see if we're in node or have a Buffer type
if(typeof Buffer == 'function') {
for(var hash in validatedBlock.hashBlock) {
validatedBlock.hashBlock[hash] = new Buffer(
validatedBlock.hashBlock[hash], encoding='base64');
}
validatedBlock.thisSignature = new Buffer(
signedBlock.SIGN, encoding='base64');
} else {
validatedBlock.thisSignature = signedBlock.SIGN;
}
return validatedBlock;
};
/*
* Make sense of signed certificate messages
* @param {Object} block the parsed structured data containing signed data
* @return {Object} validatedBlock translated and named values, binary
* elements will be Buffer objects, if available
*/
GlossyParser.prototype.parseSignedCertificate = function(block) {
if(typeof block != 'object') return false;
var signedBlock = { };
var validatedBlock = { };
// Figure out where in the object the keys live...
if(block.structuredData && block.structuredData['ssign-cert']) {
signedBlock = block.structuredData['ssign-cert'];
} else if(block['ssign-cert']) {
signedBlock = block['ssign-cert'];
} else if(block.VER) {
signedBlock = block;
} else {
return false;
}
var versionMatch = signedBlock.VER.match(/^(\d{2})(\d|\w)(\d)$/);
if(versionMatch !== null) {
validatedBlock.version = versionMatch[1];
validatedBlock.hashAlgorithm = parseInt(versionMatch[2], 10);
validatedBlock.hashAlgoString = signedBlockValues.hashAlgorithm[validatedBlock.hashAlgorithm];
validatedBlock.sigScheme = parseInt(versionMatch[3], 10);
}
validatedBlock.rebootSessionID = parseInt(signedBlock.RSID, 10);
validatedBlock.signatureGroup = parseInt(signedBlock.SG, 10);
validatedBlock.signaturePriority = parseInt(signedBlock.SPRI, 10);
validatedBlock.totalPayloadLength = parseInt(signedBlock.TPBL, 10);
validatedBlock.payloadIndex = parseInt(signedBlock.INDEX, 10);
validatedBlock.fragmentLength = parseInt(signedBlock.FLEN, 10);
var payloadFragment = signedBlock.FRAG.split(/\s/);
validatedBlock.payloadTimestamp = this.parseTimeStamp(payloadFragment[0]);
validatedBlock.payloadType = payloadFragment[1];
validatedBlock.payloadName = signedBlockValues.keyBlobType[payloadFragment[1]];
if(typeof Buffer == 'function') {
validatedBlock.keyBlob = new Buffer(
payloadFragment[2], encoding='base64');
validatedBlock.thisSignature = new Buffer(
signedBlock.SIGN, encoding='base64');
} else {
validatedBlock.keyBlob = payloadFragment[2];
validatedBlock.thisSignature = signedBlock.SIGN;
}
return validatedBlock;
};
if(typeof module == 'object') {
module.exports = new GlossyParser();
}

View File

@@ -0,0 +1,428 @@
/*
* Glossy Producer - Generate valid syslog messages
*
* Copyright Squeeks <privacymyass@gmail.com>.
* This is free software licensed under the MIT License -
* see the LICENSE file that should be included with this package.
*/
/*
* These values replace the integers in message that define the facility.
*/
var FacilityIndex = {
'kern': 0, // kernel messages
'user': 1, // user-level messages
'mail': 2, // mail system
'daemon': 3, // system daemons
'auth': 4, // security/authorization messages
'syslog': 5, // messages generated internally by syslogd
'lpr': 6, // line printer subsystem
'news': 7, // network news subsystem
'uucp': 8, // UUCP subsystem
'clock': 9, // clock daemon
'sec': 10, // security/authorization messages
'ftp': 11, // FTP daemon
'ntp': 12, // NTP subsystem
'audit': 13, // log audit
'alert': 14, // log alert
// 'clock': 15, // clock daemon (note 2)
'local0': 16, // local use 0 (local0)
'local1': 17, // local use 1 (local1)
'local2': 18, // local use 2 (local2)
'local3': 19, // local use 3 (local3)
'local4': 20, // local use 4 (local4)
'local5': 21, // local use 5 (local5)
'local6': 22, // local use 6 (local6)
'local7': 23 // local use 7 (local7)
};
// Note 1 - Various operating systems have been found to utilize
// Facilities 4, 10, 13 and 14 for security/authorization,
// audit, and alert messages which seem to be similar.
// Note 2 - Various operating systems have been found to utilize
// both Facilities 9 and 15 for clock (cron/at) messages.
/*
* These values replace the integers in message that define the severity.
*/
var SeverityIndex = {
'emerg': 0, // Emergency: system is unusable
'emergency': 0,
'alert': 1, // Alert: action must be taken immediately
'crit': 2, // Critical: critical conditions
'critical': 2,
'err': 3, // Error: error conditions
'error': 3,
'warn': 4, // Warning: warning conditions
'warning': 4,
'notice': 5, // Notice: normal but significant condition
'info': 6 , // Informational: informational messages
'information': 6,
'informational': 6,
'debug': 7 // Debug: debug-level messages
};
/*
* Defines the range matching BSD style months to integers.
*/
var BSDDateIndex = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
/*
* GlossyProducer class
* @param {Object} provides persistent details of all messages:
* facility: The facility index
* severity: Severity index
* host: Host address, either name or IP
* appName: Application/Process name
* pid: Process ID
* msgID: Message ID (RFC5424 only)
* type: RFC3164/RFC5424 message type
* @return {Object} GlossyProducer object
*/
var GlossyProducer = function(options) {
if(options && typeof options =='object' && options.type) {
this.type = options.type.match(/bsd|3164/i) ? "RFC3164" : "RFC5424";
} else if(options && typeof options == 'string') {
this.type = options.match(/bsd|3164/i) ? "RFC3164" : "RFC5424";
} else {
this.type = "RFC5424";
}
if(options && options.facility && FacilityIndex[options.facility]) {
this.facility = options.facility;
}
if(options && options.pid && parseInt(options.pid, 10)) {
this.pid = options.pid;
}
if(options && options.host) this.host = options.host.replace(/\s+/g, '');
if(options && options.appName) this.appName = options.appName.replace(/\s+/g, '');
if(options && options.msgID) this.msgID = options.msgID.replace(/\s+/g, '');
};
/*
* @param {Object} options object containing details of the message:
* facility: The facility index
* severity: Severity index
* prival: RFC5424 PRIVAL field - will override facility/severity if in valid [0-191] range and both provided
* see ABNF at: (http://tools.ietf.org/html/rfc5424#section-6)
* host: Host address, either name or IP
* appName: Application ID
* pid: Process ID
* date: Timestamp to be applied, uses current GMT by default
* time: Optional Date() argument may be used in lieu of 'date' - allows parse() output to be used for produce args
* msgID: Message ID (RFC5424 only)
* structuredData: Object of structured data (RFC5424 only)
* message: The message to be sent
*
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.produce = function(options, callback) {
// TODO: next breaking api change make key output from parse() consistent with produce input options
if(options.time instanceof Date && !options.date) options.date = options.time;
var msgData = [];
if(!options.date) options.date = new Date();
if(!options.facility) options.facility = this.facility;
if(this.type == 'RFC5424') {
if(options.hasOwnProperty('prival') && options.prival >= 0 && options.prival <= 191) {
var prival = '<' + options.prival + '>1';
}
else {
var prival = calculatePrival({
facility: options.facility,
severity: options.severity,
version: 1
});
}
if(prival === false) return false;
msgData.push(prival);
msgData.push(generateDate(options.date));
msgData.push(options.host || this.host || '-');
msgData.push(options.appName || this.appName || '-');
msgData.push(options.pid || this.pid || '-');
msgData.push(options.msgID || this.msgID || '-');
if(options.structuredData) {
msgData.push(generateStructuredData(options.structuredData) || '-');
} else {
msgData.push('-');
}
if(!options.message) options.message = '-';
} else {
options.timestamp = generateBSDDate(options.date);
msgData.push(
calculatePrival({
facility: options.facility,
severity: options.severity
}) + options.timestamp
);
msgData.push(options.host || this.host);
msgData.push();
if(options.appName || this.appName) {
var app = options.appName || this.appName;
var pid = options.pid || this.pid;
if(parseInt(pid, 10)) {
msgData.push(app + '[' + pid + ']:');
} else {
msgData.push(app + ':');
}
}
}
var compiledMessage = msgData.filter(function (messageElement) {
// Filter null/ undefined values
return messageElement;
}).map(function (messageElement) {
// Trim messages to remove successive whitespace
return String(messageElement).trim();
}).join(' ');
compiledMessage += ' ' + options.message || '';
msgData.push(compiledMessage);
if(callback) {
return callback(compiledMessage);
} else {
return compiledMessage;
}
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'debug'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.debug = function(options, callback) {
options.severity = 'debug';
return this.produce(options, callback);
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'info'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.info = function(options, callback) {
options.severity = 'info';
return this.produce(options, callback);
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'notice'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.notice = function(options, callback) {
options.severity = 'notice';
return this.produce(options, callback);
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'warn'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.warn = function(options, callback) {
options.severity = 'warn';
return this.produce(options, callback);
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'crit'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.crit = function(options, callback) {
options.severity = 'crit';
return this.produce(options, callback);
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'alert'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.alert = function(options, callback) {
options.severity = 'alert';
return this.produce(options, callback);
};
/*
* @param {Object} options object containing details of the message with
* the severity as 'emergency'
* @param {Function} callback a callback run once the message is built
* @return {String} compiledMessage on completion, false on failure
*/
GlossyProducer.prototype.emergency = function(options, callback) {
options.severity = 'emergency';
return this.produce(options, callback);
};
/*
* Prepend a zero to a number less than 10
* @param {Number} n
* @return {String}
*
* Where's sprintf when you need it?
*/
function leadZero(n) {
if(typeof n != 'number') return n;
n = n < 10 ? '0' + n : n ;
return n;
}
/*
* Get current date in RFC 3164 format. If no date is supplied, the default
* is the current time in GMT + 0.
* @param {Date} dateObject optional Date object
* @returns {String}
*
* Features code taken from https://github.com/akaspin/ain
*/
function generateBSDDate(dateObject) {
var date = new Date(dateObject);
if (isNaN(date.getTime())) return '-';
var hours = leadZero(dateObject.getHours());
var minutes = leadZero(dateObject.getMinutes());
var seconds = leadZero(dateObject.getSeconds());
var month = dateObject.getMonth();
var day = dateObject.getDate();
if(day < 10) (day = ' ' + day);
return BSDDateIndex[month] + " " + day + " " + hours + ":" + minutes + ":" + seconds;
}
/*
* Generate date in RFC 3339 format. If no date is supplied, the default is
* the current time in GMT + 0.
* @param {Date} dateObject optional Date object
* @returns {String} formatted date
*/
function generateDate(dateObject) {
var date = new Date(dateObject);
if (isNaN(date.getTime())) return '-';
return date.toISOString();
}
/*
* Calculate the PRIVAL for a given facility
* @param {Object} values Contains the three key arguments
* facility {Number}/{String} the Facility Index
* severity {Number}
* version {Number} For RFC 5424 messages, this should be 1
*
* @return {String}
*/
function calculatePrival(values) {
var pri = {};
// Facility
if(typeof values.facility == 'string' && !values.facility.match(/^\d+$/)) {
pri.facility = FacilityIndex[values.facility.toLowerCase()];
} else if( parseInt(values.facility, 10) && parseInt(values.facility, 10) < 24) {
pri.facility = parseInt(values.facility, 10);
}
//Severity
if(typeof values.severity == 'string' && !values.severity.match(/^\d+$/)) {
pri.severity = SeverityIndex[values.severity.toLowerCase()];
} else if( parseInt(values.severity, 10) && parseInt(values.severity, 10) < 8) {
pri.severity = parseInt(values.severity, 10);
}
if(!isNaN(pri.severity) && !isNaN(pri.facility)) {
pri.prival = (pri.facility * 8) + pri.severity;
pri.str = values.version ? '<' + pri.prival + '>' + values.version : '<' + pri.prival + '>';
return pri.str;
} else {
return false;
}
}
/*
* Serialise objects into the structured data segment
* @param {Object} struct The object to serialise
* @return {String} structuredData the serialised data
*/
function generateStructuredData(struct) {
if(typeof struct != 'object') return false;
var structuredData = '';
for(var sdID in struct) {
sdElement = struct[sdID];
structuredData += '[' + sdID;
for(var key in sdElement) {
if (Array.isArray(sdElement[key])) {
for(var i = 0; i < sdElement[key].length; i++) {
sdElement[key][i] = String(sdElement[key][i]).replace(/(\]|\\|")/g, '\\$1');
structuredData += ' ' + key + '="' + sdElement[key][i] + '"';
}
} else {
sdElement[key] = String(sdElement[key]).replace(/(\]|\\|")/g, '\\$1');
structuredData += ' ' + key + '="' + sdElement[key] + '"';
}
}
structuredData += ']';
}
return structuredData;
}
if(typeof module == 'object') {
module.exports = GlossyProducer;
}