From 1ed9f448cd15d1afa371f8904e9972d811466d38 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 12 Nov 2025 18:01:37 -0500 Subject: [PATCH 01/13] Provide better feedback on restore failures --- app/classes/helpers/file_helpers.py | 16 ++++++++++------ app/classes/shared/backup_mgr.py | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/app/classes/helpers/file_helpers.py b/app/classes/helpers/file_helpers.py index f855792d..06ea5f0f 100644 --- a/app/classes/helpers/file_helpers.py +++ b/app/classes/helpers/file_helpers.py @@ -126,6 +126,7 @@ class FileHelpers: @staticmethod def del_dirs(path): path = pathlib.Path(path) + clean = True for sub in path.iterdir(): if sub.is_dir(): # Delete folder if it is a folder @@ -135,26 +136,29 @@ class FileHelpers: try: sub.unlink() except Exception as e: + clean = False logger.error(f"Unable to delete file {sub}: {e}") try: # This removes the top-level folder: path.rmdir() - except Exception as e: + except Exception: logger.error("Unable to remove top level") - return e - return True + return False + return clean @staticmethod def del_file(path): path = pathlib.Path(path) + clean = True try: logger.debug(f"Deleting file: {path}") # Remove the file os.remove(path) - return True - except (FileNotFoundError, PermissionError) as e: + return clean + except (FileNotFoundError, PermissionError): logger.error(f"Path specified is not a file or does not exist. {path}") - return e + clean = False + return clean def check_mime_types(self, file_path): m_type, _value = self.mime_types.guess_type(file_path) diff --git a/app/classes/shared/backup_mgr.py b/app/classes/shared/backup_mgr.py index 876d7111..7c0c67f8 100644 --- a/app/classes/shared/backup_mgr.py +++ b/app/classes/shared/backup_mgr.py @@ -45,6 +45,7 @@ class BackupManager: self, backup_config, backup_location, backup_file, svr_obj, in_place ): server_path = svr_obj.settings["path"] + error = False if Helpers.validate_traversal(backup_location, backup_file): if svr_obj.check_running(): svr_obj.stop_server() @@ -58,10 +59,28 @@ class BackupManager: os.path.isdir(os.path.join(server_path, item)) and item != "db_stats" ): - self.file_helper.del_dirs(os.path.join(server_path, item)) + result = self.file_helper.del_dirs( + os.path.join(server_path, item) + ) + if not result: + error = True else: self.file_helper.del_file(os.path.join(server_path, item)) self.file_helper.restore_archive(backup_location, server_path) + server_users = PermissionsServers.get_server_user_list(svr_obj.server_id) + time.sleep(3) + if error: + for user in server_users: + WebSocketManager().broadcast_user( + user, + "send_start_error", + "Restore failure. Could not delete existing files", + ) + else: + for user in server_users: + WebSocketManager().broadcast_user( + user, "notification", "Restore completed" + ) def backup_starter(self, backup_config, server): """Notify users of backup starting, and start the backup. From 85596b860ab3cb4189f112daa47d043bac4abc83 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 12 Nov 2025 18:15:50 -0500 Subject: [PATCH 02/13] Add translations to restore process --- app/classes/shared/backup_mgr.py | 18 +++++++++++++++--- app/translations/en_EN.json | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/classes/shared/backup_mgr.py b/app/classes/shared/backup_mgr.py index 7c0c67f8..ffa8ffdc 100644 --- a/app/classes/shared/backup_mgr.py +++ b/app/classes/shared/backup_mgr.py @@ -65,7 +65,11 @@ class BackupManager: if not result: error = True else: - self.file_helper.del_file(os.path.join(server_path, item)) + result = self.file_helper.del_file( + os.path.join(server_path, item) + ) + if not result: + error = True self.file_helper.restore_archive(backup_location, server_path) server_users = PermissionsServers.get_server_user_list(svr_obj.server_id) time.sleep(3) @@ -74,12 +78,20 @@ class BackupManager: WebSocketManager().broadcast_user( user, "send_start_error", - "Restore failure. Could not delete existing files", + self.helper.translation.translate( + "notify", "restoreFailed", HelperUsers.get_user_lang_by_id(user) + ), ) else: for user in server_users: WebSocketManager().broadcast_user( - user, "notification", "Restore completed" + user, + "notification", + self.helper.translation.translate( + "notify", + "restoreSuccess", + HelperUsers.get_user_lang_by_id(user), + ), ) def backup_starter(self, backup_config, server): diff --git a/app/translations/en_EN.json b/app/translations/en_EN.json index 3e65cc60..6c29f479 100644 --- a/app/translations/en_EN.json +++ b/app/translations/en_EN.json @@ -283,6 +283,8 @@ "finishedPreparing": "We've finished preparing your support logs. Please click download to download", "logout": "Logout", "preparingLogs": " Please wait while we prepare your logs... We`ll send a notification when they`re ready. This may take a while for large deployments.", + "restoreFailed": "Backup restore failed. Could not delete files from server directory.", + "restoreSuccess": "Server files restored successfully.", "schedule_desc": "We detected some or all of your scheduled tasks were not successfully transferred during the upgrade. Please confirm your schedules in the schedules tab.", "schedule_title": "Schedules Migration Warning", "supportLogs": "Support Logs" From 7b418dc62f79a580407af0ce98bd9f43ee56647f Mon Sep 17 00:00:00 2001 From: = Date: Wed, 12 Nov 2025 18:21:27 -0500 Subject: [PATCH 03/13] Fix server.properties overwritten in bedrock update --- app/classes/shared/import_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/classes/shared/import_helper.py b/app/classes/shared/import_helper.py index 86a82906..a43e6388 100644 --- a/app/classes/shared/import_helper.py +++ b/app/classes/shared/import_helper.py @@ -244,7 +244,7 @@ class ImportHelpers: unzip_path = self.helper.wtol_path(file_path) # unzips archive that was downloaded. - self.file_helper.unzip_file(unzip_path) + self.file_helper.unzip_file(unzip_path, True) # adjusts permissions for execution if os is not windows if not self.helper.is_os_windows(): From 858ab486c318f8764ee97f1e45d9002fd6de4b7b Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 13 Nov 2025 20:12:13 -0500 Subject: [PATCH 04/13] Fix delete file call when deleting server --- app/classes/controllers/servers_controller.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/classes/controllers/servers_controller.py b/app/classes/controllers/servers_controller.py index ae3670f6..ca828d19 100644 --- a/app/classes/controllers/servers_controller.py +++ b/app/classes/controllers/servers_controller.py @@ -177,7 +177,9 @@ class ServersController(metaclass=Singleton): server_id, ) self.file_helper.del_dirs( - self.helper.root_dir, "app", "config", "db", "servers", str(server_id) + pathlib.Path( + self.helper.root_dir, "app", "config", "db", "servers", str(server_id) + ) ) @staticmethod From e4f43fa4c93ae19f8e2d60261aa59880f5dc2e08 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 14 Nov 2025 07:34:05 -0700 Subject: [PATCH 05/13] Fix survey not appearing on first login --- main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.py b/main.py index 8d82d4d3..5f812feb 100644 --- a/main.py +++ b/main.py @@ -21,6 +21,7 @@ from app.classes.logging.log_formatter import JsonFormatter console = Console() helper = Helpers() +FIRST_LOGIN = False # Get the path our application is running on. if getattr(sys, "frozen", False): APPLICATION_PATH = os.path.dirname(sys.executable) @@ -388,6 +389,7 @@ if __name__ == "__main__": f"through your router/firewall if you would like to be able " f"to access Crafty remotely." ) + FIRST_LOGIN = True PASSWORD = helper.create_pass() installer.default_settings(PASSWORD) with open( @@ -426,6 +428,7 @@ if __name__ == "__main__": import_helper = ImportHelpers(helper, file_helper) controller = Controller(database, helper, file_helper, import_helper) controller.set_project_root(APPLICATION_PATH) + controller.first_login = FIRST_LOGIN tasks_manager = TasksManager(helper, controller, file_helper) import3 = Import3(helper, controller) helper.migration_notifications = get_migration_notifications() From ba0e83016aa9fafbd2c4e1f517ca87ccfe61ce45 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 14 Nov 2025 07:38:19 -0700 Subject: [PATCH 06/13] first_login is not constant --- main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 5f812feb..a76f77e2 100644 --- a/main.py +++ b/main.py @@ -21,7 +21,7 @@ from app.classes.logging.log_formatter import JsonFormatter console = Console() helper = Helpers() -FIRST_LOGIN = False +first_login = False # Get the path our application is running on. if getattr(sys, "frozen", False): APPLICATION_PATH = os.path.dirname(sys.executable) @@ -389,7 +389,7 @@ if __name__ == "__main__": f"through your router/firewall if you would like to be able " f"to access Crafty remotely." ) - FIRST_LOGIN = True + first_login = True PASSWORD = helper.create_pass() installer.default_settings(PASSWORD) with open( @@ -428,7 +428,7 @@ if __name__ == "__main__": import_helper = ImportHelpers(helper, file_helper) controller = Controller(database, helper, file_helper, import_helper) controller.set_project_root(APPLICATION_PATH) - controller.first_login = FIRST_LOGIN + controller.first_login = first_login tasks_manager = TasksManager(helper, controller, file_helper) import3 = Import3(helper, controller) helper.migration_notifications = get_migration_notifications() From c63db67b04fc4662566c1cbd44acd16a68355f79 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 21 Nov 2025 14:02:02 -0400 Subject: [PATCH 07/13] Fix bad parameter in delete call on import dir cleanup --- app/classes/shared/tasks.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index 7be22c73..79ff5d2d 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -5,6 +5,7 @@ import threading import asyncio import datetime import json +from pathlib import Path from zoneinfo import ZoneInfoNotFoundError from tzlocal import get_localzone from apscheduler.events import EVENT_JOB_EXECUTED @@ -815,15 +816,16 @@ class TasksManager: os.remove(os.path.join(file)) except FileNotFoundError: logger.debug("Could not clear out file from temp directory") - - for file in os.listdir( - os.path.join(self.controller.project_root, "import", "upload") - ): - if self.helper.is_file_older_than_x_days( - os.path.join(self.controller.project_root, "import", "upload", file) - ): + import_path = Path(self.controller.project_root, "import", "upload") + for file in os.listdir(import_path): + file_path = Path(import_path, file).resolve(strict=True) + if not self.helper.validate_traversal(import_path, file_path): + logger.error( + "Traversal detected while deleting import file %s", file_path + ) + if self.helper.is_file_older_than_x_days(Path(import_path, file)): try: - os.remove(os.path.join(file)) + os.remove(Path(import_path, file)) except FileNotFoundError: logger.debug("Could not clear out file from import directory") From 20d6a2a1da9775da8217bb140c69e0adc7c97510 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 21 Nov 2025 14:05:32 -0400 Subject: [PATCH 08/13] Modify variable useage --- app/classes/shared/tasks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index 79ff5d2d..4134a634 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -823,9 +823,9 @@ class TasksManager: logger.error( "Traversal detected while deleting import file %s", file_path ) - if self.helper.is_file_older_than_x_days(Path(import_path, file)): + if self.helper.is_file_older_than_x_days(file_path): try: - os.remove(Path(import_path, file)) + os.remove(file_path) except FileNotFoundError: logger.debug("Could not clear out file from import directory") From f40e772eeb16321c84c78518bc2117d0716401ff Mon Sep 17 00:00:00 2001 From: Zedifus Date: Sat, 22 Nov 2025 15:42:05 +0000 Subject: [PATCH 09/13] Update changelog !918 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5c1b234..99adca88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ TBD - Change hour and minute intervals in APScheudler to fix incorrect triggers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/910)) - Use asyncio locks to limit upload handler race condition ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/907)) - Fix static fonts not working on some browsers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/906)) +- Fix import directory cleanup was not pointing to the proper directory ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/918)) ### Tweaks TBD ### Lang From 23e796c288da02891f34cd5d22ffb3dec1f8e3c6 Mon Sep 17 00:00:00 2001 From: Zedifus Date: Sat, 22 Nov 2025 16:16:58 +0000 Subject: [PATCH 10/13] Update changelog !917 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99adca88..c0f670ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ TBD - Use asyncio locks to limit upload handler race condition ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/907)) - Fix static fonts not working on some browsers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/906)) - Fix import directory cleanup was not pointing to the proper directory ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/918)) +- Fix survey not appearing on first login ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/917)) ### Tweaks TBD ### Lang From a0b1021fd9ce2a9cf1ef553ecc604315037cc97f Mon Sep 17 00:00:00 2001 From: Zedifus Date: Sat, 22 Nov 2025 16:24:57 +0000 Subject: [PATCH 11/13] Update changelog !916 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0f670ba..88aef332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ TBD - Fix static fonts not working on some browsers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/906)) - Fix import directory cleanup was not pointing to the proper directory ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/918)) - Fix survey not appearing on first login ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/917)) +- Fix failue deleting server's DB files on server delete ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/916)) ### Tweaks TBD ### Lang From 0c1ed6e77b0f8f156c112cff23a7f0c49bda1f65 Mon Sep 17 00:00:00 2001 From: Zedifus Date: Sat, 22 Nov 2025 16:31:45 +0000 Subject: [PATCH 12/13] Update changelog !915 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88aef332..2e353a32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ TBD - Fix import directory cleanup was not pointing to the proper directory ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/918)) - Fix survey not appearing on first login ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/917)) - Fix failue deleting server's DB files on server delete ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/916)) +- Fix server.properties overwritten in bedrock update ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/915)) ### Tweaks TBD ### Lang From c6f72ba12acce22f28d297df49194b771db09a95 Mon Sep 17 00:00:00 2001 From: Zedifus Date: Sat, 22 Nov 2025 16:52:24 +0000 Subject: [PATCH 13/13] Update changelog !914 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e353a32..ef6fdf99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ TBD - Fix failue deleting server's DB files on server delete ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/916)) - Fix server.properties overwritten in bedrock update ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/915)) ### Tweaks -TBD +- Provide better feedback on restore failures ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/914)) ### Lang TBD