def list_backups_for_server(self, server_id): # Grab our backup path from the DB backup_list = Backups.get(Backups.server_id == int(server_id)) # Join into a full path backup_folder = self.get_backup_folder_for_server(server_id) server_backup_dir = os.path.join(backup_list.storage_location, backup_folder) #helper.ensure_dir_exists(server_backup_dir) svr_obj = multi.get_server_obj(server_id) return svr_obj.list_backups()
def post(self): token = self.get_argument('token') user = self.authenticate_user(token) if user is None: self.access_denied('unknown') if not check_role_permission( user, 'api_access') and not check_role_permission( user, 'svr_control'): self.access_denied(user) server_id = self.get_argument('id') server = multi.get_server_obj(server_id) server.restart_threaded_server() self.return_response(200, {}, {'code': 'SER_RESTART_CALLED'}, {})
def post(self): token = self.get_argument('token') user = self.authenticate_user(token) if user is None: self.access_denied('unknown') if not check_role_permission( user, 'api_access') and not check_role_permission( user, 'backups'): self.access_denied(user) server_id = self.get_argument('id') server = multi.get_server_obj(server_id) backup_thread = threading.Thread(name='backup', target=server.backup_server, daemon=False) backup_thread.start() self.return_response(200, {}, {'code': 'SER_BAK_CALLED'}, {})
def do_start(self, line): if line == '': self.help_start() return 0 try: int(line) except ValueError: console.error("Server ID must be a number") self.help_start() return 0 try: server = MC_settings.get_by_id(line) except Exception as e: console.help("Unable to find a server with that ID: {}".format(e)) return 0 server = int(line) if helper.is_setup_complete(): srv_obj = multi.get_server_obj(server) if srv_obj.check_running(): console.warning("Server already running") else: console.info("Starting Minecraft Server in background") Remote.insert({ Remote.command: 'start_mc_server', Remote.server_id: server, Remote.command_source: "localhost" }).execute() else: console.warning( "Unable to start server, please complete setup in the web GUI first" )
def do_stop(self, line): if line == '': self.help_stop() return 0 try: int(line) except ValueError: console.error("Server ID must be a number") self.help_stop() return 0 try: server = MC_settings.get_by_id(line) except Exception as e: console.help("Unable to find a server with that ID: {}".format(e)) return 0 server = int(line) if helper.is_setup_complete(): srv_obj = multi.get_server_obj(server) if not srv_obj.check_running(): console.warning("Server already stopped") else: console.info("Stopping Minecraft Server") multi.stop_server(server) ''' Remote.insert({ Remote.command: 'stop_mc_server' }).execute() ''' else: console.warning( "Unable to stop server, please complete setup in the web GUI first" )
def post(self): token = self.get_argument('token') user = self.authenticate_user(token) if user is None: self.access_denied('unknown') if not check_role_permission( user, 'api_access') and not check_role_permission( user, 'svr_control'): self.access_denied(user) command = self.get_body_argument('command', default=None, strip=True) server_id = self.get_argument('id') if command: server = multi.get_server_obj(server_id) if server.check_running: server.send_command(command) self.return_response(200, '', {"run": True}, '') else: self.return_response(200, {'error': 'SER_NOT_RUNNING'}, {}, {}) else: self.return_response(200, {'error': 'NO_COMMAND'}, {}, {})
def post(self): token = self.get_argument('token') user = self.authenticate_user(token) if user is None: self.access_denied('unknown') if not check_role_permission( user, 'api_access') and not check_role_permission( user, 'svr_control'): self.access_denied(user) server_id = self.get_argument('id') server = multi.get_server_obj(server_id) if not server.check_running(): Remote.insert({ Remote.command: 'start_mc_server', Remote.server_id: server_id, Remote.command_source: "localhost" }).execute() self.return_response(200, {}, {'code': 'SER_START_CALLED'}, {}) else: self.return_response(500, {'error': 'SER_RUNNING'}, {}, {})
def get(self): token = self.get_argument('token') user = self.authenticate_user(token) if user is None: self.access_denied('unknown') if not check_role_permission( user, 'api_access') and not check_role_permission( user, 'logs'): self.access_denied(user) server_id = self.get_argument('id') server = multi.get_server_obj(server_id) logfile = os.path.join(server.server_path, 'logs', 'latest.log') data = helper.search_file(logfile, '') line_list = [] if data: for line in data: line_list.append({'line_num': line[0], 'message': line[1]}) self.return_response(200, {}, line_list, {})
def do_revert_server_jar(self, line): if line == '': self.help_update_server_jar() return 0 try: int(line) except ValueError: console.error("Server ID must be a number") self.help_update_server_jar() return 0 try: server = MC_settings.get_by_id(line) except Exception as e: console.help("Unable to find a server with that ID: {}".format(e)) return 0 server = int(line) if helper.is_setup_complete(): srv_obj = multi.get_server_obj(server) console.info("Reverting updated Server Jar in background") Remote.insert({ Remote.command: 'revert_server_jar_console', Remote.server_id: server, Remote.command_source: "localhost" }).execute() else: console.warning( "Unable to update server jar, please complete setup in the web GUI first" )
def backup_all_servers(self): logger.warning( "All server backup called. This may load your server massively!") # List all servers servers = multi.list_servers() # Iterate over them for server in servers: server_id = server['id'] # Grab the server object server_obj = multi.get_server_obj(server_id) # Start the backup thread logger.info("Backing up server %s", server_id) backup_thread = threading.Thread( name='backup_server_{}'.format(server_id), target=server_obj.backup_server, daemon=False) backup_thread.start() logger.info("Backup thread running for server %s", server_id) # Slow down the process creation for older systems sleep(1)
def handle_command(self, command, server_id): if command == "exit_crafty": logger.info("Sending Stop Command To Crafty") # stop the ftp server... if ftp_svr_object.check_running(): ftp_svr_object.stop_threaded_ftp_server() # kill all mc servers gracefully try: multi.stop_all_servers() except: pass logger.info("***** Crafty Stopped ***** \n") webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, {"code": "CWEB_STOP"}, {"info": "Crafty is shutting down"})) os._exit(0) srv_obj = multi.get_server_obj(server_id) running = srv_obj.check_running() server_name = srv_obj.get_mc_server_name() if command == 'restart_web_server': self.tornado_obj.stop_web_server() time.sleep(1) self.tornado_obj.start_web_server(True) webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, {"code": "WEBSRV_RESTART"}, {"info": "Crafty Web Interface action has completed"})) self.clear_all_commands() elif command == "reload_mc_settings": any_srv_obj = multi.get_first_server_object() any_srv_obj.reload_settings() elif command == 'restart_mc_server': if running: try: logger.info("Stopping MC Server") srv_obj.stop_threaded_server() except: logger.exception("Unable to stop server %s. Traceback: ", server_name) webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter(500, { "error": "TRACEBACK" }, { "server": { "id": server_id, "name": server_name, "running": running } }, { "info": "A Traceback occured while restarting the MC server" })) while True: server_up = srv_obj.is_server_pingable() if server_up: logger.info("%s still pingable, waiting...", server_name) time.sleep(.5) else: logger.info("Server %s has stopped", server_name) break srv_obj.run_threaded_server() else: logger.info("%s not running, starting it now", server_name) srv_obj.run_threaded_server() webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, { "code": "SER_RESTART_DONE", "server": { "id": server_id, "name": server_name, "running": running } }, {"info": "Server restart action has completed"})) elif command == 'start_mc_server': srv_obj.run_threaded_server() time.sleep(2) multi.do_stats_for_servers() webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, { "code": "SER_START_DONE", "server": { "id": server_id, "name": server_name, "running": running } }, {"info": "Server start action has completed"})) elif command == 'stop_mc_server': if running: logger.info("Stopping MC server %s", server_name) srv_obj.stop_threaded_server() time.sleep(2) multi.do_stats_for_servers() webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, { "code": "SER_STOP_DONE", "server": { "id": server_id, "name": server_name, "running": running } }, {"info": "Server stop action has completed"})) else: logger.info("Stop halted! Server %s is not running!", server_name) webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 500, {"error": "SER_NOT_RUNNING"}, { "server": { "id": server_id, "name": server_name, "running": running } }, {"info": "Server is not running"})) elif command == 'update_server_jar': srv_obj.update_server_jar(False) elif command == 'revert_server_jar': srv_obj.revert_updated_server_jar(False) elif command == 'update_server_jar_console': srv_obj.update_server_jar(True) elif command == 'revert_server_jar_console': srv_obj.revert_updated_server_jar(True) elif command == "exit_crafty": logger.info("Sending Stop Command To Crafty") # stop the ftp server... if ftp_svr_object.check_running(): ftp_svr_object.stop_threaded_ftp_server() # kill all mc servers gracefully multi.stop_all_servers() logger.info("***** Crafty Stopped ***** \n") webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, {"code": "CWEB_STOP"}, {"info": "Crafty is shutting down"})) os._exit(0) elif command == 'start_ftp': settings = MC_settings.get_by_id(server_id) if ftp_svr_object.check_running(): logger.warning( "The FTP server is already running - please stop it before starting again" ) webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 500, {"error": "FTP_RUNNING"}, {}, {"info": "FTP is already running"})) return False if helper.check_directory_exist(settings.server_path): logger.info("Setting FTP root path to {}".format( settings.server_path)) ftp_svr_object.set_root_dir(settings.server_path) else: logger.error("Path: {} not found!".format( settings.server_path)) webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {"error": "PATH_NONEXISTANT"}, {"path": settings.server_path}, {"info": "Home path for FTP server not found"})) return False logger.info("Starting FTP Server") ftp_svr_object.run_threaded_ftp_server(server_id) webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, {}, {"info": "FTP server successfully started"})) elif command == 'stop_ftp': ftp_svr_object.stop_threaded_ftp_server() webhookmgr.run_command_webhooks( command, webhookmgr.payload_formatter( 200, {}, {}, {"info": "FTP server successfully stopped"})) elif command == 'destroy_world': logger.info("Destroying World for Server: {} - {}".format( server_id, server_name)) srv_obj.destroy_world()
def get(self, page): name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = { 'user_data': user_data, 'version_data': helper.get_version(), 'servers_defined': multi.list_servers(), 'managed_server': self.session.get_data(self.current_user, 'managed_server'), 'servers_running': multi.list_running_servers(), 'mc_servers_data': multi.get_stats_for_servers() } if page == 'unauthorized': template = "admin/denied.html" elif page == "reload_web": template = "admin/reload_web_settings.html" web_data = Webserver.get() context['user_data'] = user_data context['web_settings'] = model_to_dict(web_data) self.render(template, data=context) # reload web server Remote.insert({ Remote.command: 'restart_web_server', Remote.server_id: 1, # this doesn't really matter as we are not tying to a server Remote.command_source: 'local' }).execute() elif page == 'reload_mc_settings': Remote.insert({ Remote.command: 'reload_mc_settings', Remote.server_id: 1, # this doesn't really matter as we are not tying to a server Remote.command_source: 'local' }).execute() self.redirect("/admin/config") elif page == 'dashboard': errors = bleach.clean(self.get_argument('errors', '')) context['errors'] = errors context['host_stats'] = multi.get_host_status() template = "admin/dashboard.html" elif page == 'change_password': template = "admin/change_pass.html" elif page == 'virtual_console': if not check_role_permission(user_data['username'], 'svr_console'): self.redirect('/admin/unauthorized') context['server_id'] = bleach.clean(self.get_argument('id', '')) mc_data = MC_settings.get_by_id(context['server_id']) context['server_name'] = mc_data.server_name template = "admin/virt_console.html" elif page == "backups": if not check_role_permission(user_data['username'], 'backups'): self.redirect('/admin/unauthorized') server_id = bleach.clean(self.get_argument('id', '')) mc_data = MC_settings.get_by_id(server_id) template = "admin/backups.html" backup_data = Backups.get_by_id(server_id) backup_data = model_to_dict(backup_data) backup_path = backup_data['storage_location'] backup_dirs = json.loads(backup_data['directories']) context['backup_data'] = json.loads(backup_data['directories']) context['backup_config'] = backup_data # get a listing of directories in the server path. context['directories'] = helper.scan_dirs_in_path( mc_data.server_path) context['server_root'] = mc_data.server_path context['server_name'] = mc_data.server_name context['server_id'] = mc_data.id context['backup_paths'] = backup_dirs context['backup_path'] = backup_path context['current_backups'] = backupmgr.list_backups_for_server( server_id) context['saved'] = False context['invalid'] = False elif page == "all_backups": if not check_role_permission(user_data['username'], 'backups'): self.redirect('/admin/unauthorized') template = "admin/backups.html" # END backup_list = Backups.get() backup_data = model_to_dict(backup_list) backup_path = backup_data['storage_location'] backup_dirs = json.loads(backup_data['directories']) context['backup_paths'] = backup_dirs context['backup_path'] = backup_path context['current_backups'] = backupmgr.list_all_backups() context['server_name'] = "All Servers" elif page == "schedules": if not check_role_permission(user_data['username'], 'schedules'): self.redirect('/admin/unauthorized') saved = bleach.clean(self.get_argument('saved', '')) server_id = int(bleach.clean(self.get_argument('id', 1))) db_data = Schedules.select().where( Schedules.server_id == server_id) template = "admin/schedules.html" context['db_data'] = db_data context['saved'] = saved context['server_id'] = server_id elif page == "schedule_disable": if not check_role_permission(user_data['username'], 'schedules'): self.redirect('/admin/unauthorized') schedule_id = self.get_argument('taskid', 1) server_id = self.get_argument('id', 1) q = Schedules.update(enabled=0).where(Schedules.id == schedule_id) q.execute() self._reload_schedules() self.redirect("/admin/schedules?id={}".format(server_id)) elif page == "schedule_enable": if not check_role_permission(user_data['username'], 'schedules'): self.redirect('/admin/unauthorized') schedule_id = self.get_argument('taskid', 1) server_id = self.get_argument('id', 1) q = Schedules.update(enabled=1).where(Schedules.id == schedule_id) q.execute() self._reload_schedules() self.redirect("/admin/schedules?id={}".format(server_id)) elif page == 'config': if not check_role_permission(user_data['username'], 'config'): self.redirect('/admin/unauthorized') saved = bleach.clean(self.get_argument('saved', '')) invalid = bleach.clean(self.get_argument('invalid', '')) template = "admin/config.html" crafty_data = Crafty_settings.get() # ftp_data = Ftp_Srv.get() web_data = Webserver.get() users = Users.select() roles = Roles.select() # context['ftp_user'] = ftp_data.user # context['ftp_pass'] = ftp_data.password # context['ftp_port'] = ftp_data.port context['saved'] = saved context['invalid'] = invalid context['crafty_settings'] = model_to_dict(crafty_data) context['web_settings'] = model_to_dict(web_data) context['users'] = users context['users_count'] = len(users) context['roles'] = roles elif page == 'server_config': if not check_role_permission(user_data['username'], 'config'): self.redirect('/admin/unauthorized') saved = bleach.clean(self.get_argument('saved', '')) invalid = bleach.clean(self.get_argument('invalid', '')) server_id = bleach.clean(self.get_argument('id', 1)) errors = bleach.clean(self.get_argument('errors', '')) context['errors'] = errors if server_id is None: self.redirect("/admin/dashboard") template = "admin/server_config.html" mc_data = MC_settings.get_by_id(server_id) page_data = {} context['saved'] = saved context['invalid'] = invalid context['mc_settings'] = model_to_dict(mc_data) context['server_root'] = context['mc_settings']['server_path'] srv_obj = multi.get_server_obj(server_id) context['server_running'] = srv_obj.check_running() host_data = Host_Stats.get() context['max_memory'] = host_data.mem_total elif page == 'downloadbackup': if not check_role_permission(user_data['username'], 'backups'): self.redirect('/admin/unauthorized') path = bleach.clean(self.get_argument("file", None, True)) server_id = bleach.clean(self.get_argument("id", None, True)) # only allow zip files if path[-3:] != "zip": self.redirect("/admin/backups?id={}".format(server_id)) backup_folder = backupmgr.get_backup_folder_for_server(server_id) # Grab our backup path from the DB backup_list = Backups.get(Backups.server_id == int(server_id)) base_folder = backup_list.storage_location # get full path of our backups server_backup_folder = os.path.join(base_folder, backup_folder) server_backup_file = os.path.join(server_backup_folder, path) # get list of zip files in the backup directory files = [f for f in glob.glob(server_backup_folder + "**/*.zip")] # for each file, see if it matches the file we are trying to download for f in files: # if we find a match if f == server_backup_file and helper.check_file_exists( server_backup_file): file_name = os.path.basename(server_backup_file) self.set_header('Content-Type', 'application/octet-stream') self.set_header('Content-Disposition', 'attachment; filename=' + file_name) with open(server_backup_file, 'rb') as f: while 1: data = f.read( 16384) # or some other nice-sized chunk if not data: break self.write(data) self.finish() self.redirect("/admin/backups?id={}".format(server_id)) elif page == "server_control": if not check_role_permission(user_data['username'], 'svr_control'): self.redirect('/admin/unauthorized') server_id = bleach.clean(self.get_argument('id', 1)) if server_id is None: self.redirect("/admin/dashboard") template = "admin/server_control.html" logfile = helper.get_crafty_log_file() mc_data = MC_settings.get_by_id(server_id) srv_obj = multi.get_server_obj(server_id) context['server_running'] = srv_obj.check_running() context['mc_settings'] = model_to_dict(mc_data) context['server_updating'] = self.mcserver.check_updating() context['players'] = context['mc_servers_data'][int( server_id)]['players'].split(',') context['players_online'] = context['mc_servers_data'][int( server_id)]['online_players'] context['world_info'] = srv_obj.get_world_info() elif page == 'commands': if not check_role_permission(user_data['username'], 'svr_console'): self.redirect('/admin/unauthorized') command = bleach.clean(self.get_argument("command", None, True)) id = self.get_argument("id", None, True) # grab any defined server object and reload the settings any_serv_obj = multi.get_first_server_object() any_serv_obj.reload_settings() if command == "server_stop": Remote.insert({ Remote.command: 'stop_mc_server', Remote.server_id: id, Remote.command_source: "localhost" }).execute() next_page = "/admin/virtual_console?id={}".format(id) elif command == "server_start": Remote.insert({ Remote.command: 'start_mc_server', Remote.server_id: id, Remote.command_source: "localhost" }).execute() next_page = "/admin/virtual_console?id={}".format(id) elif command == "server_restart": Remote.insert({ Remote.command: 'restart_mc_server', Remote.server_id: id, Remote.command_source: "localhost" }).execute() next_page = "/admin/virtual_console?id={}".format(id) elif command == "ftp_server_start": Remote.insert({ Remote.command: 'start_ftp', Remote.server_id: id, Remote.command_source: 'localhost' }).execute() time.sleep(2) next_page = "/admin/files?id={}".format(id) elif command == 'ftp_server_stop': Remote.insert({ Remote.command: 'stop_ftp', Remote.server_id: id, Remote.command_source: 'localhost' }).execute() time.sleep(2) next_page = "/admin/files?id={}".format(id) elif command == "backup": backupmgr.backup_server(id) time.sleep(4) next_page = '/admin/backups?id={}'.format(id) elif command == "backup_all": backupmgr.backup_all_servers() time.sleep(4) next_page = '/admin/backups' elif command == 'update_jar': Remote.insert({ Remote.command: 'update_server_jar', Remote.server_id: id, Remote.command_source: 'localhost' }).execute() time.sleep(2) next_page = "/admin/server_control?id={}".format(id) elif command == 'revert_jar': Remote.insert({ Remote.command: 'revert_server_jar', Remote.server_id: id, Remote.command_source: 'localhost' }).execute() time.sleep(2) next_page = "/admin/server_control?id={}".format(id) elif command == 'destroy_world': Remote.insert({ Remote.command: 'destroy_world', Remote.server_id: id, Remote.command_source: "localhost" }).execute() next_page = "/admin/virtual_console?id={}".format(id) self.redirect(next_page) elif page == 'get_logs': if not check_role_permission(user_data['username'], 'logs'): self.redirect('/admin/unauthorized') server_id = bleach.clean(self.get_argument('id', None)) mc_data = MC_settings.get_by_id(server_id) context['server_name'] = mc_data.server_name context['server_id'] = server_id srv_object = multi.get_server_obj(server_id) data = [] server_log = os.path.join(mc_data.server_path, 'logs', 'latest.log') if server_log is not None: data = helper.tail_file(server_log, 500) data.insert(0, "Lines trimmed to ~500 lines for speed sake \n ") else: data.insert( 0, "Unable to find {} \n ".format( os.path.join(mc_data.server_path, 'logs', 'latest.log'))) crafty_data = helper.tail_file(helper.crafty_log_file, 100) crafty_data.insert( 0, "Lines trimmed to ~100 lines for speed sake \n ") scheduler_data = helper.tail_file( os.path.join(helper.logs_dir, 'schedule.log'), 100) scheduler_data.insert( 0, "Lines trimmed to ~100 lines for speed sake \n ") access_data = helper.tail_file( os.path.join(helper.logs_dir, 'tornado-access.log'), 100) access_data.insert( 0, "Lines trimmed to ~100 lines for speed sake \n ") ftp_data = helper.tail_file( os.path.join(helper.logs_dir, 'ftp.log'), 100) ftp_data.insert(0, "Lines trimmed to ~100 lines for speed sake \n ") errors = srv_object.search_for_errors() template = "admin/logs.html" context['log_data'] = data context['errors'] = errors context['crafty_log'] = crafty_data context['scheduler'] = scheduler_data context['access'] = access_data context['ftp'] = ftp_data elif page == "files": if not check_role_permission(user_data['username'], 'files'): self.redirect('/admin/unauthorized') template = "admin/files.html" server_id = bleach.clean(self.get_argument('id', 1)) context['server_id'] = server_id srv_object = multi.get_server_obj(server_id) context['pwd'] = srv_object.server_path context['listing'] = helper.scan_dirs_in_path(context['pwd']) context['parent'] = None context['ext_list'] = [ ".txt", ".yml", "ties", "json", '.conf', 'cfg' ] else: # 404 template = "public/404.html" context = {} self.render(template, data=context)
def get(self, page): if page == 'server_log': server_id = bleach.clean(self.get_argument('id')) if server_id is None: logger.warning("Server ID not found in server_log ajax call") return False server_path = multi.get_server_root_path(server_id) server_log = os.path.join(server_path, 'logs', 'latest.log') data = helper.tail_file(server_log, 40) for d in data: self.write(d.encode("utf-8")) elif page == 'history': server_id = bleach.clean(self.get_argument("server_id", '')) db_data = History.select().where(History.server_id == server_id) return_data = [] for d in db_data: row_data = { 'time': d.time.strftime("%m/%d/%Y %H:%M:%S"), 'cpu': d.cpu, 'mem': d.memory, 'players': d.players } return_data.append(row_data) self.write(json.dumps(return_data)) elif page == 'update_check': context = { 'master': helper.check_version('master'), 'beta': helper.check_version('beta'), 'snaps': helper.check_version('snapshot'), 'current': helper.get_version() } self.render('ajax/version.html', data=context) elif page == 'host_cpu_infos': name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = {'host_stats': multi.get_host_status()} self.render('ajax/host_cpu_infos.html', data=context) elif page == 'host_ram_infos': name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = {'host_stats': multi.get_host_status()} self.render('ajax/host_ram_infos.html', data=context) elif page == 'host_disk_infos': name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = {'host_stats': multi.get_host_status()} self.render('ajax/host_disk_infos.html', data=context) elif page == 'host_running_servers': name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = { 'servers_running': multi.list_running_servers(), 'servers_defined': multi.list_servers(), } self.render('ajax/host_running_servers.html', data=context) elif page == 'server_status': name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = { 'user_data': user_data, 'mc_servers_data': multi.get_stats_for_servers() } server_id = bleach.clean(self.get_argument('id')) srv_obj = multi.get_server_obj(server_id) context['srv'] = { 'id': srv_obj.server_id, 'name': srv_obj.get_mc_server_name(), 'running': srv_obj.check_running(), 'crashed': srv_obj.check_crashed(), 'auto_start': srv_obj.settings.auto_start_server } self.render('ajax/server_status.html', data=context) elif page == 'server_infos': name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) context = { 'user_data': user_data, 'mc_servers_data': multi.get_stats_for_servers() } server_id = bleach.clean(self.get_argument('id', 1)) srv_obj = multi.get_server_obj(server_id) context['srv'] = { 'id': srv_obj.server_id, 'name': srv_obj.get_mc_server_name(), 'running': srv_obj.check_running(), 'crashed': srv_obj.check_crashed(), 'auto_start': srv_obj.settings.auto_start_server } self.render('ajax/server_infos.html', data=context) elif page == 'get_file': file_path = bleach.clean(self.get_argument('file_name')) server_id = bleach.clean(self.get_argument('server_id')) mc_data = MC_settings.get_by_id(server_id) mc_settings = model_to_dict(mc_data) mc_settings['server_path'] = str( mc_settings['server_path']).replace("\\", '/') # let's remove the server directory from the path... asked_for_path = file_path.replace(mc_settings['server_path'], '') built_path = mc_settings['server_path'] + asked_for_path # if the server directory plus the path asked for doesn't exits... # this must be an attempt to do path traversal...so we bomb out. if not helper.check_file_exists(built_path): raise Exception( "possible file traversal detected {}".format(file_path)) else: f = open(file_path, "r") file_data = f.read() context = { "file_data": file_data, "file_path": file_path, "server_id": server_id } self.render('ajax/edit_file.html', data=context)
def post(self, page): name = tornado.escape.json_decode(self.current_user) user_data = get_perms_for_user(name) if page == "send_command": command = bleach.clean( self.get_body_argument('command', default=None, strip=True)) server_id = bleach.clean(self.get_argument('id')) if server_id is None: logger.warning("Server ID not found in send_command ajax call") srv_obj = multi.get_server_obj(server_id) if command: if srv_obj.check_running(): srv_obj.send_command(command) elif page == 'del_file': file_to_del = bleach.clean( self.get_body_argument('file_name', default=None, strip=True)) server_id = bleach.clean( self.get_argument('server_id', default=None, strip=True)) # let's make sure this path is in the backup directory and not somewhere else # we don't want someone passing a path like /etc/passwd in the raw, so we are only passing the filename # to this function, and then tacking on the storage location in front of the filename. backup_folder = backupmgr.get_backup_folder_for_server(server_id) # Grab our backup path from the DB backup_list = Backups.get(Backups.server_id == int(server_id)) server_backup_file = os.path.join(backup_list.storage_location, backup_folder, file_to_del) if server_backup_file and helper.check_file_exists( server_backup_file): helper.del_file(server_backup_file) elif page == 'del_schedule': id_to_del = bleach.clean( self.get_body_argument('id', default=None, strip=True)) if id_to_del: logger.info("Got command to del schedule {}".format(id_to_del)) q = Schedules.delete().where(Schedules.id == id_to_del) q.execute() multi.reload_user_schedules() elif page == 'search_logs': search_string = bleach.clean( self.get_body_argument('search', default=None, strip=True)) server_id = bleach.clean( self.get_body_argument('id', default=None, strip=True)) data = MC_settings.get_by_id(server_id) logfile = os.path.join(data.server_path, 'logs', 'latest.log') data = helper.search_file(logfile, search_string) if data: temp_data = "" for d in data: line = "Line Number: {} {}".format(d[0], d[1]) temp_data = "{}\n{}".format(temp_data, line) return_data = temp_data else: return_data = "Unable to find your string: {}".format( search_string) self.write(return_data) elif page == 'add_user': if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Add User")) self.redirect('/admin/unauthorized') new_username = bleach.clean( self.get_argument("username", None, True)) if new_username: new_pass = helper.random_string_generator() api_token = helper.random_string_generator(32) result = Users.insert({ Users.username: new_username, Users.role: 'Mod', Users.api_token: api_token, Users.password: helper.encode_pass(new_pass) }).execute() self.write(new_pass) elif page == "edit_user_role": if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Delete User")) self.redirect('/admin/unauthorized') username = bleach.clean(self.get_argument("username", None, True)) role = bleach.clean(self.get_argument("role", None, True)) if username == 'Admin': self.write("Not Allowed") else: if username and role: Users.update({ Users.role: role }).where(Users.username == username).execute() self.write('updated') elif page == "change_password": if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Delete User")) self.redirect('/admin/unauthorized') username = bleach.clean(self.get_argument("username", None, True)) newpassword = bleach.clean( self.get_argument("password", None, True)) if username and newpassword: Users.update({ Users.password: helper.encode_pass(newpassword) }).where(Users.username == username).execute() self.write(newpassword) elif page == 'del_user': if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Delete User")) self.redirect('/admin/unauthorized') username = bleach.clean(self.get_argument("username", None, True)) if username == 'Admin': self.write("Not Allowed") else: if username: Users.delete().where(Users.username == username).execute() self.write("{} deleted".format(username)) elif page == 'add_role': if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Add Role")) self.redirect('/admin/unauthorized') new_rolename = bleach.clean( self.get_argument("rolename", None, True)) if new_rolename: result = Roles.insert({ Roles.name: new_rolename, Roles.svr_control: False, Roles.svr_console: False, Roles.logs: False, Roles.backups: False, Roles.schedules: False, Roles.config: False, Roles.files: False, Roles.api_access: False, }).execute() self.write("{}".format(new_rolename)) elif page == 'edit_role': if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Add Role")) self.redirect('/admin/unauthorized') rolename = bleach.clean(self.get_argument("rolename", None, True)) new_svr_control = 'True' == bleach.clean( self.get_argument("svr_control", False, True)) new_svr_console = 'True' == bleach.clean( self.get_argument("svr_console", False, True)) new_logs = 'True' == bleach.clean( self.get_argument("logs", False, True)) new_backups = 'True' == bleach.clean( self.get_argument("backups", False, True)) new_schedules = 'True' == bleach.clean( self.get_argument("schedules", False, True)) new_config = 'True' == bleach.clean( self.get_argument("config", False, True)) new_files = 'True' == bleach.clean( self.get_argument("files", False, True)) new_api_access = 'True' == bleach.clean( self.get_argument("api_access", False, True)) if rolename: result = Roles.update({ Roles.svr_control: new_svr_control, Roles.svr_console: new_svr_console, Roles.logs: new_logs, Roles.backups: new_backups, Roles.schedules: new_schedules, Roles.config: new_config, Roles.files: new_files, Roles.api_access: new_api_access, }).where(Roles.name == rolename).execute() self.write("{} edited".format(rolename)) elif page == 'del_role': if not user_data['config']: logger.warning( "User: {} with Role: {} Attempted Access to: {} and was denied" .format(user_data['username'], user_data['role_name'], "Delete Role")) self.redirect('/admin/unauthorized') rolename = bleach.clean(self.get_argument("rolename", None, True)) if rolename == 'Admin': self.write("Not Allowed") else: if rolename: Roles.delete().where(Roles.name == rolename).execute() self.write("{} deleted".format(rolename)) elif page == 'save_file': file_data = self.get_argument('file_contents') file_path = bleach.clean(self.get_argument("file_path")) server_id = bleach.clean(self.get_argument("server_id")) mc_data = MC_settings.get_by_id(server_id) mc_settings = model_to_dict(mc_data) mc_settings['server_path'] = str( mc_settings['server_path']).replace("\\", '/') # let's remove the server directory from the path... asked_for_path = file_path.replace(mc_settings['server_path'], '') built_path = mc_settings['server_path'] + asked_for_path # if the server directory plus the path asked for doesn't exits... # this must be an attempt to do path traversal...so we bomb out. if not helper.check_file_exists(built_path): raise Exception( "possible file traversal detected {}".format(file_path)) try: file = open(file_path, 'w') file.write(file_data) file.close() logger.info("File {} saved with new content".format(file_path)) except Exception as e: logger.error("Unable to save {} due to {} error".format( file_path, e)) self.redirect("/admin/files?id={}".format(server_id)) elif page == "del_server_file": file_path = bleach.clean(self.get_argument("file_name")) server_id = bleach.clean(self.get_argument("server_id")) mc_data = MC_settings.get_by_id(server_id) mc_settings = model_to_dict(mc_data) mc_settings['server_path'] = str( mc_settings['server_path']).replace("\\", '/') # let's remove the server directory from the path... asked_for_path = file_path.replace(mc_settings['server_path'], '') built_path = mc_settings['server_path'] + asked_for_path if helper.check_directory_exist(built_path): try: shutil.rmtree(built_path) logger.info("Deleting {}".format(built_path)) except Exception as e: logger.error("Unable to delete {} due to {} error".format( file_path, e)) if helper.check_file_exists(built_path): try: os.remove(file_path) logger.info("File {} deleted".format(file_path)) except Exception as e: logger.error("Unable to delete {} due to {} error".format( file_path, e)) self.redirect("/admin/files?id={}".format(server_id)) elif page == "new_file_folder": type = bleach.clean(self.get_argument("type")) server_id = bleach.clean(self.get_argument("server_id")) pwd = bleach.clean(self.get_argument("pwd")) name = bleach.clean(self.get_argument("name")) mc_data = MC_settings.get_by_id(server_id) mc_settings = model_to_dict(mc_data) mc_settings['server_path'] = str( mc_settings['server_path']).replace("\\", '/') # let's remove the server directory from the path... asked_for_path = pwd.replace(mc_settings['server_path'], '') built_path = mc_settings['server_path'] + asked_for_path path = os.path.join(pwd, name) if type == "folder": logger.info("Creating folder at {}".format(path)) try: os.mkdir(path) except Exception as e: logger.error( "Unable to create folder at {} due to {}".format( path, e)) else: logger.info("Creating File at {}".format(path)) try: with open(path, "w") as fobject: fobject.close() except Exception as e: logger.error( "Unable to create file at {} due to {}".format( path, e)) elif page == "unzip_server_file": file_path = bleach.clean(self.get_argument("file_name")) server_id = bleach.clean(self.get_argument("server_id")) pwd = bleach.clean(self.get_argument("pwd")) mc_data = MC_settings.get_by_id(server_id) mc_settings = model_to_dict(mc_data) mc_settings['server_path'] = str( mc_settings['server_path']).replace("\\", '/') # let's remove the server directory from the path... asked_for_path = file_path.replace(mc_settings['server_path'], '') built_path = mc_settings['server_path'] + asked_for_path # if the server directory plus the path asked for doesn't exits... # this must be an attempt to do path traversal...so we bomb out. if not helper.check_file_exists(built_path): raise Exception( "possible file traversal detected {}".format(file_path)) try: with ZipFile(file_path, "r") as zipObj: logger.info("Exctracting file: {} to dir {}".format( file_path, pwd)) zipObj.extractall(pwd) except Exception as e: logger.error("Unable to extract: {} due to error: {}".format( file_path, e)) self.redirect("/admin/files?id={}".format(server_id)) elif page == "destroy_server": server_id = bleach.clean( self.get_body_argument('server_id', default=None, strip=True)) if server_id is not None: # stop any server stats going on... schedule.clear('server_stats') # remove it from multi multi.remove_server_object(server_id) # reschedule the things multi.reload_scheduling() self.write("Success")