diff --git a/CHANGELOG.md b/CHANGELOG.md index 826e6574..82c76b73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Fix: sharing: PROPFIND response on single item with bday conversion * Fix: sharing: PROPFIND response related to C:supported-calendar-component-set * Feature: conditional log of request/response header/content by new options *_on_notice_condition +* Fix: user/path validation related to 'unicode-letter' ## 3.7.2 * Fix: broken storage/mtime granularity detection on vfat diff --git a/radicale/app/base.py b/radicale/app/base.py index cd64e253..70b23346 100644 --- a/radicale/app/base.py +++ b/radicale/app/base.py @@ -41,8 +41,10 @@ PATH_PATTERN_STRICT_RE: str = "^[" + PATH_PATTERN_STRICT + "]+$" USER_BLACKLIST_MINIMAL: list = [":", "'", '"', '*', '?'] PATH_BLACKLIST_MINIMAL: list = USER_BLACKLIST_MINIMAL -USER_WHITELIST_UNICODE: list = ["-", ".", "@", "_"] # from USER_PATTERN_STRICT -PATH_WHITELIST_UNICODE: list = ["-", ".", "@", "_", "/", "~"] # from PATH_PATTERN_STRICT +BASE_WHITELIST_UNICODE: list = ["-", ".", "@", "_", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + +USER_WHITELIST_UNICODE: list = BASE_WHITELIST_UNICODE # from USER_PATTERN_STRICT +PATH_WHITELIST_UNICODE: list = BASE_WHITELIST_UNICODE + ["/", "~"] # from PATH_PATTERN_STRICT def _check_format(self: storage.BaseStorage, @@ -72,6 +74,7 @@ def _check_format(self: storage.BaseStorage, if check_unicode_letter: if c not in whitelist_unicode: if unicodedata.category(c)[0] != "L": + logger.trace("_check_format found %r (%r)", c, unicodedata.category(c)[0]) return False if check_no_unicode: if ord(c) > 255: diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index 3855e259..10f8b40d 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -647,6 +647,32 @@ permissions: RrWw""") self.get(path1, check=check_get2) self.get(path2, check=check_get1) + def test_move_letter_unicode_dst_reject(self) -> None: + """Move a item.""" + self.configure({"server": {"validate_path_value": "unicode-letter"}}) + self.mkcalendar("/calendar.ics/") + event = get_file_content("event1.ics") + path1 = "/calendar.ics/event1.ics" + path2 = "/calendar.ics/event😁2.ics" + self.put(path1, event) + self.request("MOVE", path1, check=400, + HTTP_DESTINATION="http://127.0.0.1/"+path2) + self.get(path1, check=200) + self.get(path2, check=400) + + def test_move_letter_unicode_dst_pass(self) -> None: + """Move a item.""" + self.configure({"server": {"validate_path_value": "unicode-letter"}}) + self.mkcalendar("/calendar.ics/") + event = get_file_content("event1.ics") + path1 = "/calendar.ics/event1.ics" + path2 = "/calendar.ics/event2.ics" + self.put(path1, event) + self.request("MOVE", path1, check=201, + HTTP_DESTINATION="http://127.0.0.1/"+path2) + self.get(path1, check=404) + self.get(path2, check=200) + def test_move_strict_unicode_dst(self) -> None: """Move a item.""" self.configure({"server": {"validate_path_value": "strict"}})