From fa40dee36ac79ab6810cc565c67a4b4fa3a8ef69 Mon Sep 17 00:00:00 2001 From: Nir Date: Wed, 19 Jun 2024 16:04:07 +0300 Subject: [PATCH] New: is_allowed_path() in FileManager New test: test_file_manager_is_allowed_path() Changes: 1. check if source is in allowed folder when copy 2. use new is_allowed_path() as part of is_protected_path() to make sure it keep being correct over time --- duplicate_files_in_folders/file_manager.py | 24 +++++++++++++++++++--- tests/test_file_manager.py | 24 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/duplicate_files_in_folders/file_manager.py b/duplicate_files_in_folders/file_manager.py index a6d8474..ee777d0 100644 --- a/duplicate_files_in_folders/file_manager.py +++ b/duplicate_files_in_folders/file_manager.py @@ -84,9 +84,23 @@ def is_protected_path(self, path: str | Path) -> bool: raise FileManagerError("Protected directories not set") # True if the path is in any of the protected directories or if it is not in any of the allowed directories - return any(path == protected_dir or protected_dir in path.parents for protected_dir in self.protected_dirs) or \ - (self.allowed_dirs and not any(path == allowed_dir or allowed_dir in path.parents for allowed_dir - in self.allowed_dirs)) + # use is_allowed_path instead of the second condition to avoid a circular dependency + return any(path == protected_dir or protected_dir in path.parents for protected_dir in self.protected_dirs) \ + or not self.is_allowed_path(path) + + def is_allowed_path(self, path: str | Path) -> bool: + """ + Check if a path is in an allowed directory or in a subdirectory of an allowed directory + If allowed_dirs is empty, all paths are allowed + :param path: path to check + :return: True if the path is in an allowed directory or in a subdirectory of an allowed directory + """ + path = Path(path).resolve() + if not self.allowed_dirs: + return True # If allowed_dirs is an empty set, all paths are allowed + + # True if the path is in any of the allowed directories + return any(path == allowed_dir or allowed_dir in path.parents for allowed_dir in self.allowed_dirs) def move_file(self, src: str, dst: str) -> bool: """ @@ -126,6 +140,9 @@ def copy_file(self, src: str, dst: str) -> bool: if self.is_protected_path(dst_path): raise ProtectedPathError( f"Operation not allowed: Attempt to copy file to protected directory: {src} -> {dst}") + if not self.is_allowed_path(src_path): + raise ProtectedPathError( + f"Operation not allowed: Attempt to copy file from disallowed directory: {src} -> {dst}") src_to_dst = f"{src_path} to {dst_path}" if self.run_mode: @@ -323,6 +340,7 @@ def any_is_subfolder_of(folders: List[str]) -> Tuple[bool, List[Tuple[str, str]] :param folders: list of folder paths :return: Tuple containing a boolean and a list of subfolder relationships """ + folders = [str(Path(folder).resolve()) for folder in folders] subfolder_pairs = [] for i in range(len(folders)): for j in range(len(folders)): diff --git a/tests/test_file_manager.py b/tests/test_file_manager.py index 10af61f..ee147e8 100644 --- a/tests/test_file_manager.py +++ b/tests/test_file_manager.py @@ -298,6 +298,30 @@ def test_file_manager_any_is_subfolder_of(): assert is_subfolder is False +def test_file_manager_is_allowed_path(): + fm = FileManager(True).reset_all() + fm.add_protected_dir("C:\\Users\\user\\Desktop\\folder") + fm.add_protected_dir("C:\\Users\\user\\Desktop\\folder1") + fm.add_allowed_dir("C:\\Users\\user\\Desktop\\folder2") + + # Test case 1: protected path + assert not fm.is_allowed_path("C:\\Users\\user\\Desktop\\folder\\subfolder") + + # Test case 2: protected path + assert not fm.is_allowed_path("C:\\Users\\user\\Desktop\\folder1\\subfolder") + + # Test case 3: allowed path + assert fm.is_allowed_path("C:\\Users\\user\\Desktop\\folder2\\subfolder") + + # Test case 4: non-protected path - should be disallowed as allowed directories are set + assert not fm.is_allowed_path("C:\\Users\\user\\Desktop\\folder3\\subfolder") + + fm = FileManager(True).reset_all() + # Test case 5: no protected or allowed directories set - all paths should be allowed + assert fm.is_allowed_path("C:\\Users\\user\\Desktop\\folder3\\subfolder") + assert not fm.is_protected_path("C:\\Users\\user\\Desktop\\folder3\\subfolder") + + def test_python_source_files(): """ Test all python files in the project under duplicate_files_in_folders folder. Make sure that all python files