From 7dd24b6b15557836fc55f2b7d4483db5519cd101 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 8 Jan 2022 23:03:45 +0000 Subject: [PATCH] Improved File Loading, Fixed Port checking --- app/classes/controllers/users_controller.py | 4 +- app/classes/models/users.py | 5 +- app/classes/shared/helpers.py | 67 +++++++++++-- app/classes/shared/main_controller.py | 2 +- app/classes/shared/main_models.py | 2 +- app/classes/shared/server.py | 27 +++--- app/classes/web/ajax_handler.py | 24 ++++- app/classes/web/panel_handler.py | 12 ++- app/classes/web/public_handler.py | 23 ++++- app/config/config.json | 3 +- app/frontend/templates/base.html | 1 + app/frontend/templates/footer.html | 4 + app/frontend/templates/notify.html | 5 +- .../templates/panel/panel_edit_user.html | 4 + .../templates/panel/server_config.html | 2 +- .../templates/panel/server_files.html | 93 ++++++++++++++----- .../templates/panel/server_tasks.html | 76 +++++++++------ app/migrations/20210915205501_user_email.py | 16 ++++ app/translations/en_EN.json | 3 +- main.py | 22 ++++- requirements.txt | 1 + 21 files changed, 307 insertions(+), 89 deletions(-) create mode 100644 app/migrations/20210915205501_user_email.py diff --git a/app/classes/controllers/users_controller.py b/app/classes/controllers/users_controller.py index 3bf146f1..072b9335 100644 --- a/app/classes/controllers/users_controller.py +++ b/app/classes/controllers/users_controller.py @@ -94,8 +94,8 @@ class Users_Controller: users_helper.update_user(user_id, up_data) @staticmethod - def add_user(username, password=None, api_token=None, enabled=True, superuser=False): - return users_helper.add_user(username, password=password, api_token=api_token, enabled=enabled, superuser=superuser) + def add_user(username, password=None, email="default@example.com", api_token=None, enabled=True, superuser=False): + return users_helper.add_user(username, password=password, email=email, api_token=api_token, enabled=enabled, superuser=superuser) @staticmethod def remove_user(user_id): diff --git a/app/classes/models/users.py b/app/classes/models/users.py index d6bd1607..97d1f9f8 100644 --- a/app/classes/models/users.py +++ b/app/classes/models/users.py @@ -38,6 +38,7 @@ class Users(Model): last_ip = CharField(default="") username = CharField(default="", unique=True, index=True) password = CharField(default="") + email = CharField(default="default@example.com") enabled = BooleanField(default=True) superuser = BooleanField(default=False) api_token = CharField(default="", unique=True, index=True) # we may need to revisit this @@ -112,6 +113,7 @@ class helper_users: 'last_ip': "127.27.23.89", 'username': "SYSTEM", 'password': None, + 'email': "default@example.com", 'enabled': True, 'superuser': True, 'api_token': None, @@ -136,7 +138,7 @@ class helper_users: return False @staticmethod - def add_user(username, password=None, api_token=None, enabled=True, superuser=False): + def add_user(username, password=None, email=None, api_token=None, enabled=True, superuser=False): if password is not None: pw_enc = helper.encode_pass(password) else: @@ -149,6 +151,7 @@ class helper_users: user_id = Users.insert({ Users.username: username.lower(), Users.password: pw_enc, + Users.email: email, Users.api_token: api_token, Users.enabled: enabled, Users.superuser: superuser, diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index a4bf2fc8..116d9f5a 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -97,13 +97,33 @@ class Helpers: @staticmethod def check_port(server_port): + try: + ip = get('https://api.ipify.org').content.decode('utf8') + except: + ip = 'google.com' a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - ip = get('https://api.ipify.org').content.decode('utf8') + a_socket.settimeout(20.0) location = (ip, server_port) result_of_check = a_socket.connect_ex(location) + a_socket.close() + + if result_of_check == 0: + return True + else: + return False + + @staticmethod + def check_server_conn(server_port): + a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + a_socket.settimeout(10.0) + ip = '127.0.0.1' + + location = (ip, server_port) + result_of_check = a_socket.connect_ex(location) + a_socket.close() + if result_of_check == 0: return True else: @@ -654,29 +674,58 @@ class Helpers: @staticmethod def generate_tree(folder, output=""): file_list = os.listdir(folder) - file_list.sort() + file_list = sorted(file_list, key=str.casefold) for raw_filename in file_list: filename = html.escape(raw_filename) rel = os.path.join(folder, raw_filename) if os.path.isdir(rel): output += \ """
  • - \n
    + \n
    + {} -
    - \n
      """\ - .format(os.path.join(folder, filename), os.path.join(folder, filename), filename, filename) + +
  • + \n"""\ + .format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), filename) + else: + output += """
  • {}
  • """.format(os.path.join(folder, filename), filename, filename) + return output - output += helper.generate_tree(rel) - output += '\n' + @staticmethod + def generate_dir(folder, output=""): + file_list = os.listdir(folder) + file_list = sorted(file_list, key=str.casefold) + output += \ + """\n' return output @staticmethod diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index e9c7750f..84b2b0d9 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -130,7 +130,7 @@ class Controller: @staticmethod def add_system_user(): - helper_users.add_user("system", helper.random_string_generator(64), helper_users.new_api_token(), False, False) + helper_users.add_user("system", helper.random_string_generator(64), "default@example.com", helper_users.new_api_token(), False, False) def get_server_settings(self, server_id): for s in self.servers_list: diff --git a/app/classes/shared/main_models.py b/app/classes/shared/main_models.py index 596fa372..01d12951 100644 --- a/app/classes/shared/main_models.py +++ b/app/classes/shared/main_models.py @@ -48,7 +48,7 @@ class db_builder: # Users.enabled: True, # Users.superuser: True #}).execute() - user_id = users_helper.add_user(username=username, password=password, superuser=True) + user_id = users_helper.add_user(username=username, password=password, email="default@example.com", superuser=True) #users_helper.update_user(user_id, user_crafty_data={"permissions_mask":"111", "server_quantity":[-1,-1,-1]} ) #console.info("API token is {}".format(api_token)) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index b1ceb271..3dfd28ce 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -274,6 +274,8 @@ class Server: self.stats.record_stats() websocket_helper.broadcast_user(user_id, 'send_start_reload', { }) + check_port_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"backup_{self.name}") + check_port_thread.start() else: logger.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid)) console.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid)) @@ -284,27 +286,26 @@ class Server: self.crash_watcher_schedule = schedule.every(30).seconds.do(self.detect_crash).tag(self.name) - check_port_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"backup_{self.name}") - check_port_thread.start() - def check_internet_thread(self, user_id, user_lang): if user_id: if helper.check_internet(): loc_server_port = servers_helper.get_server_stats_by_id(self.server_id)['server_port'] port_status = False - for i in range(3): - if helper.check_port(loc_server_port): - port_status = True - return + checked = False + while not checked: + if helper.check_server_conn(loc_server_port): + checked = True + result_of_check = helper.check_port(loc_server_port) + + if result_of_check == True: + return + else: + websocket_helper.broadcast_user(user_id, 'send_start_error', { + 'error': translation.translate('error', 'closedPort', user_lang).format(loc_server_port) + }) else: time.sleep(5) - - - if port_status == False: - websocket_helper.broadcast_user(user_id, 'send_start_error', { - 'error': translation.translate('error', 'closedPort', user_lang).format(loc_server_port) - }) else: websocket_helper.broadcast_user(user_id, 'send_start_error', { 'error': translation.translate('error', 'internet', user_lang) diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 1534e872..d2c6de83 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -124,12 +124,26 @@ class AjaxHandler(BaseHandler): elif page == "get_tree": server_id = self.get_argument('id', None) + path = self.get_argument('path', None) if not self.check_server_id(server_id, 'get_tree'): return else: server_id = bleach.clean(server_id) - self.write(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['path']) + '\n' + - helper.generate_tree(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['path']))) + if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path): + self.write(helper.get_os_understandable_path(path) + '\n' + + helper.generate_tree(path)) + self.finish() + + elif page == "get_dir": + server_id = self.get_argument('id', None) + path = self.get_argument('path', None) + + if not self.check_server_id(server_id, 'get_tree'): return + else: server_id = bleach.clean(server_id) + + if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path): + self.write(helper.get_os_understandable_path(path) + '\n' + + helper.generate_dir(path)) self.finish() @tornado.web.authenticated @@ -328,7 +342,8 @@ class AjaxHandler(BaseHandler): return # Delete the file - os.remove(file_path) + if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), file_path): + os.remove(file_path) elif page == "del_dir": if not permissions['Files'] in user_perms: @@ -352,7 +367,8 @@ class AjaxHandler(BaseHandler): # Delete the directory # os.rmdir(dir_path) # Would only remove empty directories - shutil.rmtree(dir_path) # Removes also when there are contents + if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), dir_path): + shutil.rmtree(dir_path) # Removes also when there are contents elif page == "delete_server": if not permissions['Config'] in user_perms: diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index da5bc8e9..4d037281 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -422,6 +422,7 @@ class PanelHandler(BaseHandler): page_data['user'] = {} page_data['user']['username'] = "" page_data['user']['user_id'] = -1 + page_data['user']['email'] = "" page_data['user']['enabled'] = True page_data['user']['superuser'] = False page_data['user']['api_token'] = "N/A" @@ -489,6 +490,9 @@ class PanelHandler(BaseHandler): if exec_user['user_id'] != page_data['user']['user_id']: page_data['user']['api_token'] = "********" + + if exec_user['email'] == 'default@example.com': + page_data['user']['email'] = "" template = "panel/panel_edit_user.html" elif page == "remove_user": @@ -824,6 +828,7 @@ class PanelHandler(BaseHandler): username = bleach.clean(self.get_argument('username', None)) password0 = bleach.clean(self.get_argument('password0', None)) password1 = bleach.clean(self.get_argument('password1', None)) + email = bleach.clean(self.get_argument('email', "default@example.com")) enabled = int(float(self.get_argument('enabled', '0'))) regen_api = int(float(self.get_argument('regen_api', '0'))) lang = bleach.clean(self.get_argument('language'), 'en_EN') @@ -894,9 +899,13 @@ class PanelHandler(BaseHandler): else: server_quantity[permission.name] = 0 + # if email is None or "": + # email = "default@example.com" + user_data = { "username": username, "password": password0, + "email": email, "enabled": enabled, "regen_api": regen_api, "roles": roles, @@ -922,6 +931,7 @@ class PanelHandler(BaseHandler): username = bleach.clean(self.get_argument('username', None)) password0 = bleach.clean(self.get_argument('password0', None)) password1 = bleach.clean(self.get_argument('password1', None)) + email = bleach.clean(self.get_argument('email', "default@example.com")) enabled = int(float(self.get_argument('enabled', '0'))), lang = bleach.clean(self.get_argument('lang', 'en_EN')) @@ -972,7 +982,7 @@ class PanelHandler(BaseHandler): else: server_quantity[permission.name] = 0 - user_id = self.controller.users.add_user(username, password=password0, enabled=enabled) + user_id = self.controller.users.add_user(username, password=password0, email=email, enabled=enabled) user_data = { "roles": roles, 'lang': lang diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py index e5c4cd57..c367a62e 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -1,10 +1,13 @@ +from re import X import sys import json +import libgravatar import logging +import requests import tornado.web import tornado.escape -from app.classes.shared.helpers import helper +from app.classes.shared.helpers import Helpers, helper from app.classes.web.base_handler import BaseHandler from app.classes.shared.console import console from app.classes.shared.main_models import fn @@ -121,9 +124,27 @@ class PublicHandler(BaseHandler): # log this login self.controller.management.add_to_audit_log(user_data.user_id, "Logged in", 0, self.get_remote_ip()) + if helper.get_setting("allow_nsfw_profile_pictures"): + rating = "x" + else: + rating = "g" + + + #Get grvatar hash for profile pictures + if user_data.email != 'default@example.com' or "": + g = libgravatar.Gravatar(libgravatar.sanitize_email(user_data.email)) + url = g.get_image(size=80, default="404", force_default=False, rating=rating, filetype_extension=False, use_ssl=True) # + "?d=404" + if requests.head(url).status_code != 404: + profile_url = url + else: + profile_url = "/static/assets/images/faces-clipart/pic-3.png" + else: + profile_url = "/static/assets/images/faces-clipart/pic-3.png" cookie_data = { "username": user_data.username, "user_id": user_data.user_id, + "email": user_data.email, + "profile_url": profile_url, "account_type": user_data.superuser, } diff --git a/app/config/config.json b/app/config/config.json index 27f08bb8..2d11724a 100644 --- a/app/config/config.json +++ b/app/config/config.json @@ -12,5 +12,6 @@ "show_contribute_link": true, "virtual_terminal_lines": 70, "max_log_lines": 700, - "keywords": ["help", "chunk"] + "keywords": ["help", "chunk"], + "allow_nsfw_profile_pictures": false } diff --git a/app/frontend/templates/base.html b/app/frontend/templates/base.html index 6d7f908a..9210194e 100644 --- a/app/frontend/templates/base.html +++ b/app/frontend/templates/base.html @@ -29,6 +29,7 @@ + diff --git a/app/frontend/templates/footer.html b/app/frontend/templates/footer.html index 344de732..4a594c35 100644 --- a/app/frontend/templates/footer.html +++ b/app/frontend/templates/footer.html @@ -2,7 +2,11 @@