diff --git a/helpers/live_helper.py b/helpers/live_helper.py
index 985bca8..7078e49 100644
--- a/helpers/live_helper.py
+++ b/helpers/live_helper.py
@@ -43,7 +43,7 @@ class Live_helper:
jentry = json.loads(entry.decode('utf8'))
to_ret.append(jentry)
return to_ret
-
+
def add_to_stream_log_cache(self, cacheKey, item):
rKey = self.prefix_redis_key+cacheKey
diff --git a/server.py b/server.py
index 8a1943f..5136e0c 100755
--- a/server.py
+++ b/server.py
@@ -68,10 +68,10 @@ class LogItem():
FIELDNAME_ORDER_HEADER.append(item)
FIELDNAME_ORDER.append(item)
- def __init__(self, feed):
+ def __init__(self, feed, filters={}):
+ self.filters = filters
+ self.feed = feed
self.fields = []
- for f in feed:
- self.fields.append(f)
def get_head_row(self):
to_ret = []
@@ -80,38 +80,70 @@ class LogItem():
return to_ret
def get_row(self):
+ if not self.pass_filter():
+ return False
+
to_ret = {}
- #Number to keep them sorted (jsonify sort keys)
- for item in range(len(LogItem.FIELDNAME_ORDER)):
- try:
- to_ret[item] = self.fields[item]
- except IndexError: # not enough field in rcv item
- to_ret[item] = ''
+ for i, field in enumerate(json.loads(cfg.get('Dashboard', 'fieldname_order'))):
+ if type(field) is list:
+ to_join = []
+ for subField in field:
+ to_join.append(str(util.getFields(self.feed, subField)))
+ to_add = cfg.get('Dashboard', 'char_separator').join(to_join)
+ else:
+ to_add = util.getFields(self.feed, field)
+ to_ret[i] = to_add if to_add is not None else ''
+
return to_ret
+ def pass_filter(self):
+ for filter, filterValue in self.filters.items():
+ jsonValue = util.getFields(self.feed, filter)
+ if jsonValue is None or jsonValue != filterValue:
+ return False
+ return True
+
+
class EventMessage():
# Suppose the event message is a json with the format {name: 'feedName', log:'logData'}
- def __init__(self, msg):
- msg = msg.decode('utf8')
- try:
- jsonMsg = json.loads(msg)
- except json.JSONDecodeError as e:
- logger.error(e)
- jsonMsg = { 'name': "undefined" ,'log': json.loads(msg) }
+ def __init__(self, msg, filters):
+ if not isinstance(msg, dict):
+ msg = msg.decode('utf8')
+ try:
+ jsonMsg = json.loads(msg)
+ jsonMsg['log'] = json.loads(jsonMsg['log'])
+ except json.JSONDecodeError as e:
+ logger.error(e)
+ jsonMsg = { 'name': "undefined" ,'log': json.loads(msg) }
+ else:
+ jsonMsg = msg
self.name = jsonMsg['name']
self.zmqName = jsonMsg['zmqName']
- self.feed = json.loads(jsonMsg['log'])
- self.feed = LogItem(self.feed).get_row()
+ if self.name == 'Attribute':
+ self.feed = jsonMsg['log']
+ self.feed = LogItem(self.feed, filters).get_row()
+ else:
+ self.feed = jsonMsg['log']
def to_json_ev(self):
- to_ret = { 'log': self.feed, 'name': self.name, 'zmqName': self.zmqName }
- return 'data: {}\n\n'.format(json.dumps(to_ret))
+ if self.feed is not False:
+ to_ret = { 'log': self.feed, 'name': self.name, 'zmqName': self.zmqName }
+ return 'data: {}\n\n'.format(json.dumps(to_ret))
+ else:
+ return ''
def to_json(self):
- to_ret = { 'log': self.feed, 'name': self.name, 'zmqName': self.zmqName }
- return json.dumps(to_ret)
+ if self.feed is not False:
+ to_ret = { 'log': self.feed, 'name': self.name, 'zmqName': self.zmqName }
+ return json.dumps(to_ret)
+ else:
+ return ''
+
+ def to_dict(self):
+ return {'log': self.feed, 'name': self.name, 'zmqName': self.zmqName}
+
###########
## ROUTE ##
@@ -226,9 +258,18 @@ def logs():
if request.accept_mimetypes.accept_json or request.method == 'POST':
key = 'Attribute'
j = live_helper.get_stream_log_cache(key)
- return jsonify(j)
+ to_ret = []
+ for item in j:
+ filters = request.cookies.get('filters', '{}')
+ filters = json.loads(filters)
+ ev = EventMessage(item, filters)
+ if ev is not None:
+ dico = ev.to_dict()
+ if dico['log'] != False:
+ to_ret.append(dico)
+ return jsonify(to_ret)
else:
- return Response(event_stream_log(), mimetype="text/event-stream")
+ return Response(stream_with_context(event_stream_log()), mimetype="text/event-stream")
@app.route("/_maps")
def maps():
@@ -248,9 +289,14 @@ def event_stream_log():
subscriber_log.subscribe(live_helper.CHANNEL)
try:
for msg in subscriber_log.listen():
+ filters = request.cookies.get('filters', '{}')
+ filters = json.loads(filters)
content = msg['data']
- ev = EventMessage(content)
- yield ev.to_json_ev()
+ ev = EventMessage(content, filters)
+ if ev is not None:
+ yield ev.to_json_ev()
+ else:
+ pass
except GeneratorExit:
subscriber_log.unsubscribe()
diff --git a/static/js/index/index.js b/static/js/index/index.js
index 7c5a752..0fa2334 100644
--- a/static/js/index/index.js
+++ b/static/js/index/index.js
@@ -170,52 +170,67 @@ var curNumLog = 0;
var curMaxDataNumLog = 0;
var source_log;
-function connect_source_log() {
- source_log = new EventSource(urlForLogs);
-
- source_log.onopen = function(){
- //console.log('connection is opened. '+source_log.readyState);
- };
-
- source_log.onerror = function(){
- console.log('error: '+source_log.readyState);
- setTimeout(function() { connect_source_log(); }, 5000);
- };
-
- source_log.onmessage = function(event) {
- var json = jQuery.parseJSON( event.data );
- updateLogTable(json.name, json.log, json.zmqName);
- };
-}
+// function connect_source_log() {
+// source_log = new EventSource(urlForLogs);
+//
+// source_log.onopen = function(){
+// //console.log('connection is opened. '+source_log.readyState);
+// };
+//
+// source_log.onerror = function(){
+// console.log('error: '+source_log.readyState);
+// setTimeout(function() { connect_source_log(); }, 5000);
+// };
+//
+// source_log.onmessage = function(event) {
+// var json = jQuery.parseJSON( event.data );
+// updateLogTable(json.name, json.log, json.zmqName);
+// };
+// }
+var livelog;
$(document).ready(function () {
- createHead(function() {
- if (!!window.EventSource) {
- $.getJSON( urlForLogs, function( data ) {
- data.forEach(function(item) {
- updateLogTable(item.name, item.log, item.zmqName);
- });
- connect_source_log();
- });
- } else {
- console.log("No event source_log");
- }
+ // createHead(function() {
+ // if (!!window.EventSource) {
+ // $.getJSON( urlForLogs, function( data ) {
+ // data.forEach(function(item) {
+ // updateLogTable(item.name, item.log, item.zmqName);
+ // });
+ // connect_source_log();
+ // });
+ // } else {
+ // console.log("No event source_log");
+ // }
+ //
+ // });
+ $.getJSON(urlForHead, function(head) {
+ livelog = new $.livelog($("#divLogTable"), {
+ pollingFrequency: 5000,
+ tableHeader: head,
+ tableMaxEntries: 50,
+ animate: false,
+ preDataURL: urlForLogs,
+ endpoint: urlForLogs
+ });
});
+
});
// LOG TABLE
-function updateLogTable(name, log, zmqName) {
+function updateLogTable(name, log, zmqName, ignoreLed) {
if (log.length == 0)
return;
// update keepAlives
- ledmanager.updateKeepAlive(zmqName);
+ if (ignoreLed !== true) {
+ ledmanager.updateKeepAlive(zmqName);
+ }
// Create new row
- tableBody = document.getElementById('table_log_body');
+ // tableBody = document.getElementById('table_log_body');
// only add row for attribute
if (name == "Attribute" ) {
@@ -224,12 +239,12 @@ function updateLogTable(name, log, zmqName) {
sources.incCountOnSource(categName);
sources.incCountOnSource('global');
updateChartDirect();
- createRow(tableBody, log);
+ // createRow(tableBody, log);
// Remove old row
- while ($("#table_log").height() >= $("#panelLogTable").height()-26){ //26 for margin
- tableBody.deleteRow(0);
- }
+ // while ($("#table_log").height() >= $("#panelLogTable").height()-26){ //26 for margin
+ // tableBody.deleteRow(0);
+ // }
} else if (name == "Keepalive") {
// do nothing
@@ -264,23 +279,6 @@ function getTextColour(rgb) {
}
}
-function addObjectToLog(name, obj, td) {
- if(name == "Tag") {
- var a = document.createElement('A');
- a.classList.add('tagElem');
- a.style.backgroundColor = obj.colour;
- a.style.color = getTextColour(obj.colour.substring(1,6));
- a.innerHTML = obj.name;
- td.appendChild(a);
- td.appendChild(document.createElement('br'));
- } else if (name == "mispObject") {
- td.appendChild(document.createTextNode('mispObj'));
- } else {
- td.appendChild(document.createTextNode('nop'));
-
- }
-}
-
function createRow(tableBody, log) {
var tr = document.createElement('TR');
@@ -338,3 +336,554 @@ function createHead(callback) {
callback();
});
}
+
+
+
+/* LIVE LOG */
+(function(factory) {
+ "use strict";
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery'], factory);
+ } else if (window.jQuery && !window.jQuery.fn.Livelog) {
+ factory(window.jQuery);
+ }
+ }
+ (function($) {
+ 'use strict';
+
+ // Livelog object
+ var Livelog = function(container, options) {
+ this._default_options = {
+ pollingFrequency: 5000,
+ tableHeader: undefined,
+ tableMaxEntries: undefined,
+ animate: true
+ }
+
+ options.container = container;
+
+ this.validateOptions(options);
+ this._options = $.extend({}, this._default_options, options);
+
+ // create table and draw header
+ this.origTableOptions = {
+ dom: "<'row'<'col-sm-12'<'dt-toolbar-led'>>>"
+ + "<'row'<'col-sm-12'tr>>",
+ searching: false,
+ paging: false,
+ "order": [[ 0, "desc" ]],
+ responsive: true,
+ columnDefs: [
+ { targets: 0, orderable: false },
+ { targets: '_all', searchable: false, orderable: false,
+ render: function ( data, type, row ) {
+ // return data +' ('+ row[3]+')';
+ var $toRet;
+ if (typeof data === 'object') {
+ $toRet = $('');
+ data.data.forEach(function(cur, i) {
+ switch (data.name) {
+ case 'Tag':
+ var $tag = $('');
+ $tag.addClass('tagElem');
+ $tag.css({
+ backgroundColor: cur.colour,
+ color: getTextColour(cur.colour.substring(1,6))
+ });
+ $tag.text(cur.name)
+ $toRet.append($tag);
+ break;
+ case 'mispObject':
+ $toRet.append('MISP Object not supported yet')
+ break;
+ default:
+ break;
+ }
+ });
+ $toRet = $toRet[0].outerHTML;
+ } else if (data === undefined) {
+ $toRet = '';
+ } else {
+ var textToAddArray = data.split(char_separator);
+ $toRet = '';
+ textToAddArray.forEach(function(e, i) {
+ if (i > 0) {
+ $toRet += '
' + e;
+ } else {
+ $toRet += e;
+ }
+ });
+ }
+ return $toRet;
+ },
+ }
+ ],
+ };
+
+ this.DOMTable = $('