const jsonFile = "/api/monkey"; const jsonFileTelemetry = "/api/telemetry"; var monkeys = null; var scannedMachines = []; var generationDate = null; var temelGenerationDate = null; // The JSON must be fully loaded before onload() happens for calling draw() on 'monkeys' $.ajaxSetup({ async: false }); // Reading the JSON file containing the monkeys' informations $.getJSON(jsonFile, function(json) { monkeys = json.objects; generationDate = json.timestamp; }); // The objects used by vis var network = null; var nodes = []; var edges = []; var numOfParentLinks = 0; var numOfTunnelLinks = 0; var numOfScanLinks = 0; var showScannedHosts = true; // Images/icons constants const ICONS_DIR = "./css/img/objects/"; const ICONS_EXT = ".png"; const HOST_TYPE_MONKEY = "monkey"; const HOST_TYPE_SCAN = "scanned"; const EDGE_TYPE_PARENT = "parent"; const EDGE_TYPE_TUNNEL = "tunnel"; const EDGE_TYPE_SCAN = "scan"; const EDGE_COLOR_PARENT = "red"; const EDGE_COLOR_TUNNEL = "blue"; const EDGE_COLOR_SCAN = "gray"; // General options // If variable from local storage != null, assign it, otherwise set it's default value. var focusedOnNode = false; var monkeyCfg = undefined; var newCfg = undefined; var telemTable = undefined; JSONEditor.defaults.theme = 'bootstrap3'; function initAdmin() { if (monkeys == null) { errorMessage = "Could not find '" + jsonFile + "'."; $("#networkmap").html(errorMessage); } nodes = []; edges = []; createEdges(); createTunnels(); createScanned(); var data = { nodes: createNodes(), edges: edges }; updateCounters(); var options = { layout: { improvedLayout: false } }; // Using jQuery to get the element does not work with vis.js library var container = document.getElementById("monkeysmap"); network = new vis.Network(container, data, options); $("[name='chboxShowScanned']").bootstrapSwitch('onSwitchChange', toggleScannedHosts); $("[name='chboxMonkeyEnabled']").bootstrapSwitch('onSwitchChange', toggleMonkeyEnabled); prepareSearchEngine(); monkeyCfg = new JSONEditor(document.getElementById('monkey-config'),{ schema: { type: "object", title: "Monkey", properties: { alive: { title: "Alive", type: "boolean", }, }, options: { "collapsed": true }, }, disable_edit_json: false, }); newCfg = new JSONEditor(document.getElementById('new-config'),{ schema: { type: "object", title: "New Monkeys", properties: { alive: { title: "Alive", type: "boolean", }, }, options: { "collapsed": true }, }, disable_edit_json: false, }); newCfg.setValue({alive: true}); telemTable = $("#telemetris-table").DataTable({ "ordering": false, }); loadNewMonkeysConfig(); setInterval(updateMonkeys, 10000); addEventsListeners(); } function toggleScannedHosts(event, state) { if (event.type != "switchChange") { return; } if (state) { showScannedHosts = true; } else { showScannedHosts = false; } refreshDrawing(); } function refreshDrawing() { // function called before first init if (network == null) { return; } // keep old selection var selNode = network.getSelectedNodes(); if (showScannedHosts) { network.setData({nodes: nodes, edges: edges}); } else { var selectiveNodes = []; var selectiveEdges = []; for (var i=0; i 0) { refreshDrawing(); updateCounters(); } }); } /** * Builds node description */ function buildMonkeyDescription(monkey) { var html = " " + monkey.hostname + "
" + " " + monkey.description + "
" + " " + monkey.internet_access + "
"; if (monkey.dead) { html += " Dead
"; } if (!monkey.config.alive) { html += " Marked to be dead
"; } html += " " + monkey.keepalive + "
" + "
"; for (var i = 0; i < monkey.ip_addresses.length; i++) { html += monkey.ip_addresses[i] + "
" } return html; } function updateCounters() { $('#infoNumOfMonkeys').html(monkeys.length); $('#infoNumOfHosts').html(scannedMachines.length); $('#infoNumOfParents').html(numOfParentLinks); $('#infoNumOfTunnels').html(numOfTunnelLinks); } /** * Preparing the autocompletion search engine for the monkeys * TODO Upgrade the search with regex */ function prepareSearchEngine() { var engine = new Bloodhound({ datumTokenizer: Bloodhound.tokenizers.obj.whitespace("hostname"), queryTokenizer: Bloodhound.tokenizers.whitespace, local: this.monkeys }); engine.initialize(); $("#monkeySearch").typeahead({ hint: true, highlight: true, minLength: 1 }, { displayKey: "hostname", source: engine.ttAdapter() }); $("#monkeySearch").keypress(function(event) { const ENTER_KEY_CODE = 13; if (event.which == ENTER_KEY_CODE) { selectNode(undefined, zoom=true); } }); } /** * Manage the key presses events */ function onKeyPress(event){ var charCode = ("charCode" in event) ? event.charCode : event.keyCode; console.log("Unicode '" + charCode + "' was pressed."); } /** * Adding the events listeners */ function addEventsListeners() { network.on("doubleClick", onDoubleClick); network.on("select", onSelect); } /** * Manage the event when an object is double-clicked */ function onDoubleClick(properties) { for (var i = 0; i < properties.nodes.length; i++) { network.focus(properties.nodes[i], {scale:1}); } onSelect(properties); } /** * Manage the event when an object is selected */ function onSelect(properties) { if (properties.nodes.length > 0) { onNodeSelect(properties.nodes); } else { var content = "No selection" $("#selectionInfo").html(content); $('#monkey-config').hide() $('#btnConfigLoad, #btnConfigUpdate').hide(); $('#monkey-enabled').hide(); telemTable.clear(); telemTable.draw(); } if (properties.edges.length > 0) { onEdgeSelect(properties.edges); } } /** * Manage the event when a node is selected */ function onNodeSelect(nodeId) { var monkey = getMonkey(nodeId); var htmlContent = ""; if (monkey) { htmlContent = buildMonkeyDescription(monkey); $("#monkeySearch").val(monkey.hostname); } $("#selectionInfo").html(htmlContent); $('#monkey-config').show() $('#btnConfigLoad, #btnConfigUpdate').show(); loadMonkeyConfig(); if (monkey.config.alive) { $("[name='chboxMonkeyEnabled']").bootstrapSwitch('state', true); } else { $("[name='chboxMonkeyEnabled']").bootstrapSwitch('state', false); } $('#monkey-enabled').show(); $.getJSON('/api/telemetry?monkey_guid=' + monkey.guid, function(json) { telemTable.clear(); var telemetries = json.objects; for (var i = 0; i < telemetries.length; i++) { telemTable.row.add([telemetries[i].timestamp, telemetries[i].telem_type, JSON.stringify(telemetries[i].data)]); } telemTable.draw(); }); network.selectNodes([nodeId]); } /** * Manage the event when an edge is selected */ function onEdgeSelect(edge) { var edge = getEdge(edge); } function toggleMonkeyEnabled(event, state) { if (event.type != "switchChange") { return; } if (state) { reviveMonkey(); } else { killMonkey(); } } function killMonkey() { var curr_config = monkeyCfg.getValue(); curr_config.alive = false; monkeyCfg.setValue(curr_config); updateMonkeyConfig(); } function reviveMonkey() { var curr_config = monkeyCfg.getValue(); curr_config.alive = true; monkeyCfg.setValue(curr_config); updateMonkeyConfig(); } function toggleFocusOnNode() { if (focusedOnNode) { network.zoomExtent({duration:0}); focusedOnNode = false; } else { selectNode(undefined, true); } } function loadNewMonkeysConfig() { $.getJSON('/api/config/new', function(json) { if (jQuery.isEmptyObject(json)) { newCfg.setValue({alive: true}); } else { if(undefined == json.alive) { json.alive = true; } delete json.id; newCfg.setValue(json); } }); } function updateNewMonkeysConfig() { var curr_config = newCfg.getValue() $.ajax({ headers : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' }, url : '/api/config/new', type : 'POST', data : JSON.stringify(curr_config), success : function(response, textStatus, jqXhr) { console.log("New monkeys config successfully updated!"); BootstrapDialog.show({ title: "Update New Monkeys Config", message: "New monkeys config successfully updated!" }); }, error : function(jqXHR, textStatus, errorThrown) { // log the error to the console console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Update New Monkeys Config", message: "The following error occured: " + textStatus }); }, complete : function() { console.log("Sending new monkeys config update..."); } }); } function loadMonkeyConfig() { var node = network.getSelectedNodes(); if(node.length != 1) { return; } var monkey = getMonkey(node[0]); monkeyCfg.setValue(monkey.config); } function updateMonkeyConfig() { var node = network.getSelectedNodes(); if(node.length != 1) { return; } var monkey = getMonkey(node[0]); var curr_config = monkeyCfg.getValue(); $.ajax({ headers : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' }, url : '/api/monkey/' + monkey.guid, type : 'PATCH', data : JSON.stringify({config: curr_config}), success : function(response, textStatus, jqXhr) { monkey.config = curr_config; console.log("Monkey config successfully updated! (" + monkey.hostname + ")"); selectNode(monkey.hostname, false); BootstrapDialog.show({ title: "Update Monkey Config", message: "Monkey config successfully updated! (" + monkey.hostname + ")" }); }, error : function(jqXHR, textStatus, errorThrown) { // log the error to the console console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Update Monkey Config", message: "The following error occured: " + textStatus }); }, complete : function() { console.log("Sending monkey config update..."); } }); } function selectNode(hostname, zoom) { if (hostname == undefined) { hostname = $("#monkeySearch").val(); } if (hostname == "") { return; } for (var i = 0; i < monkeys.length; i++) { var monkey = monkeys[i]; if (monkey.hostname == hostname) { onNodeSelect([monkey.id]); if (zoom) { network.focus(monkey.id, {scale:1}); focusedOnNode = true; } break; } } } function resetDB() { if (confirm('Are you sure you want to empty the database?')) { $.ajax({ headers : { 'Accept' : 'application/json', }, url : '/api?action=reset', type : 'GET', success : function(response, textStatus, jqXhr) { console.log("DB was successfully reset!"); location.reload(); }, error : function(jqXHR, textStatus, errorThrown) { // log the error to the console console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Reset DB", message: "The following error occured: " + textStatus }); }, complete : function() { console.log("Trying to reset DB..."); } }); } } /** * Get a monkey from its id */ function getMonkey(id) { for (var i = 0; i < monkeys.length; i++) { if (monkeys[i].id == id) { return monkeys[i]; } } } function getMonkeyByGuid(guid) { for (var i = 0; i < monkeys.length; i++) { if (monkeys[i].guid == guid) { return monkeys[i]; } } } function getMonkeyByIP(ip) { for (var i = 0; i < monkeys.length; i++) { var monkey = monkeys[i]; for (var j = 0; j< monkey.ip_addresses; j++) { if (monkeys[i].ip == ip) { return monkeys[i]; } } } return null; } function getScannedByIP(ip) { for (var i = 0; i < scannedMachines.length; i++) { var machine = scannedMachines[i]; if (machine.id == ip) { return machine } } return null; } function getMonkeyIndex(guid) { for (var i = 0; i < monkeys.length; i++) { if (monkeys[i].guid == guid) { return i; } } return -1; } /** * Get a node from its id */ function getNode(id) { for (var i = 0; i < nodes.length; i++) { if (nodes[i].id == id) { return nodes[i]; } } } /** * Get an edge from its id */ function getEdge(id) { for (var i = 0; i < edges.length; i++) { if (edges[i].id == id) { return edges[i]; } } } /** * Verifies whether a node already exist or not */ function nodeExists(id) { return getNode(id) != null; } /** * Verifies whether a link already exist or not */ function edgeExists(link) { for (var i = 0; i < edges.length; i++) { var from = edges[i].from; var to = edges[i].to; var type = edges[i].type; if (from == link[0] && to == link[1] && type == link[2]) { return true; } } } /** * Clears the value in the local storage */ function clear(key) { if (localStorage[key]) { delete localStorage[key]; } }; /** /.localStorage Section **/ /** **/ /** ----- **/ /** **/ /** Utilities Section **/ /** * Returns the differences between two arrays */ Array.prototype.diff = function(other) { var diff = []; for (var i = 0; i < this.length; i++) { var obj = this[i]; if (other.indexOf(obj) == -1) { diff.push(obj); } } for (var i = 0; i < other.length; i++) { var obj = other[i]; if (this.indexOf(obj) == -1 && diff.indexOf(obj) == -1) { diff.push(obj); } } return diff; }; /** /.Utilities Section **/ /** **/