From f6a312b2d478b460a43d5405bb3d32289b774d78 Mon Sep 17 00:00:00 2001 From: Francois Lesueur Date: Mon, 2 Mar 2026 10:01:46 +0100 Subject: [PATCH 1/3] preload rights from file --- radicale/rights/from_file.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/radicale/rights/from_file.py b/radicale/rights/from_file.py index 7ebe38cf..531dec49 100644 --- a/radicale/rights/from_file.py +++ b/radicale/rights/from_file.py @@ -50,15 +50,29 @@ class Rights(rights.BaseRights): super().__init__(configuration) self._filename = configuration.get("rights", "file") self._log_rights_rule_doesnt_match_on_debug = configuration.get("logging", "rights_rule_doesnt_match_on_debug") - self._rights_config = configparser.ConfigParser() + self._rights_config_parser = configparser.ConfigParser() try: with open(self._filename, "r") as f: - self._rights_config.read_file(f) + self._rights_config_parser.read_file(f) logger.debug("Read rights file") except Exception as e: raise RuntimeError("Failed to load rights file %r: %s" % (self._filename, e)) from e + # Pre-load rights (ConfigParser is slow) + self._rights_config = {} + for section in self._rights_config_parser.sections(): + try: + user_pattern = self._rights_config_parser.get(section, "user", fallback="") + collection_pattern = self._rights_config_parser.get(section, "collection") + allowed_groups = self._rights_config_parser.get(section, "groups", fallback="").split(",") + permission = self._rights_config_parser.get(section, "permissions") + self._rights_config[section] = {"user_pattern": user_pattern, "collection_pattern": collection_pattern, + "allowed_groups": allowed_groups, "permission": permission} + except Exception as e: + raise RuntimeError("Error in section %r of rights file %r: " + "%s" % (section, self._filename, e)) from e + def authorization(self, user: str, path: str) -> str: user = user or "" sane_path = pathutils.strip_path(path) @@ -66,13 +80,13 @@ class Rights(rights.BaseRights): escaped_user = re.escape(user) if not self._log_rights_rule_doesnt_match_on_debug: logger.debug("logging of rules which doesn't match suppressed by config/option [logging] rights_rule_doesnt_match_on_debug") - for section in self._rights_config.sections(): + for section, rules in self._rights_config.items(): group_match = None user_match = None try: - user_pattern = self._rights_config.get(section, "user", fallback="") - collection_pattern = self._rights_config.get(section, "collection") - allowed_groups = self._rights_config.get(section, "groups", fallback="").split(",") + user_pattern = rules["user_pattern"] + collection_pattern = rules["collection_pattern"] + allowed_groups = rules["allowed_groups"] try: group_match = len(self._user_groups.intersection(allowed_groups)) > 0 except Exception: @@ -90,13 +104,13 @@ class Rights(rights.BaseRights): raise RuntimeError("Error in section %r of rights file %r: " "%s" % (section, self._filename, e)) from e if user_match and user_collection_match: - permission = self._rights_config.get(section, "permissions") + permission = rules["permission"] logger.debug("Rule %r:%r matches %r:%r from section %r permission %r", user, sane_path, user_pattern, collection_pattern, section, permission) return permission if group_match and group_collection_match: - permission = self._rights_config.get(section, "permissions") + permission = rules["permission"] logger.debug("Rule %r:%r matches %r:%r from section %r permission %r by group membership", user, sane_path, user_pattern, collection_pattern, section, permission) From 6288bc6f84e9a4f2b2ec5ba7d4ee5ca5551025ac Mon Sep 17 00:00:00 2001 From: Francois Lesueur Date: Mon, 2 Mar 2026 10:16:15 +0100 Subject: [PATCH 2/3] rename configparser variable --- radicale/rights/from_file.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/radicale/rights/from_file.py b/radicale/rights/from_file.py index 531dec49..84f6246e 100644 --- a/radicale/rights/from_file.py +++ b/radicale/rights/from_file.py @@ -50,10 +50,10 @@ class Rights(rights.BaseRights): super().__init__(configuration) self._filename = configuration.get("rights", "file") self._log_rights_rule_doesnt_match_on_debug = configuration.get("logging", "rights_rule_doesnt_match_on_debug") - self._rights_config_parser = configparser.ConfigParser() + rights_config_parser = configparser.ConfigParser() try: with open(self._filename, "r") as f: - self._rights_config_parser.read_file(f) + rights_config_parser.read_file(f) logger.debug("Read rights file") except Exception as e: raise RuntimeError("Failed to load rights file %r: %s" % @@ -61,12 +61,12 @@ class Rights(rights.BaseRights): # Pre-load rights (ConfigParser is slow) self._rights_config = {} - for section in self._rights_config_parser.sections(): + for section in rights_config_parser.sections(): try: - user_pattern = self._rights_config_parser.get(section, "user", fallback="") - collection_pattern = self._rights_config_parser.get(section, "collection") - allowed_groups = self._rights_config_parser.get(section, "groups", fallback="").split(",") - permission = self._rights_config_parser.get(section, "permissions") + user_pattern = rights_config_parser.get(section, "user", fallback="") + collection_pattern = rights_config_parser.get(section, "collection") + allowed_groups = rights_config_parser.get(section, "groups", fallback="").split(",") + permission = rights_config_parser.get(section, "permissions") self._rights_config[section] = {"user_pattern": user_pattern, "collection_pattern": collection_pattern, "allowed_groups": allowed_groups, "permission": permission} except Exception as e: From 15cf6ccb70f9d79869b1ca548413ecb5105dd2ab Mon Sep 17 00:00:00 2001 From: Francois Lesueur Date: Mon, 2 Mar 2026 10:34:25 +0100 Subject: [PATCH 3/3] fix typecheck --- radicale/rights/from_file.py | 1 + 1 file changed, 1 insertion(+) diff --git a/radicale/rights/from_file.py b/radicale/rights/from_file.py index 84f6246e..b0610051 100644 --- a/radicale/rights/from_file.py +++ b/radicale/rights/from_file.py @@ -45,6 +45,7 @@ from radicale.log import logger class Rights(rights.BaseRights): _filename: str + _rights_config: dict def __init__(self, configuration: config.Configuration) -> None: super().__init__(configuration)