mirror of https://github.com/MISP/misp-dashboard
Added draft support of radius
parent
09e48f33f1
commit
f1b20883b1
26
server.py
26
server.py
|
@ -2,7 +2,7 @@
|
||||||
from flask import Flask, render_template, request, Response, jsonify
|
from flask import Flask, render_template, request, Response, jsonify
|
||||||
import json
|
import json
|
||||||
import redis
|
import redis
|
||||||
import random
|
import random, math
|
||||||
import configparser
|
import configparser
|
||||||
from time import gmtime as now
|
from time import gmtime as now
|
||||||
from time import sleep, strftime
|
from time import sleep, strftime
|
||||||
|
@ -149,6 +149,30 @@ def getHitMap():
|
||||||
data = getZrange(keyCateg, dayNum, topNum)
|
data = getZrange(keyCateg, dayNum, topNum)
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
@app.route("/_getCoordsByRadius")
|
||||||
|
def getCoordsByRadius():
|
||||||
|
to_return = []
|
||||||
|
try:
|
||||||
|
dateStart = datetime.datetime.fromtimestamp(float(request.args.get('dateStart')))
|
||||||
|
dateEnd = datetime.datetime.fromtimestamp(float(request.args.get('dateEnd')))
|
||||||
|
centerLat = request.args.get('centerLat')
|
||||||
|
centerLon = request.args.get('centerLon')
|
||||||
|
radius = int(math.ceil(float(request.args.get('radius'))))
|
||||||
|
except:
|
||||||
|
return jsonify(to_return)
|
||||||
|
|
||||||
|
delta = dateEnd - dateStart
|
||||||
|
for i in range(delta.days+1):
|
||||||
|
correctDatetime = dateStart + datetime.timedelta(days=i)
|
||||||
|
date_str = str(correctDatetime.year)+str(correctDatetime.month)+str(correctDatetime.day)
|
||||||
|
keyCateg = 'GEO_RAD'
|
||||||
|
keyname = "{}:{}".format(keyCateg, date_str)
|
||||||
|
res = serv_redis_db.georadius(keyname, centerLon, centerLat, radius, unit='km', withcoord=True)
|
||||||
|
res = [ [json.loads(data), coord] for data, coord in res ] #correctly send the json
|
||||||
|
to_return.append(res)
|
||||||
|
|
||||||
|
return jsonify(to_return)
|
||||||
|
|
||||||
@app.route("/_logs")
|
@app.route("/_logs")
|
||||||
def logs():
|
def logs():
|
||||||
return Response(event_stream_log(), mimetype="text/event-stream")
|
return Response(event_stream_log(), mimetype="text/event-stream")
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
.panel-body {
|
.panel-body {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
.panel {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.col-lg-6 {
|
.col-lg-6 {
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
@ -69,7 +72,7 @@ small {
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0; padding-left: 15px;">
|
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0; padding-left: 15px;">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-brand" href="{{ url_for('geo') }}">Misp Geolocalization</a>
|
<a class="navbar-brand" href="{{ url_for('geo') }}">Misp Geolocalisation</a>
|
||||||
<div id="ledsHolder" style="float: right; height: 50px;">
|
<div id="ledsHolder" style="float: right; height: 50px;">
|
||||||
<div class='leftSepa textTopHeader'>
|
<div class='leftSepa textTopHeader'>
|
||||||
<strong>Zoom level:</strong>
|
<strong>Zoom level:</strong>
|
||||||
|
@ -81,6 +84,9 @@ small {
|
||||||
<option value="11">11</option>
|
<option value="11">11</option>
|
||||||
<option value="9">9</option>
|
<option value="9">9</option>
|
||||||
<option value="7">7</option>
|
<option value="7">7</option>
|
||||||
|
<option value="5">5</option>
|
||||||
|
<option value="4">4</option>
|
||||||
|
<option value="3">3</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class='leftSepa textTopHeader'>
|
<div class='leftSepa textTopHeader'>
|
||||||
|
@ -168,12 +174,26 @@ small {
|
||||||
<b id="worldMapHeader">Hit map </b>
|
<b id="worldMapHeader">Hit map </b>
|
||||||
</div>
|
</div>
|
||||||
<div id="panelbody" class="panel-body" style="height: 100%;">
|
<div id="panelbody" class="panel-body" style="height: 100%;">
|
||||||
<div id="worldMap" style="width:100%; height: 88vh; position: relative;"></div>
|
<div id="worldMap" style="width:100%; height: 30vh; position: relative;"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.panel-body -->
|
<!-- /.panel-body -->
|
||||||
|
|
||||||
</div><!-- /.panel -->
|
</div><!-- /.panel -->
|
||||||
|
|
||||||
|
<div class="panel panel-default" style="height: 100%;">
|
||||||
|
<div class="panel-heading bg-info" style="font-weight: bold; padding: 5px 10px;">
|
||||||
|
<b id="radiusHeader" style="font-size: 18px;">Geospatial information</b>
|
||||||
|
<strong class='leftSepa textTopHeader' style="float: none; padding: 11px;">Dates:
|
||||||
|
<input type="text" id="datepickerRadiusFrom" size="20" style="">
|
||||||
|
<input type="text" id="datepickerRadiusTo" size="20" style="">
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div id="panelbody" class="panel-body" style="height: 100%;">
|
||||||
|
<div id="radiusMap" style="width:100%; height: 51vh; position: relative;"></div>
|
||||||
|
</div>
|
||||||
|
<!-- /.panel-body -->
|
||||||
|
</div><!-- /.panel -->
|
||||||
|
|
||||||
|
|
||||||
</div><!-- /.col-lg-6 -->
|
</div><!-- /.col-lg-6 -->
|
||||||
|
|
||||||
</div><!-- /.col-lg-12 -->
|
</div><!-- /.col-lg-12 -->
|
||||||
|
@ -214,7 +234,12 @@ small {
|
||||||
var updateFrequency = 1000*60*60*1 //1h
|
var updateFrequency = 1000*60*60*1 //1h
|
||||||
var allOpenStreetMap = {};
|
var allOpenStreetMap = {};
|
||||||
var savedMarker = {};
|
var savedMarker = {};
|
||||||
|
var savedMarkerRadius = [];
|
||||||
var datePickerWidget;
|
var datePickerWidget;
|
||||||
|
var datePickersRadiusWidget;
|
||||||
|
var radiusOpenStreetMap;
|
||||||
|
var circleRadius;
|
||||||
|
|
||||||
|
|
||||||
for(var i=1; i<7; i++) {
|
for(var i=1; i<7; i++) {
|
||||||
allOpenStreetMap[i] = L.map('topMap'+i).setView([0, 0], 0);
|
allOpenStreetMap[i] = L.map('topMap'+i).setView([0, 0], 0);
|
||||||
|
@ -284,6 +309,42 @@ small {
|
||||||
worldMapObj.series.regions[0].setValues(regionhits);
|
worldMapObj.series.regions[0].setValues(regionhits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateRadius(e) {
|
||||||
|
var curObj = e.target;
|
||||||
|
var curCoord = curObj.getCenter();
|
||||||
|
var zoom = curObj.zoom;
|
||||||
|
var scale = getScale(radiusOpenStreetMap.getZoom());
|
||||||
|
circleRadius.setRadius(scale);
|
||||||
|
circleRadius.setLatLng(curCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScale(zoom) {
|
||||||
|
return 64 * Math.pow(2, (18-zoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryAndAddMarkers() {
|
||||||
|
var radius_km = circleRadius.getRadius() / 1000;
|
||||||
|
var coord = circleRadius._latlng;
|
||||||
|
var dateStart = datePickersRadiusWidgetFrom.datepicker("getDate").getTime() / 1000;
|
||||||
|
var dateEnd = datePickersRadiusWidgetTo.datepicker("getDate").getTime() / 1000;
|
||||||
|
$.getJSON("{{ url_for('getCoordsByRadius') }}?dateStart="+dateStart+"&dateEnd="+dateEnd+"¢erLat="+coord.lat+"¢erLon="+coord.lng+"&radius="+radius_km, function(list){
|
||||||
|
// remove old markers
|
||||||
|
for (var i in savedMarkerRadius) {
|
||||||
|
savedMarkerRadius[i].remove(); // remove marker
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = list[0];
|
||||||
|
for (var dayListIndex in list) {
|
||||||
|
var jsonData = list[dayListIndex][0];
|
||||||
|
var coordJson = list[dayListIndex][1];
|
||||||
|
|
||||||
|
var marker = L.marker([coordJson[1], coordJson[0]]).addTo(radiusOpenStreetMap);
|
||||||
|
savedMarkerRadius.push(marker);
|
||||||
|
marker.bindPopup('<strong>'+jsonData.categ+'</strong><br>'+jsonData.value, {autoClose:false}).openPopup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function days_between(date1, date2) {
|
function days_between(date1, date2) {
|
||||||
var ONEDAY = 60*60*24*1000;
|
var ONEDAY = 60*60*24*1000;
|
||||||
var diff_ms = Math.abs(date1.getTime() - date2.getTime());
|
var diff_ms = Math.abs(date1.getTime() - date2.getTime());
|
||||||
|
@ -313,16 +374,49 @@ small {
|
||||||
showAnim: "slideDown",
|
showAnim: "slideDown",
|
||||||
onSelect: updateAll
|
onSelect: updateAll
|
||||||
};
|
};
|
||||||
|
var datePickerRadiusOptions = {
|
||||||
|
showOn: "button",
|
||||||
|
minDate: -31,
|
||||||
|
maxDate: 0,
|
||||||
|
buttonImage: "{{ url_for('static', filename='pics/calendar.gif') }}",
|
||||||
|
buttonImageOnly: true,
|
||||||
|
buttonText: "Select date",
|
||||||
|
showAnim: "slideDown",
|
||||||
|
onSelect: updateRadius
|
||||||
|
};
|
||||||
|
|
||||||
datePickerWidget = $( "#datepicker" )
|
datePickerWidget = $( "#datepicker" )
|
||||||
datePickerWidget.datepicker(datePickerOptions);
|
datePickerWidget.datepicker(datePickerOptions);
|
||||||
datePickerWidget.datepicker("setDate", new Date());
|
datePickerWidget.datepicker("setDate", new Date());
|
||||||
|
|
||||||
|
// radius
|
||||||
|
datePickersRadiusWidgetFrom = $( "#datepickerRadiusFrom" )
|
||||||
|
datePickersRadiusWidgetFrom.datepicker(datePickerRadiusOptions);
|
||||||
|
datePickersRadiusWidgetFrom.datepicker("setDate", new Date());
|
||||||
|
datePickersRadiusWidgetTo = $( "#datepickerRadiusTo" )
|
||||||
|
datePickersRadiusWidgetTo.datepicker(datePickerRadiusOptions);
|
||||||
|
datePickersRadiusWidgetTo.datepicker("setDate", new Date());
|
||||||
|
radiusOpenStreetMap = L.map('radiusMap', {closePopupOnClick: false} ).setView([30, 0], 2);
|
||||||
|
console.log(radiusOpenStreetMap);
|
||||||
|
new L.TileLayer(OSMURL, {minZoom: 0, maxZoom: 18}).addTo(radiusOpenStreetMap);
|
||||||
|
|
||||||
|
var radiusSize =
|
||||||
|
circleRadius = L.circle(radiusOpenStreetMap.getCenter(), {
|
||||||
|
color: 'red',
|
||||||
|
fillColor: '#f03',
|
||||||
|
fillOpacity: 0.4,
|
||||||
|
radius: getScale(radiusOpenStreetMap.getZoom())
|
||||||
|
}).addTo(radiusOpenStreetMap);
|
||||||
|
|
||||||
|
radiusOpenStreetMap.on('move', updateRadius);
|
||||||
|
|
||||||
$( "#zoom_selector" ).change(function() {
|
$( "#zoom_selector" ).change(function() {
|
||||||
var sel = parseInt($( this ).val());
|
var sel = parseInt($( this ).val());
|
||||||
ZOOMLEVEL = sel;
|
ZOOMLEVEL = sel;
|
||||||
updateAll();
|
updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
updateAll();
|
updateAll();
|
||||||
setInterval(function(){
|
setInterval(function(){
|
||||||
updateAll();
|
updateAll();
|
||||||
|
|
|
@ -47,6 +47,12 @@ def push_to_redis_zset(keyCateg, toAdd):
|
||||||
keyname = "{}:{}".format(keyCateg, today_str)
|
keyname = "{}:{}".format(keyCateg, today_str)
|
||||||
serv_redis_db.zincrby(keyname, toAdd)
|
serv_redis_db.zincrby(keyname, toAdd)
|
||||||
|
|
||||||
|
def push_to_redis_geo(keyCateg, lon, lat, content):
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
today_str = str(now.year)+str(now.month)+str(now.day)
|
||||||
|
keyname = "{}:{}".format(keyCateg, today_str)
|
||||||
|
serv_redis_db.geoadd(keyname, lon, lat, content)
|
||||||
|
|
||||||
|
|
||||||
def ip_to_coord(ip):
|
def ip_to_coord(ip):
|
||||||
resp = reader.city(ip)
|
resp = reader.city(ip)
|
||||||
|
@ -66,6 +72,7 @@ def getCoordAndPublish(zmq_name, supposed_ip, categ):
|
||||||
coord_list = [coord['lat'], coord['lon']]
|
coord_list = [coord['lat'], coord['lon']]
|
||||||
push_to_redis_zset('GEO_COORD', json.dumps(coord_dic))
|
push_to_redis_zset('GEO_COORD', json.dumps(coord_dic))
|
||||||
push_to_redis_zset('GEO_COUNTRY', rep['full_rep'].country.iso_code)
|
push_to_redis_zset('GEO_COUNTRY', rep['full_rep'].country.iso_code)
|
||||||
|
push_to_redis_geo('GEO_RAD', coord['lon'], coord['lat'], json.dumps({ 'categ': categ, 'value': supposed_ip }))
|
||||||
to_send = {
|
to_send = {
|
||||||
"coord": coord,
|
"coord": coord,
|
||||||
"categ": categ,
|
"categ": categ,
|
||||||
|
|
Loading…
Reference in New Issue