This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit 2231aed98bbc6c0ce773fc60b475d49c64c5ff69 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 17:03:37 2015 +0100 code d'instruction websocket devenus textuels --- app/app.py | 38 +++++------------ app/module_loader.py | 45 ++++++++++++-------- app/modules/detection_modules/nmap_detection.py | 12 +++--- .../notification_modules/websocket_container.py | 2 +- app/modules/storage_modules/shelve_db.py | 48 +++++++++++++--------- static/js/controllers/headCtrl.js | 18 ++++---- static/js/controllers/hostPageCtrl.js | 48 +++++++++++++++++++--- static/js/controllers/scanCtrl.js | 2 +- views/hostpage.html | 26 +++--------- 9 files changed, 132 insertions(+), 107 deletions(-) diff --git a/app/app.py b/app/app.py index 2d6d636..eeb595d 100755 --- a/app/app.py +++ b/app/app.py @@ -11,23 +11,6 @@ from module_loader import ModuleLoader import process_monitoring from modules.notification_modules.websocket_container import WebSocketContainer -NMAP_SCAN_DEMAND = "10" -DETECTION_DEMAND = "11" -MONITORING_DEMAND = "12" -HOST_INFO_DEMAND = "13" -GET_HOSTS_DEMAND = "14" -CALL_FUNC_DB = "15" - -SUCCESS_MODULE = "20" -INFO_HOST = "21" -GET_HOSTS_RESPONSE = "22" -RES_CALL_FUNC_DB = "23" - -CURRENT_STATE_INFO = "30" -BROWSER_NOTIFICATION = "31" - -ERROR = "40" - wsc = None ml = None @@ -46,7 +29,7 @@ class ThreadDetect(threading.Thread): self.ml.get_conection_modules_list(), self.ml.get_info_mod_monitoring()) if scanned_ip is not None: - self.ws.send(json.dumps({SUCCESS_MODULE: scanned_ip})) + self.ws.send(json.dumps({"SUCCESS_MODULE": scanned_ip})) for ip in json.loads(scanned_ip): monitoring_intructions = db.get_monitoring_instructions(ip) for instr in monitoring_intructions: @@ -142,18 +125,19 @@ def receive(ws): if response is not None: msg = json.loads(response) for code in msg: - if code == NMAP_SCAN_DEMAND: - start_first_detection(msg[NMAP_SCAN_DEMAND], ml, ws) - elif code == GET_HOSTS_DEMAND: + if code == "NMAP_SCAN_DEMAND": + start_first_detection(msg["NMAP_SCAN_DEMAND"], ml, ws) + elif code == "GET_HOSTS": db = ml.get_db() - ws.send(json.dumps({GET_HOSTS_RESPONSE: db.get_hosts()})) - elif code == HOST_INFO_DEMAND: + ws.send(json.dumps({"RES_GET_HOSTS": db.get_hosts()})) + elif code == "GET_HOST_INFO": db = ml.get_db() - ws.send(json.dumps({INFO_HOST: db.get_host_informations(msg[HOST_INFO_DEMAND])})) - elif code == CALL_FUNC_DB: - res = ml.launch_db_function(msg[CALL_FUNC_DB]) + ws.send(json.dumps({"RES_INFO_HOST": db.get_host_informations(msg["GET_HOST_INFO"])})) + elif code == "CALL_FUNC_DB": + res = ml.launch_db_function(msg["CALL_FUNC_DB"]) if res is not None: - ws.send(json.dumps({RES_CALL_FUNC_DB: res})) + print res + ws.send(json.dumps({"RES_CALL_FUNC_DB": res})) else: print 'res is None' else: diff --git a/app/module_loader.py b/app/module_loader.py index 92bf62b..57ae88b 100644 --- a/app/module_loader.py +++ b/app/module_loader.py @@ -66,7 +66,7 @@ class ModuleLoader: return ip_range except modules.HostNotFoundException.HostNotFoundException as hnfe: print hnfe.__str__() - ws.send(json.dumps({"40": hnfe.__str__()})) + ws.send(json.dumps({"ERROR": hnfe.__str__()})) return None def run_all_detection_modules(self, os, conn, db, ws): @@ -88,7 +88,7 @@ class ModuleLoader: except modules.CommandNotFoundException.CommandNotFoundException as cnfe: print cnfe.__str__() if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__()})) + ws.send(json.dumps({"ERROR": cnfe.__str__()})) def load_all_monitoring_modules(self): """ @@ -163,13 +163,13 @@ class ModuleLoader: def get_info_mod_monitoring(self): """ Get information about the output, block, compatible os and class name of the monitoring modules. - These informations must be specified on each modules, and are loaded at the launch of the application with - the + These informations must be specified on each modules, and must be loaded at the launch of the application. :return: a dictionary containing these informations on the form : { mod_name: { 'class_name': val, => the name of the class to instanciate + 'imported': module => the module imported 'compatible_os': [val1, val2, ...], => a list containing the compatibles os 'unit': val, => the unit type of return ('%', 'bool' or other) 'block': val, => the monitoring block of the module @@ -182,25 +182,36 @@ class ModuleLoader: def load_all_connection_modules(self): """ Instanciates and stores the informations about each connection modules avaliable - on the loaded_mod_conn attribute + on the loaded_mod_conn attribute. """ for importer, mod_name, ispkg in pkgutil.iter_modules(["app/modules/connection_modules/"]): if mod_name not in sys.modules: - loaded_mod = __import__("modules.connection_modules." + mod_name, fromlist=[mod_name]) - class_name = getattr(loaded_mod, "get_class_name")() - mod_inst = getattr(loaded_mod, class_name)(None, None, None) - infos_mod = {} - infos_mod['imported'] = loaded_mod - infos_mod['class_name'] = getattr(mod_inst, 'get_name')() - infos_mod['params'] = getattr(mod_inst, 'get_parameters')() - self.loaded_mod_conn[mod_name] = infos_mod + try: + loaded_mod = __import__("modules.connection_modules." + mod_name, fromlist=[mod_name]) + class_name = getattr(loaded_mod, "get_class_name")() + mod_inst = getattr(loaded_mod, class_name)(None, None, None) + infos_mod = {} + infos_mod['imported'] = loaded_mod + infos_mod['class_name'] = getattr(mod_inst, 'get_name')() + infos_mod['params'] = getattr(mod_inst, 'get_parameters')() + self.loaded_mod_conn[mod_name] = infos_mod + except AttributeError: + print "Error : internal connection module " + mod_name + " could not have been loaded. " def get_conection_modules_list(self): """ - Get a list containing the names of the different connection modules declared on the __init__.py file - of the connection_modules package. - :return: a list containing the names of the different connection modules declared on the __init__.py file - of the connection_modules package. + Get informations about of the connection modules loaded and their parameters necessary to instanciate the + connection. The type of the parameters is necessary for the web application in order to show a corresponding + form (can be 'string' for a textfield, 'int' for a number field, 'file' for a file location). + :return: a dictionary containing these informations on the form : + { + mod_name: + { + 'class_name': val, => the name of the class to instanciate + 'imported': module, => the module imported + 'params': {param1: type1, param2: type2, ...} => the parameters necessary to create the connection + } + } """ return self.loaded_mod_conn diff --git a/app/modules/detection_modules/nmap_detection.py b/app/modules/detection_modules/nmap_detection.py index 80216c9..1d6d84c 100644 --- a/app/modules/detection_modules/nmap_detection.py +++ b/app/modules/detection_modules/nmap_detection.py @@ -86,7 +86,7 @@ class nmap_detection: # launch the nmap detection for the IP adress represented by the 4 bytes in parameters def launch_detection(self, byte_1, byte_2, byte_3, byte_4): ip = str(byte_1) + '.' + str(byte_2) + '.' + str(byte_3) + '.' + str(byte_4) - self.ws.send(json.dumps({"30": "Scanning ip : " + ip})) + self.ws.send(json.dumps({"CURRENT_STATE_INFO": "Scanning ip : " + ip})) try: child = pexpect.spawn('nmap ' + self.opt + ' ' + ip + ' -oX ' + self.filename) while child.isalive(): @@ -97,12 +97,12 @@ class nmap_detection: #except: # self.ws.send(json.dumps({"40": "Database error"})) except pexpect.TIMEOUT: - self.ws.send(json.dumps({"40": "Timeout on nmap execution"})) + self.ws.send(json.dumps({"ERROR": "Timeout on nmap execution"})) except pexpect.ExceptionPexpect: - self.ws.send(json.dumps({"40": "nmap command not avaliable on server"})) + self.ws.send(json.dumps({"ERROR": "nmap command not avaliable on server"})) def launch_detection_with_hostname(self, hostname): - self.ws.send(json.dumps({"30": "Scanning host : " + hostname})) + self.ws.send(json.dumps({"CURRENT_STATE_INFO": "Scanning host : " + hostname})) try: child = pexpect.spawn('nmap ' + self.opt + ' ' + hostname + ' -oX ' + self.filename) while child.isalive(): @@ -114,9 +114,9 @@ class nmap_detection: #except: # self.ws.send(json.dumps({"40": "Database error"})) except pexpect.TIMEOUT: - self.ws.send(json.dumps({"40": "Timeout on nmap execution"})) + self.ws.send(json.dumps({"ERROR": "Timeout on nmap execution"})) except pexpect.ExceptionPexpect: - self.ws.send(json.dumps({"40": "nmap command not avaliable on server"})) + self.ws.send(json.dumps({"ERROR": "nmap command not avaliable on server"})) # parse the xml result to keep only interesting values # save directly it on the database diff --git a/app/modules/notification_modules/websocket_container.py b/app/modules/notification_modules/websocket_container.py index 15c5c04..28dce07 100644 --- a/app/modules/notification_modules/websocket_container.py +++ b/app/modules/notification_modules/websocket_container.py @@ -16,4 +16,4 @@ class WebSocketContainer: def notify_state_change(self): for ws in self.ws_set: - ws.send(json.dumps({"22": self.db.get_hosts()})) \ No newline at end of file + ws.send(json.dumps({"RES_HOST_DEMAND": self.db.get_hosts()})) \ No newline at end of file diff --git a/app/modules/storage_modules/shelve_db.py b/app/modules/storage_modules/shelve_db.py index 1f739b6..cb1f914 100644 --- a/app/modules/storage_modules/shelve_db.py +++ b/app/modules/storage_modules/shelve_db.py @@ -62,10 +62,11 @@ class shelve_db: self.db["hosts"][addr_host]["detected"]["nmap"] = nmap_res # Preconfiguration self.db["hosts"][addr_host]["conf"] = {} - self.db["hosts"][addr_host]["conf"]["connections"] = self.init_conn(json.loads(nmap_res), list_mod_conn) - os_host = json.loads(nmap_res)['os'] + nmap_res_data = json.loads(nmap_res) + self.db["hosts"][addr_host]["conf"]["connections"] = self.init_conn(nmap_res_data, list_mod_conn) self.db["hosts"][addr_host]["conf"]["monitoring"] = self.generate_global_conf(dict_mod_info, - addr_host, os_host) + addr_host, + nmap_res_data['os']) self.db["hosts"][addr_host]["conf"]["groups"] = ["all"] # Every host is in group "all" self.db["hosts"][addr_host]["conf"]["subscribers"] = {} # Add current user automatically ? self.db["hosts"][addr_host]["conf"]["custom_info"] = "" @@ -80,29 +81,27 @@ class shelve_db: self.close_db() @staticmethod - def init_conn(dict_nmap_res, conn_list): + def init_conn(dict_nmap_res, conn_infos): """ Returns an initialization for the connection configuration on a host. - :param dict_nmap_res: The result of the nmap detection formatted to datastructures. - :param conn_list: A list of all connection modules avaliable + :param dict_nmap_res: The result of the nmap detection in dictionnary form + :param conn_infos: A dictionnary containing informations about connection modules in the form : + { + mod_name: { + 'params': {param1: type1, param2: type2, ...} + } + } :return: """ dict_conn = {} - cpt = 1 for port in dict_nmap_res['openports']: - if port["portname"] in conn_list: - dict_conn[port["portname"]] = { - "priority": cpt, - "portid": int(port["portid"]) - } - cpt += 1 - else: + if port["portname"] in conn_infos: dict_conn[port["portname"]] = { "priority": 0, - "portid": None + "portid": int(port["portid"]) } - dict_conn[port["portname"]]["login"] = None - dict_conn[port["portname"]]["key_couple"] = None + for param in conn_infos[port["portname"]]['params']: + dict_conn[port["portname"]][param] = None return dict_conn def generate_global_conf(self, dict_mod_info, addr_host, os_host): @@ -167,14 +166,23 @@ class shelve_db: res['ping'] = ping_conf return res - def get_conn_param(self, addr_host): + def get_conn_param(self, args): + """ + Returns the connection parameters of an host. + :param args: A dictionnary containing : + {'addr_host': val} + :return: The connection parameters in the form: + mod_name: { + {param1: val1, param2: val2, ...} + } + """ self.open_db() res = None try: - res = self.db['hosts'][addr_host]['conf']['connections'] + res = self.db['hosts'][args['addr_host']]['conf']['connections'] finally: self.close_db() - return res + return json.dumps(res) def get_monitoring_instructions(self, addr_host): """ diff --git a/static/js/controllers/headCtrl.js b/static/js/controllers/headCtrl.js index 1a1e748..e8aeb8d 100644 --- a/static/js/controllers/headCtrl.js +++ b/static/js/controllers/headCtrl.js @@ -13,7 +13,7 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r var ws = new WebSocket("ws://" + $location.host() + ":1337/websocket"); ws.onopen = function() { - var request = '{"14" : ""}'; + var request = JSON.stringify({"GET_HOSTS": ""}); ws.send(request); }; @@ -25,24 +25,24 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r ws.onmessage = function (evt) { // actions effectuees lors de la reception d'un message via la websocket JSON.parse(evt.data, function (key, value) { - switch(parseInt(key)){ - case 20: // Success of a module execution + switch(key){ + case "SUCCESS_MODULE": // Success of a module execution $rootScope.$broadcast("success", value); toastr.success(value, "Success on module execution"); - case 21: // Informations concerning one host + case "RES_INFO_HOST": // Informations concerning one host $rootScope.$broadcast("hostInfos", JSON.parse(value)); break; - case 22: // List of hosts under monitoring + case "RES_GET_HOSTS": // List of hosts under monitoring DataHosts.Items = JSON.parse(value); $rootScope.$broadcast("hostsUpdate"); $scope.$apply(function(){ $scope.items = DataHosts.Items; }); break; - case 23: // Get a result after calling a funcion on the db + case "RES_CALL_FUNC_DB": // Get a result after calling a funcion on the db $rootScope.$broadcast("resCall", JSON.parse(value)); break; - case 30: + case "CURRENT_STATE_INFO": $scope.$apply(function(){ $scope.state = value; }); @@ -53,7 +53,7 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r $scope.state = value });*/ break; - case 31: + case "BROWSER_NOTIFICATION": params = value.split(','); if(params[0]=='success'){ $scope.pop_success("Success on " + params[1], params[2]); @@ -65,7 +65,7 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r $scope.pop_danger("Danger on "+ params[1], params[2]); } break; - case 40: + case "ERROR": toastr.error(value, "Server error"); break; default: diff --git a/static/js/controllers/hostPageCtrl.js b/static/js/controllers/hostPageCtrl.js index 5ad0fa2..0c915fd 100644 --- a/static/js/controllers/hostPageCtrl.js +++ b/static/js/controllers/hostPageCtrl.js @@ -3,7 +3,7 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo $scope.addr_host = $routeParams.param // asks for host informations - $rootScope.$broadcast("sendViaWs", JSON.stringify({"13": $routeParams.param})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"GET_HOST_INFO": $routeParams.param})); $scope.items = [];/* result of get_host_informations => { @@ -52,7 +52,7 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo var args = {}; args.addr_host = $scope.addr_host; args.txt = $scope.model.custom_infos; - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'update_custom_informations', 'args': args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'update_custom_informations', 'args': args}})); }; // creation of modals @@ -79,6 +79,18 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo } }); }; + + $scope.open_modal_conn = function () { + var modalInstance = $modal.open({ + templateUrl: 'modal_conn_label.html', + controller: 'ModalConnInstanceCtrl', + resolve: { + conn_args: function(){ + return {'addr_host' : $scope.addr_host}; + } + } + }); + }; }); // modals controllers @@ -86,7 +98,7 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalInstance, conf_args) { $scope.conf_args = conf_args; // {'addr_host' : val, 'mod_name', val} - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'get_conf_mod', 'args': conf_args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'get_conf_mod', 'args': conf_args}})); $scope.items = {} /* { 'unit' : val, // the unit of the value @@ -146,7 +158,7 @@ mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalI args.minor_limit = $scope.minor_limit_unit; args.major_limit = $scope.major_limit_unit; } - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'set_conf_mod', 'args': args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'set_conf_mod', 'args': args}})); $modalInstance.close(); }; @@ -170,7 +182,33 @@ mumApp.controller('ModalIntervInstanceCtrl', function ($scope, $rootScope, $moda args.date = $scope.date; args.details = $scope.details; - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'add_intervention', 'args': args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'add_intervention', 'args': args}})); + + $modalInstance.close(); + }; + + $scope.cancel = function () { + $modalInstance.close(); + }; +}); + +mumApp.controller('ModalConnInstanceCtrl', function ($scope, $rootScope, $modalInstance, conn_args) { + $scope.conn_args = conn_args; // {'addr_host' : val} + + $scope.current_config = {}; + + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'get_conn_param','args': {'addr_host': $scope.conn_args['addr_host']}}})); + + // when the configuration of the connection is received + $scope.$on("resCall", function (event, args) { + $scope.$apply(function(){ + $scope.current_config = args; + }); + }); + + $scope.ok = function () { + var args = {}; + $modalInstance.close(); }; diff --git a/static/js/controllers/scanCtrl.js b/static/js/controllers/scanCtrl.js index 43d810b..7c2b0ce 100644 --- a/static/js/controllers/scanCtrl.js +++ b/static/js/controllers/scanCtrl.js @@ -24,6 +24,6 @@ mumApp.controller('scanCtrl', function($scope, $rootScope) { var args = {}; args.ip_range = $scope.ip_range; args.nmap_options = $scope.nmap_options; - $rootScope.$broadcast("sendViaWs", JSON.stringify({"10": args})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"NMAP_SCAN_DEMAND": args})); }; }); \ No newline at end of file diff --git a/views/hostpage.html b/views/hostpage.html index 6010696..6a24b18 100644 --- a/views/hostpage.html +++ b/views/hostpage.html @@ -2,7 +2,7 @@ <div class="col-md-offset-2 main"> <h1 class="page-header">Current state of {{addr_host}} <small>{{items.hostname}}</small></h1> <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#modal_block">Activate/Deactivate</button> - <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#modal_conn">Connection settings</button> + <button type="button" class="btn btn-primary btn-xs" ng-click="open_modal_conn()">Connection settings</button> <button type="button" class="btn btn-info btn-xs">Launch a new detection</button> <button type="button" class="btn btn-danger btn-xs" ng-click="call_func('remove_host', [addr_host])">Remove this host</button> <table class="table table-condensed table-hover"> @@ -146,6 +146,7 @@ <h3 class="modal-title">Connection configuration</h3> </div> <div class="modal-body"> + {{current_config}} <form> <div class="form-group"> <h3>Choose the priority of each avaliable connection</h3> @@ -158,32 +159,15 @@ </tr> </thead> <tbody> - <tr> - <td>SSH</td> - <td><input type="number" min="0" placeholder=1></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - - </tr> - <tr> - <td>SNMP</td> - <td><input type="number" min="0" placeholder=0 disabled></td> + <tr ng-repeat="(modname, modconf) in current_config"> + <td>{{modname}}</td> + <td><input type="number" min="0" ng-model="prio_{{modname}}"></td> <td> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> <button type="button" class="btn btn-success">Test</button> </td> </tr> - <tr> - <td>Nagios</td> - <td><input type="number" min="0" placeholder=0 disabled></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - </tr> </tbody> </table> </div> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.