From 6a89541c2ce2da3085b9998557fd13e019599ee3 Mon Sep 17 00:00:00 2001 From: Mathieu Velten Date: Fri, 8 Nov 2024 10:35:33 +0100 Subject: [PATCH] Allow switching an encrypted room from public to non public --- room_access_rules/__init__.py | 13 ++++++--- tests/test_event_allowed.py | 54 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/room_access_rules/__init__.py b/room_access_rules/__init__.py index b8da083..9416d2b 100644 --- a/room_access_rules/__init__.py +++ b/room_access_rules/__init__.py @@ -881,8 +881,9 @@ def _on_join_rule_change( ) -> bool: """Check whether a join rule change is allowed. - A join rule change is always allowed unless the new join rule is "public" and - the current access rule is "direct". + A join rule change is always allowed unless: + - the new join rule is "public" and the current access rule is "direct" + - the existing join rule is "public" and the room is not encrypted Args: event: The event to check. @@ -894,8 +895,12 @@ def _on_join_rule_change( if event.content.get("join_rule") == JoinRules.PUBLIC: return rule != AccessRules.DIRECT - if self._get_join_rule_from_state(state_events) == JoinRules.PUBLIC: - return False + if ( + self._get_join_rule_from_state(state_events) == JoinRules.PUBLIC + and event.content.get("join_rule") != JoinRules.PUBLIC + ): + if not state_events.get((EventTypes.RoomEncryption, "")): + return False return True diff --git a/tests/test_event_allowed.py b/tests/test_event_allowed.py index 3b446c7..f9a09d5 100644 --- a/tests/test_event_allowed.py +++ b/tests/test_event_allowed.py @@ -48,6 +48,13 @@ def setUp(self) -> None: content=self.module._get_default_power_levels(self.room_creator), room_id=self.direct_room, ), + (EventTypes.JoinRules, ""): MockEvent( + sender=self.room_creator, + type=EventTypes.JoinRules, + state_key="", + content={"join_rule": JoinRules.PRIVATE}, + room_id=self.direct_room, + ), (ACCESS_RULES_TYPE, ""): MockEvent( sender=self.room_creator, type=ACCESS_RULES_TYPE, @@ -80,6 +87,13 @@ def setUp(self) -> None: content=self.module._get_default_power_levels(self.room_creator), room_id=self.unrestricted_room, ), + (EventTypes.JoinRules, ""): MockEvent( + sender=self.room_creator, + type=EventTypes.JoinRules, + state_key="", + content={"join_rule": JoinRules.PUBLIC}, + room_id=self.unrestricted_room, + ), (ACCESS_RULES_TYPE, ""): MockEvent( sender=self.room_creator, type=ACCESS_RULES_TYPE, @@ -105,6 +119,13 @@ def setUp(self) -> None: content=self.module._get_default_power_levels(self.room_creator), room_id=self.restricted_room, ), + (EventTypes.JoinRules, ""): MockEvent( + sender=self.room_creator, + type=EventTypes.JoinRules, + state_key="", + content={"join_rule": JoinRules.PRIVATE}, + room_id=self.restricted_room, + ), (ACCESS_RULES_TYPE, ""): MockEvent( sender=self.room_creator, type=ACCESS_RULES_TYPE, @@ -729,6 +750,39 @@ async def test_join_rules(self): ) ) + # the existing join rule is "public" and the room is not encrypted + allowed, _ = await self.module.check_event_allowed( + event=MockEvent( + sender=self.room_creator, + type=EventTypes.JoinRules, + content={"join_rule": JoinRules.PRIVATE}, + state_key="", + ), + state_events=self.unrestricted_room_state, + ) + self.assertFalse(allowed) + + # the existing join rule is "public" and the room is encrypted + allowed, _ = await self.module.check_event_allowed( + event=MockEvent( + sender=self.room_creator, + type=EventTypes.JoinRules, + content={"join_rule": JoinRules.PRIVATE}, + state_key="", + ), + state_events=self.unrestricted_room_state + | { + (EventTypes.RoomEncryption, ""): MockEvent( + sender=self.room_creator, + type=EventTypes.RoomEncryption, + state_key="", + content={"algorithm": "m.megolm.v1.aes-sha2"}, + room_id=self.unrestricted_room, + ) + }, + ) + self.assertTrue(allowed) + def _new_membership_event( self, src: str,