From b7a2e9fc35afd97796538056cd9803b7887dfe5b Mon Sep 17 00:00:00 2001 From: Charlie Calendre <57274151+c-cal@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:55:50 +0100 Subject: [PATCH 1/5] fix: unfreeze notification_levels for the Rust implementation of PushRuleEvaluator, which can't handle immutabledict --- synapse/push/bulk_push_rule_evaluator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/synapse/push/bulk_push_rule_evaluator.py b/synapse/push/bulk_push_rule_evaluator.py index 8c106f9649b..36453615608 100644 --- a/synapse/push/bulk_push_rule_evaluator.py +++ b/synapse/push/bulk_push_rule_evaluator.py @@ -59,6 +59,7 @@ from synapse.util import unwrapFirstError from synapse.util.async_helpers import gather_results from synapse.util.caches import register_cache +from synapse.util.frozenutils import unfreeze from synapse.util.metrics import measure_func from synapse.visibility import filter_event_for_clients_with_state @@ -412,7 +413,7 @@ async def _action_for_event_by_user( # Note that this is done automatically for the sender's power level by # _get_power_levels_and_sender_level in its call to get_user_power_level # (even for room V10.) - notification_levels = power_levels.get("notifications", {}) + notification_levels = unfreeze(power_levels.get("notifications", {})) if not event.room_version.enforce_int_power_levels: keys = list(notification_levels.keys()) for key in keys: From 6edb079f9133c80514f8099214db6cc8a22d3f01 Mon Sep 17 00:00:00 2001 From: c-cal Date: Mon, 20 Jan 2025 16:34:18 +0100 Subject: [PATCH 2/5] add a changelog entry --- changelog.d/18103.bugfix | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/18103.bugfix diff --git a/changelog.d/18103.bugfix b/changelog.d/18103.bugfix new file mode 100644 index 00000000000..11000d569fd --- /dev/null +++ b/changelog.d/18103.bugfix @@ -0,0 +1,3 @@ +Fixed a bug that disturbed room creation when a check_event_allowed callback was registered by a module and power_level Notifications mapping exists. + +Contributed by @c-cal From 81969523d4d95428e4a13edb651b50a6ee0aa16b Mon Sep 17 00:00:00 2001 From: c-cal Date: Fri, 31 Jan 2025 18:31:06 +0100 Subject: [PATCH 3/5] Revert "fix: unfreeze notification_levels for the Rust implementation of PushRuleEvaluator, which can't handle immutabledict" This reverts commit b7a2e9fc35afd97796538056cd9803b7887dfe5b. --- synapse/push/bulk_push_rule_evaluator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/synapse/push/bulk_push_rule_evaluator.py b/synapse/push/bulk_push_rule_evaluator.py index 36453615608..8c106f9649b 100644 --- a/synapse/push/bulk_push_rule_evaluator.py +++ b/synapse/push/bulk_push_rule_evaluator.py @@ -59,7 +59,6 @@ from synapse.util import unwrapFirstError from synapse.util.async_helpers import gather_results from synapse.util.caches import register_cache -from synapse.util.frozenutils import unfreeze from synapse.util.metrics import measure_func from synapse.visibility import filter_event_for_clients_with_state @@ -413,7 +412,7 @@ async def _action_for_event_by_user( # Note that this is done automatically for the sender's power level by # _get_power_levels_and_sender_level in its call to get_user_power_level # (even for room V10.) - notification_levels = unfreeze(power_levels.get("notifications", {})) + notification_levels = power_levels.get("notifications", {}) if not event.room_version.enforce_int_power_levels: keys = list(notification_levels.keys()) for key in keys: From c637a3c92bf960a1255c4bdc411a777579e8cd3d Mon Sep 17 00:00:00 2001 From: c-cal Date: Fri, 31 Jan 2025 19:00:23 +0100 Subject: [PATCH 4/5] add event.unfreeze method --- synapse/events/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/synapse/events/__init__.py b/synapse/events/__init__.py index 8e9d27138ca..85d1f63bbc7 100644 --- a/synapse/events/__init__.py +++ b/synapse/events/__init__.py @@ -47,7 +47,7 @@ from synapse.synapse_rust.events import EventInternalMetadata from synapse.types import JsonDict, StrCollection from synapse.util.caches import intern_dict -from synapse.util.frozenutils import freeze +from synapse.util.frozenutils import freeze, unfreeze from synapse.util.stringutils import strtobool if TYPE_CHECKING: @@ -319,6 +319,12 @@ def freeze(self) -> None: # this will be a no-op if the event dict is already frozen. self._dict = freeze(self._dict) + def unfreeze(self) -> None: + """'Unfreeze' the event dict, so it can be modified afterwards""" + + # this will be a no-op if the event dict is already unfrozen. + self._dict = unfreeze(self._dict) + def __str__(self) -> str: return self.__repr__() From c8a4628d0333161863f2f769c51c3c751baab191 Mon Sep 17 00:00:00 2001 From: c-cal Date: Fri, 31 Jan 2025 19:03:58 +0100 Subject: [PATCH 5/5] unfreeze event after executing all check_event_allowed callbacks --- .../callbacks/third_party_event_rules_callbacks.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/synapse/module_api/callbacks/third_party_event_rules_callbacks.py b/synapse/module_api/callbacks/third_party_event_rules_callbacks.py index 9f7a04372de..6672f780ccc 100644 --- a/synapse/module_api/callbacks/third_party_event_rules_callbacks.py +++ b/synapse/module_api/callbacks/third_party_event_rules_callbacks.py @@ -293,6 +293,9 @@ async def check_event_allowed( # the hashes and signatures. event.freeze() + allow = True + event_dict = None + for callback in self._check_event_allowed_callbacks: try: res, replacement_data = await delay_cancellation( @@ -318,11 +321,15 @@ async def check_event_allowed( # Return if the event shouldn't be allowed or if the module came up with a # replacement dict for the event. if res is False: - return res, None + allow = False + break elif isinstance(replacement_data, dict): - return True, replacement_data + event_dict = replacement_data + break + + event.unfreeze() - return True, None + return allow, event_dict async def on_create_room( self, requester: Requester, config: dict, is_requester_admin: bool