123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- /**
- * TraCINg-Server - Gathering and visualizing cyber incidents on the world
- *
- * Copyright 2013 Matthias Gazzari, Annemarie Mattmann, André Wolski
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /**
- * Creates a world object containing a 2d map, 2d streetmap and a 3d globe
- */
- var world = new function() {
- // constants
- var view = {
- MAP: 0,
- STREETMAP: 1,
- GLOBE: 2,
- NULL: 3
- };
- var currentView;
- var globeObject; // the 3d globe
- var mapObject; // the 2d map
- var streetmapObject; // the street map
- var timeout = 300; // timeout interval
- var timer = null; // timeout id
- var key = 0; // current key for delayed database request
- var dataset = null; // database data
- var requestPaused = "."; // text to show in speed information if loading is currently paused
- var attackNumberHash = {}; // hashmap containing the number of attacks per Lat/Lng position
- var controller = new Controller();
-
- /**
- * Toggle whether the key control is enabled or not
- */
- this.toggleEnabled = controller.toggleEnabled;
-
- /**
- * Leave maps
- */
- this.leaveMap = function() {
- currentView = view.NULL;
- controller.unregisterCallbacks();
- }
-
- /**
- * Show 2d map
- */
- this.showMap = function() {
- if (mapObject === undefined) {
- mapObject = new map($('#map'), 'world_mill_en', 'navy');
-
- }
- currentView = view.MAP;
- controller.registerCallbacks({
- zoom: function(dir) {
- if (dir == controller.args.IN)
- mapObject.zoom(1.6);
- if (dir == controller.args.OUT)
- mapObject.zoom(1/1.6);
- },
- move: function(dir) {
- var speed = 120;
- if (dir == controller.args.LEFT)
- mapObject.move(speed,0);
- if (dir == controller.args.RIGHT)
- mapObject.move(-speed, 0);
- if (dir == controller.args.UP)
- mapObject.move(0, speed);
- if (dir == controller.args.DOWN)
- mapObject.move(0, -speed);
- },
- toggle: undefined
- });
- }
-
- /**
- * Show streetmap
- */
- this.showStreetmap = function() {
- if (streetmapObject === undefined) {
- streetmapObject = new streetmap('streetmap');
- }
- currentView = view.STREETMAP;
- controller.registerCallbacks({
- zoom: function(dir) {
- if (dir == controller.args.IN)
- streetmapObject.zoom(1);
- if (dir == controller.args.OUT)
- streetmapObject.zoom(-1);
- },
- move: function(dir) {
- var speed = 120;
- if (dir == controller.args.LEFT)
- streetmapObject.move(speed,0);
- if (dir == controller.args.RIGHT)
- streetmapObject.move(-speed, 0);
- if (dir == controller.args.UP)
- streetmapObject.move(0, speed);
- if (dir == controller.args.DOWN)
- streetmapObject.move(0, -speed);
- },
- toggle: undefined
- });
- }
-
- /**
- * Show 3d globe
- */
- this.showGlobe = function() {
- if (globeObject === undefined) {
- // create globeObject
- var container = document.getElementById('globe');
- // set modifyMarkerLabel function for globe
- var modifyMarkerLabel = function(label) {
- if (!advInfo) {
- var splittedLabel = label.split(";");
- label = splittedLabel[0];
- }
- return label;
- };
- // set setCountryLabel function for globe
- var setCountryLabel = function(cc, markers, allMarkers) {
- var country = countryName[cc];
- return country + " (" + markers + " attacks of " + allMarkers + " total)";
- };
- globeObject = new GLOBE.main(container, "extern/globe/images/", {
- 'modifyMarkerLabel': modifyMarkerLabel,
- 'setCountryLabel': setCountryLabel
- });
- }
- else
- globeObject.resize();
- currentView = view.GLOBE;
- controller.registerCallbacks({
- zoom: function(dir) {
- if (dir == controller.args.IN)
- globeObject.zoom(100);
- if (dir == controller.args.OUT)
- globeObject.zoom(-100);
- },
- move: function(dir) {
- if (dir == controller.args.LEFT)
- globeObject.rotate(-0.000001, 0);
- if (dir == controller.args.RIGHT)
- globeObject.rotate(0.000001, 0);
- if (dir == controller.args.UP)
- globeObject.rotate(0, 0.0000005);
- if (dir == controller.args.DOWN)
- globeObject.rotate(0, -0.0000005);
- },
- toggle: function() {
- globeObject.toggleView();
- }
- });
- }
-
- /**
- * Delay database markings
- */
- this.delayedMarking = function delayedMarking(data, live) {
- var total_attacks = 0;
- for(var i=0; i<data.length; i++){
- var d = data[i];
- var llHash = d.location[0] + d.location[1];
- if (attackNumberHash[llHash] != undefined) {
- attackNumberHash[llHash] += d.count;
- } else {
- attackNumberHash[llHash] = d.count;
- }
- total_attacks += d.count;
- // define source color and label
- var sourceColor = "red";
- var sourceLabel = getLabel(d, false);
- // each view has it own marker key
- var mapKey;
- var streetmapKey;
- var globeKey;
- // mark on 2d map and try to animate
- if (mapObject != undefined) {
- mapKey = mapObject.addMarker(d._id.cc, d.location, sourceColor, sourceLabel, d.count);
- if (currentView == view.MAP) {
- var pos = mapObject.getPosition(d.location[0], d.location[1]);
- animateMarker(pos.x, pos.y, sourceColor, "#map", mapKey);
- }
- }
- // mark on streetmap and try to animate
- if (streetmapObject != undefined) {
- streetmapKey = streetmapObject.addMarker(d.location, sourceColor, sourceLabel);
- if (currentView == view.STREETMAP) {
- var pos = streetmapObject.getPosition(d.location[0], d.location[1]);
- animateMarker(pos.x, pos.y, sourceColor, "#streetmap", streetmapKey);
- }
- }
- // mark on 3d map
- if (globeObject != undefined && globeObject.addMarker != undefined) {
- globeKey = globeObject.addMarker(d._id.cc, d.location[0], d.location[1], sourceLabel);
- // globe has its own mechanism to animate a marker
- }
- }
- if (data.length > 0) {
- world.finishLoading(true);
- } else {
- world.finishLoading(false);
- }
- // show number of attacks loaded
- if (data.length > 0) {
- $('#requestInfo').text('Successfully loaded ' + total_attacks + ' attacks.');
- }
- }
-
- /**
- * Stop the timeout of the database delay timer, reset all values, the progress bar and "Get Incidents" Button
- */
- this.finishLoading = function finishLoading(showState) {
- // stop the timer
- clearTimeout(timer);
- // reset timer
- timer = null;
- dataset = null;
- key = 0;
- timeout = 500;
- if (showState) {
- // update progress bar
- $('.bar').css('width', '100%');
- } else {
- // reset progress bar
- $('.bar').css('width', 0);
- }
- // reset play button to pause if necessary
- if ($('#playButton i').hasClass('icon-play')) {
- $('#playButton i').addClass('icon-pause');
- $('#playButton i').removeClass('icon-play');
- }
- // reset "Get Incidents" button (stop showing "Loading..."), disable control buttons
- $('#getIncidents').text('Get Incidents');
- $('#getIncidents').removeClass("disabled");
- disableRequestControl();
- // reset info on loading progress and speed
- $('#requestInfo').text('');
- $('#requestSpeedInfo').text('');
- }
-
- /*
- * Change the timeout intervals of the database delay timer
- */
- this.changeTimer = function(value) {
- // do not speed up too fast
- if (timeout + value <= 0)
- value = -100;
- // and slow down in the same interval as the speedup
- if (timeout - value < 0)
- value = 100;
- // do not speed up to "no time"
- if (timeout + value <= 0)
- value = 0;
- // increase or decrease the timeout interval depending on the given value
- timeout += value;
- // do not speed up "in negative time"
- if (timeout < 0)
- timeout = 0;
- $('#requestSpeedInfo').text('Current speed: ' + Math.round(100*(1000/timeout))/100 + ' attacks/second' + requestPaused);
- }
-
- /**
- * Reset the timeout of the database delay timer to 0
- */
- this.resetTimer = function() {
- timeout = 0;
- $('#requestSpeedInfo').text('');
- }
-
- /**
- * Stop the timeout of the database delay timer
- */
- this.stopTimer = function() {
- clearTimeout(timer);
- requestPaused = " (currently paused).";
- $('#requestSpeedInfo').text('Current speed: ' + Math.round(100*(1000/timeout))/100 + ' attacks/second' + requestPaused);
- }
-
- /**
- * Restart the timeout of the database delay timer
- */
- this.restartTimer = function() {
- this.delayedMarking(dataset, live);
- requestPaused = ".";
- $('#requestSpeedInfo').text('Current speed: ' + Math.round(100*(1000/timeout))/100 + ' attacks/second' + requestPaused);
- }
-
- /**
- * Mark an incident on the 2d map, the street map and the 3d globe
- */
- this.markIncident = function(data, live, noAnimation) {
- // remove alert saying "Waiting for attacks..."
- $("#tableWaitingAlert").remove();
-
- // update hashmap for displaying number of attacks per LatLng
- llHash = new String(data.src.ll ? data.src.ll[0] : "") + new String(data.src.ll ? data.src.ll[1] : "");
- if (attackNumberHash[llHash] != undefined) {
- attackNumberHash[llHash]++;
- } else {
- attackNumberHash[llHash] = 1;
- }
-
- // define source color and label
- var sourceColor = "red";
- var sourceLabel = getLabel(data, live);
-
- // each view has it own marker key
- var mapKey;
- var streetmapKey;
- var globeKey;
- // mark on 2d map and try to animate
- if (mapObject != undefined) {
- mapKey = mapObject.addMarker(data.src.cc, data.src.ll, sourceColor, sourceLabel);
- if (currentView == view.MAP && !noAnimation) {
- var pos = mapObject.getPosition(data.src.ll[0], data.src.ll[1]);
- animateMarker(pos.x, pos.y, sourceColor, "#map", mapKey);
- }
- }
- // mark on streetmap and try to animate
- if (streetmapObject != undefined) {
- streetmapKey = streetmapObject.addMarker(data.src.ll, sourceColor, sourceLabel);
- if (currentView == view.STREETMAP && !noAnimation) {
- var pos = streetmapObject.getPosition(data.src.ll[0], data.src.ll[1]);
- animateMarker(pos.x, pos.y, sourceColor, "#streetmap", streetmapKey);
- }
- }
- // mark on 3d map
- if (globeObject != undefined && globeObject.addMarker != undefined) {
- globeKey = globeObject.addMarker(data.src.cc, data.src.ll[0], data.src.ll[1], sourceLabel);
- // globe has its own mechanism to animate a marker
- }
-
- // set timeout to remove marker if in live view
- if (live) {
- var expireTime = 300000;
- setTimeout(
- function() {
- // update hashmap for displaying number of attacks per LatLng
- llHash = new String(data.src.ll[0]) + new String(data.src.ll[1]);
- if (attackNumberHash[llHash] > 0) {
- attackNumberHash[llHash]--;
- } else {
- attackNumberHash[llHash] = undefined;
- }
- // remove marker on 2d maps and globe
- if (mapKey != undefined && mapObject != undefined)
- mapObject.removeMarker(mapKey);
- if (streetmapKey != undefined && streetmapObject != undefined)
- streetmapObject.removeMarker(streetmapKey);
- if (globeKey != undefined && globeObject != undefined)
- globeObject.removeMarker(globeKey);
- },
- expireTime
- );
- }
- }
-
- /**
- * State whether there is a marker on the jVectorMap
- */
- this.jvmHasMarker = function() {
- if (mapObject != undefined) {
- return mapObject.hasMarker();
- }
- return false;
- }
-
- /**
- * State whether there is a marker on the streetmap
- */
- this.stMapHasMarker = function() {
- if (streetmapObject != undefined) {
- return streetmapObject.hasMarker();
- }
- return false;
- }
-
- /**
- * State whether there is a marker on the globe
- */
- this.globeHasMarker = function() {
- if (globeObject != undefined && globeObject.hasMarker != undefined) {
- return globeObject.hasMarker();
- }
- return false;
- }
-
- /**
- * Reset every marker on the 2d map, the streetmap and the 3d globe
- */
- this.reset = function() {
- // reset 2d maps abd globe
- mapObject && mapObject.reset();
- streetmapObject && streetmapObject.reset();
- globeObject && globeObject.reset();
-
- attackNumberHash = {};
-
- // reset progress bar
- $('.bar').css('width', 0);
- // reset progress information
- $('#requestInfo').text('');
- //TODO also influence x/y entries loaded and successfully loaded y items?
- }
-
- /**
- * Reset the table
- */
- this.resetTable = function() {
- // reset table
- $("#attackTable").dataTable().fnClearTable();
- }
-
- /**
- * Determine label shown on both the 2d map and the 3d globe.
- */
- function getLabel(data, live) {
- var label = "";
- // standard information label
- if (live)
- label += "Live data";
- else
- label += "Database data";
- var llKey = !live ? data.location[0] + data.location[1] : new String(data.src.ll ? data.src.ll[0] : "") + new String(data.src.ll ? data.src.ll[1] : "");
- var num = attackNumberHash[llKey];
- if (num != null) {
- if (num == 1)
- label += ": " + num + " attack";
- else
- label += ": " + num + " attacks";
- }
- label += "<br />Attack source (marked here): ";
- var city = live ? data.src.city : data._id.city;
- if(city){
- label += city + ",";
- }
- label += live ? data.src.country : data._id.country;
- // advanced information
- label += ";<br />Destination: ";
- var destination = "";
- if(live){
- if (data.dst.city != "" && data.dst.city != undefined) {
- destination += data.dst.city + ", ";
- }
- if (data.dst.country != "" && data.dst.country != undefined) {
- destination += data.dst.country;
- }
- } else {
- destination = data.destination;
- }
- if (destination)
- label += destination;
- else
- label += "Unknown";
- label += ";<br />Date: " + formatDate(data);
-
- var type = typeid2str(data.type)
- if (type != "" && type != undefined);
- label += ";<br />Type: " + type;
-
- if (data.authorized)
- label += ";<br />Authorized Sensor";
- else
- label += ";<br />Unauthorized Sensor";
-
- return label;
- }
- /**
- * Format the date to a more readable representation
- */
- function formatDate(incident) {
- var date = incident.date && new Date(incident.date) || new Date();
- var day = date.getDate();
- if (date.getDate() < 10)
- day = "0" + date.getDate();
- var month = (date.getMonth() + 1);
- if ((date.getMonth() + 1) < 10)
- month = "0" + (date.getMonth() + 1);
- var hour = date.getHours();
- if (date.getHours() < 10)
- hour = "0" + date.getHours();
- var minute = date.getMinutes();
- if (date.getMinutes() < 10)
- minute = "0" + date.getMinutes();
- var dateFormat = day + "." + month + "." + date.getFullYear() + " " + hour + ":" + minute;
-
- return dateFormat;
- }
-
- /**
- * Generate one table entry and return it as a string to be inserted
- */
- function generateTableEntry(incident) {
- // set city and country names
- if (incident.src.city == undefined)
- incident.src.city = "";
- if (incident.dst.country == undefined)
- incident.dst.country = "";
- if (incident.dst.city == undefined)
- incident.dst.city = "";
- if (incident.src.port == 0)
- incident.src.port = "";
- if (incident.dst.port == 0)
- incident.dst.port = "";
-
- //format date
- dateFormat = formatDate(incident);
- var log = '';
- if (incident.log && incident.log != ''){
- log = '<a href="#showLog" data-toggle="modal" onclick="javascript:showLog(\'' + incident._id + '\');">show log</a>';
- }
-
- var type = typeid2str(incident.type);
- var typeDescr = typeid2descr(incident.type);
-
- // popup for md5sum so it does not take so much space in the table
- var md5 = "";
- if (incident.md5sum && incident.md5sum != '') {
- var virustotalLink = "https://www.virustotal.com/en/search/?query=" + incident.md5sum;
- var popoverContent = "Md5sum of malware hash: " + incident.md5sum + "<br \\> Get more information about this malware from virustotal: <a href=\'" + virustotalLink + "\' target='_blank'>Click here</a> (by doing so you will open a different website)!";
- var url = "\"./extern/bootstrap/images/glyphicons-halflings.png\"";
- md5 = "<a class='btn' rel='popover' data-html='true' data-content=\"" + popoverContent + "\" data-animation='false' data-placement='left'><i class='icon-info-sign' style='background-image: url("+ url +");'></i></a>";
- }
-
- var authorized = "";
- if (incident.authorized) {
- authorized = "<p class='text-success'>Yes</p>";
- } else {
- authorized = "<p class='text-error'>No</p>";
- }
- //make entry
- var attackTableEntry = [incident.sensortype, incident.sensorname, '<span title="' + typeDescr + '">' + type + '</span>', dateFormat, incident.src.country, incident.src.city, incident.src.port, incident.dst.country, incident.dst.city, incident.dst.port, authorized, md5, log];
- return attackTableEntry;
- }
- this.generateTableEntry = generateTableEntry;
-
- /**
- * Make table entries (includes time formatting)
- */
- function makeTableEntry(attackTableEntries) {
- $("#attackTable").dataTable().fnAddData(attackTableEntries);
- makePopovers();
- }
- this.makeTableEntry = makeTableEntry;
-
-
- /**
- * Make popovers in the table
- */
- function makePopovers() {
- console.log("makePopovers");
- $('a[rel=popover]').popover({});
- }
- this.makePopovers = makePopovers;
-
- /**
- * animate new marker using jquery animate()
- */
- function animateMarker(x, y, color, container, key) {
- // define style of the animation div
- var style = {
- 'background-color': color,
- 'position': 'absolute',
- 'border-radius': '100px',
- 'height': '40px',
- 'width': '40px',
- 'margin-top': '-20px',
- 'margin-left': '-20px',
- 'left': x + 'px',
- 'top': y + 'px',
- };
- // create a marker animation
- $(container).append('<div class="markerAnimation" id=' + key + '></div>');
- // add the css style to the marker animation
- $("#" + key + ".markerAnimation").css(style);
- // animate the marker and delete it afterwards
- $("#" + key + ".markerAnimation").fadeOut(
- 1000,
- $("#" + key + ".markerAnimation").remove
- );
- }
-
- function updateAttackTableHeight() {
- var attackTable = $("#attackTable").dataTable();
-
- var height = $(window).height();
-
- height -= $("#table .dataTables_scrollBody").offset().top;
- height -= $("#table .dataTables_scroll + div").height();
-
- console.log("attackTableHeight: " + height);
-
- $("#table .dataTables_scrollBody").css({"max-height": height});
- }
- /**
- * resize table
- */
- function resize() {
- updateAttackTableHeight();
- $("#attackTable").dataTable().fnDraw();
- }
- this.resize = resize;
- }
- function showLog(id){
- console.log("showLog " + id);
- socket.emit("getLog", id, function(content){
- console.log("showLog content: " + content);
- $('#showLogLabel').text("Log for id " + id);
- $('#showLogBody').html(content);
- $('#showLog').modal();
- });
- }
- $(function(){
- $("#attackTable").dataTable({
- "aaSorting": [[ 3, "desc" ]], // order by date, new items first
- "sScrollY": "100%",
- bServerSide: false,
- "ajax": function(request, callback, settings){
- if(!currentTableFilter) return;
- var attackFilter = currentTableFilter;
- attackFilter["page"] = request.start;
- attackFilter["perpage"] = request.length;
- attackFilter["query"] = request.search.value;
- socket.emit("requestAttacksForTable", attackFilter);
- console.log(arguments);
- },
- "fnDrawCallback": function() {
- world.makePopovers();
- }
- });
- setTimeout(function() {
- world.resize();
- }, 10);
- });
- $(window).resize($.throttle(250,function() {
- world.resize();
- }));
|