mirror of https://github.com/MISP/misp-dashboard
Added login overtime + users_helper script
parent
2f74406f64
commit
c1105aba73
40
server.py
40
server.py
|
@ -11,6 +11,7 @@ import os
|
|||
|
||||
import util
|
||||
import contributor_helper
|
||||
import users_helper
|
||||
|
||||
configfile = os.path.join(os.environ['DASH_CONFIG'], 'config.cfg')
|
||||
cfg = configparser.ConfigParser()
|
||||
|
@ -32,6 +33,7 @@ serv_redis_db = redis.StrictRedis(
|
|||
db=cfg.getint('RedisDB', 'db'))
|
||||
|
||||
contributor_helper = contributor_helper.Contributor_helper(serv_redis_db, cfg)
|
||||
users_helper = users_helper.Users_helper(serv_redis_db, cfg)
|
||||
|
||||
subscriber_log = redis_server_log.pubsub(ignore_subscribe_messages=True)
|
||||
subscriber_log.psubscribe(cfg.get('RedisLog', 'channel'))
|
||||
|
@ -206,35 +208,17 @@ def getUserLogins():
|
|||
except:
|
||||
date = datetime.datetime.now()
|
||||
|
||||
keyname = "USER_LOGIN:{}"
|
||||
prev_days = 6
|
||||
week = {}
|
||||
for curDate in util.getXPrevDaysSpan(date, prev_days):
|
||||
timestamps = serv_redis_db.smembers(keyname.format(util.getDateStrFormat(curDate)))
|
||||
timestamps = [int(timestamp.decode('utf8')) for timestamp in timestamps]
|
||||
day = {}
|
||||
for timestamp in timestamps:
|
||||
date = datetime.datetime.fromtimestamp(float(timestamp))
|
||||
if date.hour not in day:
|
||||
day[date.hour] = 0
|
||||
day[date.hour] += 1
|
||||
week[curDate.weekday()] = day
|
||||
data = users_helper.getUserLoginsForPunchCard(date)
|
||||
return jsonify(data)
|
||||
|
||||
# Format data
|
||||
data = []
|
||||
for d in range(7):
|
||||
try:
|
||||
to_append = []
|
||||
for h in range(24):
|
||||
try:
|
||||
to_append.append(week[d][h])
|
||||
except KeyError:
|
||||
to_append.append(0)
|
||||
# swap 24 and 1. (punchcard starts at 1h)
|
||||
temp = to_append[1:]+[to_append[0]]
|
||||
data.append(temp)
|
||||
except KeyError:
|
||||
data.append([0 for x in range(24)])
|
||||
@app.route("/_getUserLoginsOvertime")
|
||||
def getUserLoginsOvertime():
|
||||
try:
|
||||
date = datetime.datetime.fromtimestamp(float(request.args.get('date')))
|
||||
except:
|
||||
date = datetime.datetime.now()
|
||||
|
||||
data = users_helper.getUserLoginsOvertime(date)
|
||||
return jsonify(data)
|
||||
|
||||
''' INDEX '''
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<script src="{{ url_for('static', filename='js/jquery.flot.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.flot.pie.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.flot.resize.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.flot.time.js') }}"></script>
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script src="{{ url_for('static', filename='js/bootstrap.js') }}"></script>
|
||||
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="text/css">
|
||||
|
@ -104,29 +105,50 @@ small {
|
|||
<div class="row">
|
||||
<div style="height: 10px;"></div>
|
||||
|
||||
<div class="col-lg-8">
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||
<b>Punch card - login</b>
|
||||
</div>
|
||||
<div id="panelbody" class="panel-body" style="">
|
||||
<div id="punchcard" style="width:100%; height: 100%;"></div>
|
||||
</div>
|
||||
</div><!-- /.panel-body -->
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div class="col-lg-8">
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||
<b>Punch card - login</b>
|
||||
</div>
|
||||
<div id="panelbody" class="panel-body" style="">
|
||||
<div id="punchcard" style="width:100%; height: 100%;"></div>
|
||||
</div>
|
||||
</div><!-- /.panel-body -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||
<b>Contribution after login (API vs non-API)</b>
|
||||
</div>
|
||||
<div id="panelbody" class="panel-body" style="">
|
||||
<div id="pieChart" style="width:100%; height: 20vh;"></div>
|
||||
</div>
|
||||
</div><!-- /.panel-body -->
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||
<b>Top login per organisation</b>
|
||||
</div>
|
||||
<div id="panelbody" class="panel-body" style="">
|
||||
<div id="barChart" style="width:100%; height: 20vh;"></div>
|
||||
</div>
|
||||
</div><!-- /.panel-body -->
|
||||
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||
<b>Contribution after login (API vs non-API)</b>
|
||||
</div>
|
||||
<div id="panelbody" class="panel-body" style="">
|
||||
<div id="pieChart" style="width:100%; height: 20vh;"></div>
|
||||
</div>
|
||||
</div><!-- /.panel-body -->
|
||||
</div>
|
||||
|
||||
</div><!-- /.col-lg-12 -->
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||
<b>Login overtime</b>
|
||||
</div>
|
||||
<div id="panelbody" class="panel-body" style="">
|
||||
<div id="lineChart" style="width:100%; height: 20vh;"></div>
|
||||
</div>
|
||||
</div><!-- /.panel-body -->
|
||||
</div><!-- /.col-lg-12 -->
|
||||
|
||||
</div><!-- /.row -->
|
||||
|
||||
</div> <!-- /.container-fluid -->
|
||||
|
@ -178,6 +200,40 @@ small {
|
|||
});
|
||||
});
|
||||
|
||||
$.getJSON( "{{ url_for('getUserLogins') }}", function( data ) {
|
||||
data = [{label: 'org1', data:[ Math.floor(Math.random() * 100) + 1]},
|
||||
{label: 'org2', data:[ Math.floor(Math.random() * 100) + 1]},
|
||||
{label: 'org3', data:[ Math.floor(Math.random() * 100) + 1]}]
|
||||
$.plot('#barChart', data, {
|
||||
series: {
|
||||
pie: {
|
||||
innerRadius: 0.5,
|
||||
show: true
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$.getJSON( "{{ url_for('getUserLoginsOvertime') }}", function( data ) {
|
||||
temp = [];
|
||||
var i=0;
|
||||
for (item of data) {
|
||||
temp.push([new Date(item[0]*1000), item[1]]);
|
||||
}
|
||||
console.log(temp);
|
||||
data = {label: 'Login overtime', data: temp}
|
||||
$.plot('#lineChart', [data], {
|
||||
lines: {
|
||||
show: true,
|
||||
steps: true,
|
||||
fill: true
|
||||
},
|
||||
xaxis: {
|
||||
mode: "time",
|
||||
minTickSize: [1, "hour"],
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import math, random
|
||||
import os
|
||||
import json
|
||||
import datetime, time
|
||||
|
||||
import util
|
||||
|
||||
class Users_helper:
|
||||
def __init__(self, serv_redis_db, cfg):
|
||||
self.serv_redis_db = serv_redis_db
|
||||
self.cfg = cfg
|
||||
|
||||
def add_user_login(self, timestamp):
|
||||
timestampDate = datetime.datetime.fromtimestamp(float(timestamp))
|
||||
timestampDate_str = util.getDateStrFormat(timestampDate)
|
||||
keyname = "{}:{}".format('USER_LOGIN', timestampDate_str)
|
||||
self.serv_redis_db.sadd(keyname, timestamp)
|
||||
|
||||
def getUserLogins(self, date):
|
||||
keyname = "USER_LOGIN:{}"
|
||||
timestamps = self.serv_redis_db.smembers(keyname.format(util.getDateStrFormat(date)))
|
||||
timestamps = [int(timestamp.decode('utf8')) for timestamp in timestamps]
|
||||
return timestamps
|
||||
|
||||
def getUserLoginsForPunchCard(self, date, prev_days=6):
|
||||
week = {}
|
||||
for curDate in util.getXPrevDaysSpan(date, prev_days):
|
||||
timestamps = self.getUserLogins(curDate)
|
||||
day = {}
|
||||
for timestamp in timestamps:
|
||||
date = datetime.datetime.fromtimestamp(float(timestamp))
|
||||
if date.hour not in day:
|
||||
day[date.hour] = 0
|
||||
day[date.hour] += 1
|
||||
week[curDate.weekday()] = day
|
||||
|
||||
# Format data
|
||||
data = []
|
||||
for d in range(7):
|
||||
try:
|
||||
to_append = []
|
||||
for h in range(24):
|
||||
try:
|
||||
to_append.append(week[d][h])
|
||||
except KeyError:
|
||||
to_append.append(0)
|
||||
# swap 24 and 1. (punchcard starts at 1h)
|
||||
temp = to_append[1:]+[to_append[0]]
|
||||
data.append(temp)
|
||||
except KeyError: # no data
|
||||
data.append([0 for x in range(24)])
|
||||
|
||||
return data
|
||||
|
||||
def getUserLoginsOvertime(self, date, prev_days=6):
|
||||
dico_hours = {}
|
||||
for curDate in util.getXPrevHoursSpan(date, prev_days*24):
|
||||
dico_hours[util.getTimestamp(curDate)] = 0 # populate with empty data
|
||||
|
||||
for curDate in util.getXPrevDaysSpan(date, prev_days):
|
||||
timestamps = self.getUserLogins(curDate)
|
||||
for timestamp in timestamps: # sum occurence during the current hour
|
||||
date = datetime.datetime.fromtimestamp(float(timestamp))
|
||||
date = date.replace(minute=0, second=0, microsecond=0)
|
||||
dico_hours[util.getTimestamp(date)] += 1
|
||||
|
||||
# Format data
|
||||
data = []
|
||||
for date, occ in dico_hours.items():
|
||||
data.append([date, occ])
|
||||
|
||||
data.sort(key=lambda x: x[0])
|
||||
return data
|
13
util.py
13
util.py
|
@ -24,8 +24,19 @@ def getXPrevDaysSpan(date, days):
|
|||
to_return.append(de - datetime.timedelta(days=i))
|
||||
return to_return
|
||||
|
||||
def getXPrevHoursSpan(date, hours):
|
||||
de = date
|
||||
de = de.replace(minute=0, second=0, microsecond=0)
|
||||
ds = de - datetime.timedelta(hours=hours)
|
||||
|
||||
delta = de - ds
|
||||
to_return = []
|
||||
for i in range(0, int(delta.total_seconds()/3600)+1):
|
||||
to_return.append(de - datetime.timedelta(hours=i))
|
||||
return to_return
|
||||
|
||||
def getDateStrFormat(date):
|
||||
return str(date.year)+str(date.month).zfill(2)+str(date.day).zfill(2)
|
||||
|
||||
def getTimestamp(date):
|
||||
return time.mktime(date.timetuple())
|
||||
return int(time.mktime(date.timetuple()))
|
||||
|
|
|
@ -16,6 +16,7 @@ import geoip2.database
|
|||
|
||||
import util
|
||||
import contributor_helper
|
||||
import users_helper
|
||||
|
||||
configfile = os.path.join(os.environ['DASH_CONFIG'], 'config.cfg')
|
||||
cfg = configparser.ConfigParser()
|
||||
|
@ -53,6 +54,7 @@ serv_redis_db = redis.StrictRedis(
|
|||
db=cfg.getint('RedisDB', 'db'))
|
||||
|
||||
contributor_helper = contributor_helper.Contributor_helper(serv_redis_db, cfg)
|
||||
users_helper = users_helper.Users_helper(serv_redis_db, cfg)
|
||||
|
||||
reader = geoip2.database.Reader(PATH_TO_DB)
|
||||
|
||||
|
@ -194,10 +196,8 @@ def handler_user(zmq_name, jsondata):
|
|||
timestamp = json_user['current_login']
|
||||
except KeyError:
|
||||
return
|
||||
now = datetime.datetime.now()
|
||||
today_str = util.getDateStrFormat(now)
|
||||
keyname = "{}:{}".format('USER_LOGIN', today_str)
|
||||
serv_redis_db.sadd(keyname, timestamp)
|
||||
if timestamp != 0: # "invited_by": "xxxx" ???
|
||||
users_helper.add_user_login(timestamp)
|
||||
|
||||
def handler_conversation(zmq_name, jsonevent):
|
||||
try: #only consider POST, not THREAD
|
||||
|
|
Loading…
Reference in New Issue