Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 2d91b62

Browse files
author
David Robertson
authored
Fix adding excluded users to the private room sharing tables when joining a room (#11143)
* We only need to fetch users in private rooms * Filter out `user_id` at the top * Discard excluded users in the top loop We weren't doing this in the "First, if they're our user" branch so this is a bugfix. * The caller must check that `user_id` is included This is in the docstring. There are two call sites: - one in `_handle_room_publicity_change`, which explicitly checks before calling; - and another in `_handle_room_membership_event`, which returns early if the user is excluded. So this change is safe. * Test joining a private room with an excluded user * Tweak an existing test * Changelog * test docstring * lint
1 parent 6408372 commit 2d91b62

File tree

3 files changed

+67
-29
lines changed

3 files changed

+67
-29
lines changed

changelog.d/11143.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a long-standing bug where users excluded from the directory could still be added to the `users_who_share_private_rooms` table after a regular user joins a private room.

synapse/handlers/user_directory.py

+13-15
Original file line numberDiff line numberDiff line change
@@ -373,31 +373,29 @@ async def _track_user_joined_room(self, room_id: str, user_id: str) -> None:
373373
is_public = await self.store.is_room_world_readable_or_publicly_joinable(
374374
room_id
375375
)
376-
other_users_in_room = await self.store.get_users_in_room(room_id)
377-
378376
if is_public:
379377
await self.store.add_users_in_public_rooms(room_id, (user_id,))
380378
else:
379+
users_in_room = await self.store.get_users_in_room(room_id)
380+
other_users_in_room = [
381+
other
382+
for other in users_in_room
383+
if other != user_id
384+
and (
385+
not self.is_mine_id(other)
386+
or await self.store.should_include_local_user_in_dir(other)
387+
)
388+
]
381389
to_insert = set()
382390

383391
# First, if they're our user then we need to update for every user
384392
if self.is_mine_id(user_id):
385-
if await self.store.should_include_local_user_in_dir(user_id):
386-
for other_user_id in other_users_in_room:
387-
if user_id == other_user_id:
388-
continue
389-
390-
to_insert.add((user_id, other_user_id))
393+
for other_user_id in other_users_in_room:
394+
to_insert.add((user_id, other_user_id))
391395

392396
# Next we need to update for every local user in the room
393397
for other_user_id in other_users_in_room:
394-
if user_id == other_user_id:
395-
continue
396-
397-
include_other_user = self.is_mine_id(
398-
other_user_id
399-
) and await self.store.should_include_local_user_in_dir(other_user_id)
400-
if include_other_user:
398+
if self.is_mine_id(other_user_id):
401399
to_insert.add((other_user_id, user_id))
402400

403401
if to_insert:

tests/handlers/test_user_directory.py

+53-14
Original file line numberDiff line numberDiff line change
@@ -646,22 +646,20 @@ def test_private_room(self) -> None:
646646
u2_token = self.login(u2, "pass")
647647
u3 = self.register_user("user3", "pass")
648648

649-
# We do not add users to the directory until they join a room.
649+
# u1 can't see u2 until they share a private room, or u1 is in a public room.
650650
s = self.get_success(self.handler.search_users(u1, "user2", 10))
651651
self.assertEqual(len(s["results"]), 0)
652652

653+
# Get u1 and u2 into a private room.
653654
room = self.helper.create_room_as(u1, is_public=False, tok=u1_token)
654655
self.helper.invite(room, src=u1, targ=u2, tok=u1_token)
655656
self.helper.join(room, user=u2, tok=u2_token)
656657

657658
# Check we have populated the database correctly.
658-
shares_private = self.get_success(
659-
self.user_dir_helper.get_users_who_share_private_rooms()
660-
)
661-
public_users = self.get_success(
662-
self.user_dir_helper.get_users_in_public_rooms()
659+
users, public_users, shares_private = self.get_success(
660+
self.user_dir_helper.get_tables()
663661
)
664-
662+
self.assertEqual(users, {u1, u2, u3})
665663
self.assertEqual(shares_private, {(u1, u2, room), (u2, u1, room)})
666664
self.assertEqual(public_users, set())
667665

@@ -680,14 +678,11 @@ def test_private_room(self) -> None:
680678
# User 2 then leaves.
681679
self.helper.leave(room, user=u2, tok=u2_token)
682680

683-
# Check we have removed the values.
684-
shares_private = self.get_success(
685-
self.user_dir_helper.get_users_who_share_private_rooms()
686-
)
687-
public_users = self.get_success(
688-
self.user_dir_helper.get_users_in_public_rooms()
681+
# Check this is reflected in the DB.
682+
users, public_users, shares_private = self.get_success(
683+
self.user_dir_helper.get_tables()
689684
)
690-
685+
self.assertEqual(users, {u1, u2, u3})
691686
self.assertEqual(shares_private, set())
692687
self.assertEqual(public_users, set())
693688

@@ -698,6 +693,50 @@ def test_private_room(self) -> None:
698693
s = self.get_success(self.handler.search_users(u1, "user3", 10))
699694
self.assertEqual(len(s["results"]), 0)
700695

696+
def test_joining_private_room_with_excluded_user(self) -> None:
697+
"""
698+
When a user excluded from the user directory, E say, joins a private
699+
room, E will not appear in the `users_who_share_private_rooms` table.
700+
701+
When a normal user, U say, joins a private room containing E, then
702+
U will appear in the `users_who_share_private_rooms` table, but E will
703+
not.
704+
"""
705+
# Setup a support and two normal users.
706+
alice = self.register_user("alice", "pass")
707+
alice_token = self.login(alice, "pass")
708+
bob = self.register_user("bob", "pass")
709+
bob_token = self.login(bob, "pass")
710+
support = "@support1:test"
711+
self.get_success(
712+
self.store.register_user(
713+
user_id=support, password_hash=None, user_type=UserTypes.SUPPORT
714+
)
715+
)
716+
717+
# Alice makes a room. Inject the support user into the room.
718+
room = self.helper.create_room_as(alice, is_public=False, tok=alice_token)
719+
self.get_success(inject_member_event(self.hs, room, support, "join"))
720+
# Check the DB state. The support user should not be in the directory.
721+
users, in_public, in_private = self.get_success(
722+
self.user_dir_helper.get_tables()
723+
)
724+
self.assertEqual(users, {alice, bob})
725+
self.assertEqual(in_public, set())
726+
self.assertEqual(in_private, set())
727+
728+
# Then invite Bob, who accepts.
729+
self.helper.invite(room, alice, bob, tok=alice_token)
730+
self.helper.join(room, bob, tok=bob_token)
731+
732+
# Check the DB state. The support user should not be in the directory.
733+
users, in_public, in_private = self.get_success(
734+
self.user_dir_helper.get_tables()
735+
)
736+
self.assertEqual(users, {alice, bob})
737+
self.assertEqual(in_public, set())
738+
self.assertEqual(in_private, {(alice, bob, room), (bob, alice, room)})
739+
701740
def test_spam_checker(self) -> None:
702741
"""
703742
A user which fails the spam checks will not appear in search results.

0 commit comments

Comments
 (0)