import logging import os import time import urllib.parse import tornado.web import tornado.options import tornado.httpserver from app.classes.models.crafty_permissions import EnumPermissionsCrafty from app.classes.models.server_permissions import EnumPermissionsServer from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.shared.main_controller import Controller from app.classes.web.base_handler import BaseHandler from app.classes.shared.websocket_manager import WebSocketManager logger = logging.getLogger(__name__) @tornado.web.stream_request_body class UploadHandler(BaseHandler): # noinspection PyAttributeOutsideInit def initialize( self, helper: Helpers = None, controller: Controller = None, tasks_manager=None, translator=None, file_helper=None, ): self.helper = helper self.controller = controller self.tasks_manager = tasks_manager self.translator = translator self.file_helper = file_helper def prepare(self): # Class & Function Defination api_key, _token_data, exec_user = self.current_user self.upload_type = str(self.request.headers.get("X-Content-Upload-Type")) if self.upload_type == "server_import": superuser = exec_user["superuser"] if api_key is not None: superuser = superuser and api_key.full_access user_id = exec_user["user_id"] stream_size_value = self.helper.get_setting("stream_size_GB") max_streamed_size = (1024 * 1024 * 1024) * stream_size_value self.content_len = int(self.request.headers.get("Content-Length")) if self.content_len > max_streamed_size: logger.error( f"User with ID {user_id} attempted to upload a file that" f" exceeded the max body size." ) return self.finish_json( 413, { "status": "error", "error": "TOO LARGE", "info": self.helper.translation.translate( "error", "fileTooLarge", self.controller.users.get_user_lang_by_id(user_id), ), }, ) self.do_upload = True if superuser: exec_user_server_permissions = ( self.controller.server_perms.list_defined_permissions() ) elif api_key is not None: exec_user_server_permissions = ( self.controller.crafty_perms.get_api_key_permissions_list(api_key) ) else: exec_user_server_permissions = ( self.controller.crafty_perms.get_crafty_permissions_list( exec_user["user_id"] ) ) if user_id is None: logger.warning("User ID not found in upload handler call") Console.warning("User ID not found in upload handler call") self.do_upload = False if ( EnumPermissionsCrafty.SERVER_CREATION not in exec_user_server_permissions and not exec_user["superuser"] ): logger.warning( f"User {user_id} tried to upload a server" " without permissions!" ) Console.warning( f"User {user_id} tried to upload a server" " without permissions!" ) self.do_upload = False path = os.path.join(self.controller.project_root, "import", "upload") self.helper.ensure_dir_exists(path) # Delete existing files if len(os.listdir(path)) > 0: for item in os.listdir(): try: os.remove(os.path.join(path, item)) except: logger.debug("Could not delete file on user server upload") self.helper.ensure_dir_exists(path) filename = urllib.parse.unquote( self.request.headers.get("X-FileName", None) ) if not str(filename).endswith(".zip"): WebSocketManager().broadcast("close_upload_box", "error") self.finish("error") full_path = os.path.join(path, filename) if self.do_upload: try: self.f = open(full_path, "wb") except Exception as e: logger.error(f"Upload failed with error: {e}") self.do_upload = False # If max_body_size is not set, you cannot upload files > 100MB self.request.connection.set_max_body_size(max_streamed_size) elif self.upload_type == "background": superuser = exec_user["superuser"] if api_key is not None: superuser = superuser and api_key.full_access user_id = exec_user["user_id"] stream_size_value = self.helper.get_setting("stream_size_GB") max_streamed_size = (1024 * 1024 * 1024) * stream_size_value self.content_len = int(self.request.headers.get("Content-Length")) if self.content_len > max_streamed_size: logger.error( f"User with ID {user_id} attempted to upload a file that" f" exceeded the max body size." ) return self.finish_json( 413, { "status": "error", "error": "TOO LARGE", "info": self.helper.translation.translate( "error", "fileTooLarge", self.controller.users.get_user_lang_by_id(user_id), ), }, ) self.do_upload = True if not superuser: return self.finish_json( 401, { "status": "error", "error": "UNAUTHORIZED ACCESS", "info": self.helper.translation.translate( "error", "superError", self.controller.users.get_user_lang_by_id(user_id), ), }, ) if not self.request.headers.get("X-Content-Type", None).startswith( "image/" ): return self.finish_json( 415, { "status": "error", "error": "TYPE ERROR", "info": self.helper.translation.translate( "error", "fileError", self.controller.users.get_user_lang_by_id(user_id), ), }, ) if user_id is None: logger.warning("User ID not found in upload handler call") Console.warning("User ID not found in upload handler call") self.do_upload = False path = os.path.join( self.controller.project_root, "app/frontend/static/assets/images/auth/custom", ) filename = self.request.headers.get("X-FileName", None) full_path = os.path.join(path, filename) if self.do_upload: try: self.f = open(full_path, "wb") except Exception as e: logger.error(f"Upload failed with error: {e}") self.do_upload = False # If max_body_size is not set, you cannot upload files > 100MB self.request.connection.set_max_body_size(max_streamed_size) else: server_id = self.get_argument("server_id", None) superuser = exec_user["superuser"] if api_key is not None: superuser = superuser and api_key.full_access user_id = exec_user["user_id"] stream_size_value = self.helper.get_setting("stream_size_GB") max_streamed_size = (1024 * 1024 * 1024) * stream_size_value self.content_len = int(self.request.headers.get("Content-Length")) if self.content_len > max_streamed_size: logger.error( f"User with ID {user_id} attempted to upload a file that" f" exceeded the max body size." ) return self.finish_json( 413, { "status": "error", "error": "TOO LARGE", "info": self.helper.translation.translate( "error", "fileTooLarge", self.controller.users.get_user_lang_by_id(user_id), ), }, ) self.do_upload = True if superuser: exec_user_server_permissions = ( self.controller.server_perms.list_defined_permissions() ) elif api_key is not None: exec_user_server_permissions = ( self.controller.server_perms.get_api_key_permissions_list( api_key, server_id ) ) else: exec_user_server_permissions = ( self.controller.server_perms.get_user_id_permissions_list( exec_user["user_id"], server_id ) ) server_id = self.request.headers.get("X-ServerId", None) if server_id is None: logger.warning("Server ID not found in upload handler call") Console.warning("Server ID not found in upload handler call") self.do_upload = False if user_id is None: logger.warning("User ID not found in upload handler call") Console.warning("User ID not found in upload handler call") self.do_upload = False if EnumPermissionsServer.FILES not in exec_user_server_permissions: logger.warning( f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) Console.warning( f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) self.do_upload = False path = self.request.headers.get("X-Path", None) filename = self.request.headers.get("X-FileName", None) full_path = os.path.join(path, filename) if not self.helper.is_subdir( full_path, Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), ): logger.warning( f"User {user_id} tried to upload a file to {server_id} " f"but the path is not inside of the server!" ) Console.warning( f"User {user_id} tried to upload a file to {server_id} " f"but the path is not inside of the server!" ) self.do_upload = False if self.do_upload: try: self.f = open(full_path, "wb") except Exception as e: logger.error(f"Upload failed with error: {e}") self.do_upload = False # If max_body_size is not set, you cannot upload files > 100MB self.request.connection.set_max_body_size(max_streamed_size) def post(self): logger.info("Upload completed") if self.upload_type == "server_files": files_left = int(self.request.headers.get("X-Files-Left", None)) else: files_left = 0 if self.do_upload: time.sleep(5) if files_left == 0: WebSocketManager().broadcast("close_upload_box", "success") self.finish("success") # Nope, I'm sending "success" self.f.close() else: time.sleep(5) if files_left == 0: WebSocketManager().broadcast("close_upload_box", "error") self.finish("error") def data_received(self, chunk): if self.do_upload: self.f.write(chunk)