From 978032141b0255b08116bdcaadd903eda56f782e Mon Sep 17 00:00:00 2001 From: Kegan Dougal <7190048+kegsay@users.noreply.github.com> Date: Tue, 10 Jun 2025 15:11:49 +0100 Subject: [PATCH] bugfix: ensure _get_power_level_for_sender works when there is no PL event (#18534) --- changelog.d/18534.bugfix | 1 + synapse/state/v2.py | 14 ++++- tests/state/test_v2.py | 118 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 changelog.d/18534.bugfix diff --git a/changelog.d/18534.bugfix b/changelog.d/18534.bugfix new file mode 100644 index 000000000..ee1bfc8f2 --- /dev/null +++ b/changelog.d/18534.bugfix @@ -0,0 +1 @@ +Fix an issue where during state resolution for v11 rooms Synapse would incorrectly calculate the power level of the creator when there was no power levels event in the room. diff --git a/synapse/state/v2.py b/synapse/state/v2.py index d0c0a9fc9..11e80df42 100644 --- a/synapse/state/v2.py +++ b/synapse/state/v2.py @@ -254,7 +254,19 @@ async def _get_power_level_for_sender( room_id, aid, event_map, state_res_store, allow_none=True ) if aev and (aev.type, aev.state_key) == (EventTypes.Create, ""): - if aev.content.get("creator") == event.sender: + creator = ( + event.sender + if event.room_version.implicit_room_creator + else aev.content.get("creator") + ) + if not creator: + logger.warning( + "_get_power_level_for_sender: event %s has no PL in auth_events and " + "creator is missing from create event %s", + event_id, + aev.event_id, + ) + if creator == event.sender: return 100 break return 0 diff --git a/tests/state/test_v2.py b/tests/state/test_v2.py index 0b70f779d..968c1ff64 100644 --- a/tests/state/test_v2.py +++ b/tests/state/test_v2.py @@ -41,6 +41,7 @@ from synapse.event_auth import auth_types_for_event from synapse.events import EventBase, make_event_from_dict from synapse.state.v2 import ( _get_auth_chain_difference, + _get_power_level_for_sender, lexicographical_topological_sort, resolve_events_with_store, ) @@ -863,6 +864,123 @@ class AuthChainDifferenceTestCase(unittest.TestCase): self.assertEqual(difference, {d.event_id, e.event_id}) + def test_get_power_level_for_sender(self) -> None: + """Test that we use the correct definition of `creator` depending + on room version""" + store = TestStateResolutionStore({}) + for room_version in [RoomVersions.V10, RoomVersions.V11]: + create_event = make_event_from_dict( + { + "room_id": ROOM_ID, + "sender": ALICE, + "type": EventTypes.Create, + "state_key": "", + "content": { + "room_version": room_version.identifier, + } + # conditionally add 'creator' if the version doesn't use implicit room creators + | ( + {"creator": ALICE} + if not room_version.implicit_room_creator + else {} + ), + }, + room_version, + ) + member_event = make_event_from_dict( + { + "room_id": ROOM_ID, + "sender": ALICE, + "type": EventTypes.Member, + "state_key": ALICE, + "content": { + "membership": "join", + }, + "auth_events": [create_event.event_id], + "prev_events": [create_event.event_id], + }, + room_version, + ) + pl_event = make_event_from_dict( + { + "room_id": ROOM_ID, + "sender": ALICE, + "type": EventTypes.PowerLevels, + "state_key": "", + "content": { + "users": { + ALICE: 100, + BOB: 50, + }, + "users_default": 10, + }, + "auth_events": [create_event.event_id, member_event.event_id], + "prev_events": [member_event.event_id], + }, + room_version, + ) + + event_map = { + create_event.event_id: create_event, + member_event.event_id: member_event, + pl_event.event_id: pl_event, + } + want_pls = { + ALICE: 100, + BOB: 50, + CHARLIE: 10, + } + for user_id, want_pl in want_pls.items(): + test_event = make_event_from_dict( + { + "room_id": ROOM_ID, + "sender": user_id, + "type": EventTypes.Topic, + "state_key": "", + "content": {"topic": "Test"}, + "auth_events": [ + create_event.event_id, + member_event.event_id, + pl_event.event_id, + ], + "prev_events": [pl_event.event_id], + }, + room_version, + ) + event_map[test_event.event_id] = test_event + got_pl = self.successResultOf( + defer.ensureDeferred( + _get_power_level_for_sender( + ROOM_ID, test_event.event_id, event_map, store + ) + ) + ) + self.assertEqual( + got_pl, + want_pl, + f"wrong pl for {user_id} on v{room_version.identifier}", + ) + + # the creator alone without PL is 100 + got_creator_pl = self.successResultOf( + defer.ensureDeferred( + _get_power_level_for_sender( + ROOM_ID, + member_event.event_id, + { + member_event.event_id: member_event, + create_event.event_id: create_event, + }, + store, + ) + ) + ) + self.assertEqual( + got_creator_pl, + 100, + f"wrong pl for creator with no PL event on v{room_version.identifier}", + ) + T = TypeVar("T")