diff --git a/src/openflexure_microscope_server/utilities.py b/src/openflexure_microscope_server/utilities.py index c93bf6ed..c4b328d4 100644 --- a/src/openflexure_microscope_server/utilities.py +++ b/src/openflexure_microscope_server/utilities.py @@ -137,9 +137,23 @@ def make_path_safe(unsafe_path_string: str) -> str: else _POSIX_UNSAFE_PATTERN ) - for component in components: + for i, component in enumerate(components): if component in ("/", "\\"): sanitised_components.append(component) + elif component == ".": + # Only allow '.' if its the very first + # element and the next element is a separator. + # This allows for relative paths like "./file" + # but not "file./file" + is_first = i == 0 + next_to_sep = (i + 1 < len(components)) and ( + components[i + 1] in ("/", "\\") + ) + + if is_first and next_to_sep: + sanitised_components.append(component) + else: + sanitised_components.append("_") elif component: # 1. Strip trailing dots and spaces # 2. Apply unsafe character regex diff --git a/tests/unit_tests/test_utilities.py b/tests/unit_tests/test_utilities.py index 52f17c3f..84c25dc3 100644 --- a/tests/unit_tests/test_utilities.py +++ b/tests/unit_tests/test_utilities.py @@ -79,8 +79,30 @@ def test_make_path_safe_trailing_in_components(): assert make_path_safe("path /to. /file ") == "path/to/file" assert make_path_safe("path./to /file.") == "path/to/file" + # Allow dots at the start of the path + # As this is common for hidden files on POSIX and relative paths + # And is the configuration in the manual and simulation config + # json files. + assert make_path_safe("./path/to/file") == "./path/to/file" + assert make_path_safe("./path./to /file.") == "./path/to/file" + assert make_path_safe("./openflexure/data/") == "./openflexure/data/" + def test_make_path_safe_separators(): """Test that separators are preserved and components sanitised.""" assert make_path_safe("a/b\\c") == "a/b\\c" assert make_path_safe("a./b /c.") == "a/b/c" + + +def test_make_path_safe_relative(): + """Test that relative path components are preserved. + We only allow relative paths with one dot, and at the beginning of the path, + to avoid issues with paths like "file./file" or "file../file + """ + assert make_path_safe("./openflexure/data/") == "./openflexure/data/" + + assert make_path_safe("../openflexure/data/") == "_/openflexure/data/" + assert make_path_safe("path/./to/file") == "path/_/to/file" + assert make_path_safe("path/../to/file") == "path/_/to/file" + assert make_path_safe(".") == "_" + assert make_path_safe("..") == "_"