diff --git a/changelog.d/7376.bugfix b/changelog.d/7376.bugfix
new file mode 100644
index 0000000000..b7b67e328e
--- /dev/null
+++ b/changelog.d/7376.bugfix
@@ -0,0 +1 @@
+Fix a bug which could cause messages not to be sent over federation, when state events with state keys matching user IDs (such as custom user statuses) were received.
diff --git a/synapse/storage/data_stores/main/roommember.py b/synapse/storage/data_stores/main/roommember.py
index d5bd0cb5cf..e626b7f6f7 100644
--- a/synapse/storage/data_stores/main/roommember.py
+++ b/synapse/storage/data_stores/main/roommember.py
@@ -576,7 +576,8 @@ class RoomMemberWorkerStore(EventsWorkerStore):
if key[0] == EventTypes.Member
]
for etype, state_key in context.delta_ids:
- users_in_room.pop(state_key, None)
+ if etype == EventTypes.Member:
+ users_in_room.pop(state_key, None)
# We check if we have any of the member event ids in the event cache
# before we ask the DB
diff --git a/tests/storage/test_roommember.py b/tests/storage/test_roommember.py
index 00df0ea68e..5dd46005e6 100644
--- a/tests/storage/test_roommember.py
+++ b/tests/storage/test_roommember.py
@@ -22,6 +22,8 @@ from synapse.rest.client.v1 import login, room
from synapse.types import Requester, UserID
from tests import unittest
+from tests.test_utils import event_injection
+from tests.utils import TestHomeServer
class RoomMemberStoreTestCase(unittest.HomeserverTestCase):
@@ -38,7 +40,7 @@ class RoomMemberStoreTestCase(unittest.HomeserverTestCase):
)
return hs
- def prepare(self, reactor, clock, hs):
+ def prepare(self, reactor, clock, hs: TestHomeServer):
# We can't test the RoomMemberStore on its own without the other event
# storage logic
@@ -114,6 +116,52 @@ class RoomMemberStoreTestCase(unittest.HomeserverTestCase):
# It now knows about Charlie's server.
self.assertEqual(self.store._known_servers_count, 2)
+ def test_get_joined_users_from_context(self):
+ room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
+ bob_event = event_injection.inject_member_event(
+ self.hs, room, self.u_bob, Membership.JOIN
+ )
+
+ # first, create a regular event
+ event, context = event_injection.create_event(
+ self.hs,
+ room_id=room,
+ sender=self.u_alice,
+ prev_event_ids=[bob_event.event_id],
+ type="m.test.1",
+ content={},
+ )
+
+ users = self.get_success(
+ self.store.get_joined_users_from_context(event, context)
+ )
+ self.assertEqual(users.keys(), {self.u_alice, self.u_bob})
+
+ # Regression test for #7376: create a state event whose key matches bob's
+ # user_id, but which is *not* a membership event, and persist that; then check
+ # that `get_joined_users_from_context` returns the correct users for the next event.
+ non_member_event = event_injection.inject_event(
+ self.hs,
+ room_id=room,
+ sender=self.u_bob,
+ prev_event_ids=[bob_event.event_id],
+ type="m.test.2",
+ state_key=self.u_bob,
+ content={},
+ )
+ event, context = event_injection.create_event(
+ self.hs,
+ room_id=room,
+ sender=self.u_alice,
+ prev_event_ids=[non_member_event.event_id],
+ type="m.test.3",
+ content={},
+ )
+ users = self.get_success(
+ self.store.get_joined_users_from_context(event, context)
+ )
+ self.assertEqual(users.keys(), {self.u_alice, self.u_bob})
+
class CurrentStateMembershipUpdateTestCase(unittest.HomeserverTestCase):
def prepare(self, reactor, clock, homeserver):
|