From d54c0b570ac5f89c9f0ac2f1dbc9252845f11c7c Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 19:20:33 +0200 Subject: [PATCH 1/7] GUI: Fix new repo / group creation did not update repo selector --- npbackup/configuration.py | 33 ++++++++++++++++++++++++--------- npbackup/gui/config.py | 28 ++++++++++++++++++---------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/npbackup/configuration.py b/npbackup/configuration.py index 662a7d3..a3423cd 100644 --- a/npbackup/configuration.py +++ b/npbackup/configuration.py @@ -7,7 +7,7 @@ __intname__ = "npbackup.configuration" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2022-2024 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2024052201" +__build__ = "2024061601" __version__ = "npbackup 3.0.0+" MIN_CONF_VERSION = 3.0 @@ -233,6 +233,13 @@ empty_config_dict = { }, } +def convert_to_commented_map( + source_dict, +): + if isinstance(source_dict, dict): + return CommentedMap({k: convert_to_commented_map(v) for k, v in source_dict.items()}) + else: + return source_dict def get_default_config() -> dict: """ @@ -240,15 +247,23 @@ def get_default_config() -> dict: """ full_config = deepcopy(empty_config_dict) - def convert_to( - source_dict, - ): - if isinstance(source_dict, dict): - return CommentedMap({k: convert_to(v) for k, v in source_dict.items()}) - else: - return source_dict + return convert_to_commented_map(full_config) - return convert_to(full_config) + +def get_default_repo_config() -> dict: + """ + Returns a repo config dict as nested CommentedMaps (used by ruamel.yaml to keep comments intact) + """ + repo_config = deepcopy(empty_config_dict["repos"]["default"]) + return convert_to_commented_map(repo_config) + + +def get_default_group_config() -> dict: + """ + Returns a group config dict as nested CommentedMaps (used by ruamel.yaml to keep comments intact) + """ + group_config = deepcopy(empty_config_dict["groups"]["default_group"]) + return convert_to_commented_map(group_config) def key_should_be_encrypted(key: str, encrypted_options: List[str]): diff --git a/npbackup/gui/config.py b/npbackup/gui/config.py index bfbd216..5a19084 100644 --- a/npbackup/gui/config.py +++ b/npbackup/gui/config.py @@ -7,7 +7,7 @@ __intname__ = "npbackup.gui.config" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2022-2024 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2024051001" +__build__ = "2024061601" from typing import List, Tuple @@ -155,19 +155,20 @@ def config_gui(full_config: dict, config_file: str): _t("config_gui.repo_already_exists"), keep_on_top=True ) continue - full_config.s(f"repos.{object_name}", CommentedMap()) + full_config.s(f"repos.{object_name}", configuration.get_default_repo_config()) elif object_type == "group": if full_config.g(f"groups.{object_name}"): sg.PopupError( _t("config_gui.group_already_exists"), keep_on_top=True ) continue - full_config.s(f"groups.{object_name}", CommentedMap()) + full_config.s(f"groups.{object_name}", configuration.get_default_group_config()) else: raise ValueError("Bogus object type given") + break window.close() update_object_gui(None, unencrypted=False) - return full_config + return full_config, object_name, object_type def delete_object(full_config: dict, object_name: str) -> dict: object_type, object_name = get_object_from_combo(object_name) @@ -179,10 +180,17 @@ def config_gui(full_config: dict, config_file: str): update_object_gui(None, unencrypted=False) return full_config - def update_object_selector() -> None: - objects = get_objects() - window["-OBJECT-SELECT-"].Update(objects) - window["-OBJECT-SELECT-"].Update(value=objects[0]) + def update_object_selector(object_name: str = None, object_type: str = None) -> None: + object_list = get_objects() + if not object_name or not object_type: + object = object_list[0] + else: + object = f"{object_type.capitalize()}: {object_name}" + print(object_list) + print(object) + + window["-OBJECT-SELECT-"].Update(values=object_list) + window["-OBJECT-SELECT-"].Update(value=object) def get_object_from_combo(combo_value: str) -> Tuple[str, str]: """ @@ -1908,8 +1916,8 @@ Google Cloud storage: GOOGLE_PROJECT_ID GOOGLE_APPLICATION_CREDENTIALS\n\ update_object_selector() continue if event == "-OBJECT-CREATE-": - full_config = create_object(full_config) - update_object_selector() + full_config, object_name, object_type = create_object(full_config) + update_object_selector(object_name, object_type) continue if event == "--SET-PERMISSIONS--": manager_password = configuration.get_manager_password( From 06d7c720552abb3c685ff257c08c5eb7629bda96 Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 19:27:33 +0200 Subject: [PATCH 2/7] Add audience in config file --- npbackup/configuration.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/npbackup/configuration.py b/npbackup/configuration.py index a3423cd..769b250 100644 --- a/npbackup/configuration.py +++ b/npbackup/configuration.py @@ -129,6 +129,7 @@ ENCRYPTED_OPTIONS = [ # This is what a config file looks like empty_config_dict = { "conf_version": MAX_CONF_VERSION, + "audience": None, "repos": { "default": { "repo_uri": None, @@ -836,9 +837,9 @@ def load_config(config_file: Path) -> Optional[dict]: def save_config(config_file: Path, full_config: dict) -> bool: try: + full_config = inject_permissions_into_full_config(full_config) + full_config.s("audience", "private" if IS_PRIV_BUILD else "public") with open(config_file, "w", encoding="utf-8") as file_handle: - full_config = inject_permissions_into_full_config(full_config) - if not is_encrypted(full_config): full_config = crypt_config( full_config, AES_KEY, ENCRYPTED_OPTIONS, operation="encrypt" From 8c781efeea5206a87530ce168c3bd4c56925d6e4 Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 19:39:47 +0200 Subject: [PATCH 3/7] CLI: Make sure we show permissions and manager_password when needed --- npbackup/configuration.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/npbackup/configuration.py b/npbackup/configuration.py index 769b250..663b80c 100644 --- a/npbackup/configuration.py +++ b/npbackup/configuration.py @@ -486,6 +486,9 @@ def extract_permissions_from_full_config(full_config: dict) -> dict: full_config.s(f"repos.{repo}.manager_password", manager_password) else: logger.info(f"No extra information for repo {repo} found") + # If no permissions are set, we get to use default permissions + full_config.s(f"repos.{repo}.permissions", empty_config_dict["repos"]["default"]["permissions"]) + full_config.s(f"repos.{repo}.manager_password", None) return full_config @@ -905,8 +908,9 @@ def get_anonymous_repo_config(repo_config: dict, show_encrypted: bool = False) - value = "__(o_O)__" return value - # NPF-SEC-00008: Don't show manager password / sensible data with --show-config - repo_config.pop("manager_password", None) + # NPF-SEC-00008: Don't show manager password / sensible data with --show-config unless it's empty + if repo_config.get("manager_password", None): + repo_config["manager_password"] = "__(x_X)__" repo_config.pop("update_manager_password", None) if show_encrypted: return repo_config From bcc94dd42c81e8c13ed4e5f6a7aa6503b42691ef Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 19:39:58 +0200 Subject: [PATCH 4/7] Add init permission --- npbackup/core/runner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/npbackup/core/runner.py b/npbackup/core/runner.py index 93ad0fa..8229dc5 100644 --- a/npbackup/core/runner.py +++ b/npbackup/core/runner.py @@ -472,6 +472,7 @@ class NPBackupRunner: "restore": ["restore", "full"], "dump": ["restore", "full"], "check": ["restore", "full"], + "init": ["full"], "list": ["full"], "unlock": ["full"], "repair": ["full"], From 438ceaf4b0580f250f560d468b0210136642704d Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 21:07:43 +0200 Subject: [PATCH 5/7] Try to expand exclude_files path when missing --- npbackup/restic_wrapper/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/npbackup/restic_wrapper/__init__.py b/npbackup/restic_wrapper/__init__.py index d730db3..375824a 100644 --- a/npbackup/restic_wrapper/__init__.py +++ b/npbackup/restic_wrapper/__init__.py @@ -7,8 +7,8 @@ __intname__ = "npbackup.restic_wrapper" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2022-2024 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2024060101" -__version__ = "2.2.0" +__build__ = "2024061601" +__version__ = "2.2.1" from typing import Tuple, List, Optional, Callable, Union @@ -25,6 +25,7 @@ from command_runner import command_runner from ofunctions.misc import BytesConverter, fn_name from npbackup.__debug__ import _DEBUG from npbackup.__env__ import FAST_COMMANDS_TIMEOUT, CHECK_INTERVAL +from npbackup.path_helper import CURRENT_DIR logger = getLogger() @@ -823,6 +824,11 @@ class ResticRunner: if exclude_file: if os.path.isfile(exclude_file): cmd += f' --{case_ignore_param}exclude-file "{exclude_file}"' + elif os.path.isfile(os.path.join(CURRENT_DIR, os.path.basename(exclude_file))): + cmd += f' --{case_ignore_param}exclude-file "{os.path.join(CURRENT_DIR, os.path.basename(exclude_file))}"' + self.write_logs( + f"Expanding exclude file path to {CURRENT_DIR}", level="info" + ) else: self.write_logs( f"Exclude file '{exclude_file}' not found", level="error" From 915f509d8a7246a24047f0640730bade2ed4eb10 Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 21:18:46 +0200 Subject: [PATCH 6/7] Rename env variables, fixes #67 --- npbackup/core/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npbackup/core/runner.py b/npbackup/core/runner.py index 8229dc5..451f2b0 100644 --- a/npbackup/core/runner.py +++ b/npbackup/core/runner.py @@ -760,13 +760,13 @@ class NPBackupRunner: self.write_logs("Bogus additional parameters given", level="warning") try: - env_variables = self.repo_config.g("env.variables") + env_variables = self.repo_config.g("env.env_variables") if not isinstance(env_variables, list): env_variables = [env_variables] except KeyError: env_variables = [] try: - encrypted_env_variables = self.repo_config.g("env.encrypted_variables") + encrypted_env_variables = self.repo_config.g("env.encrypted_env_variables") if not isinstance(encrypted_env_variables, list): encrypted_env_variables = [encrypted_env_variables] except KeyError: From 7fbc6cfa90ea7bf06e78f9f82f33a81b3faa6673 Mon Sep 17 00:00:00 2001 From: deajan Date: Sun, 16 Jun 2024 21:55:33 +0200 Subject: [PATCH 7/7] GUI: Fix inheritance for empty strings, fixes #66 --- npbackup/configuration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/npbackup/configuration.py b/npbackup/configuration.py index 663b80c..b869872 100644 --- a/npbackup/configuration.py +++ b/npbackup/configuration.py @@ -609,15 +609,15 @@ def get_repo_config( _config_inheritance.g(key)[v] = False else: # repo_config may or may not already contain data - if _repo_config is None: + if _repo_config is None or _repo_config == "": _repo_config = CommentedMap() _config_inheritance = CommentedMap() - if _repo_config.g(key) is None: + if _repo_config.g(key) is None or _repo_config.g(key) == "": _repo_config.s(key, value) _config_inheritance.s(key, True) # Case where repo_config contains list but group info has single str elif ( - isinstance(_repo_config.g(key), list) and value is not None + isinstance(_repo_config.g(key), list) and value is not None and value != "" ): merged_lists = _repo_config.g(key) + [value]