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

Commit e19e3d4

Browse files
authored
Improve the reliability of auto-joining remote rooms (#10237)
If a room is remote and we don't have a user in it, always try to join it. It might fail if the room is invite-only, but we don't have a user to invite with, so at this point it's the best we can do. Fixes #10233 (at least to some extent)
1 parent 8beead6 commit e19e3d4

File tree

3 files changed

+96
-17
lines changed

3 files changed

+96
-17
lines changed

changelog.d/10237.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve the reliability of auto-joining remote rooms.

synapse/handlers/register.py

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,32 @@ async def _create_and_join_rooms(self, user_id: str) -> None:
386386
room_alias = RoomAlias.from_string(r)
387387

388388
if self.hs.hostname != room_alias.domain:
389-
logger.warning(
390-
"Cannot create room alias %s, "
391-
"it does not match server domain",
389+
# If the alias is remote, try to join the room. This might fail
390+
# because the room might be invite only, but we don't have any local
391+
# user in the room to invite this one with, so at this point that's
392+
# the best we can do.
393+
logger.info(
394+
"Cannot automatically create room with alias %s as it isn't"
395+
" local, trying to join the room instead",
392396
r,
393397
)
398+
399+
(
400+
room,
401+
remote_room_hosts,
402+
) = await room_member_handler.lookup_room_alias(room_alias)
403+
room_id = room.to_string()
404+
405+
await room_member_handler.update_membership(
406+
requester=create_requester(
407+
user_id, authenticated_entity=self._server_name
408+
),
409+
target=UserID.from_string(user_id),
410+
room_id=room_id,
411+
remote_room_hosts=remote_room_hosts,
412+
action="join",
413+
ratelimit=False,
414+
)
394415
else:
395416
# A shallow copy is OK here since the only key that is
396417
# modified is room_alias_name.
@@ -448,22 +469,32 @@ async def _join_rooms(self, user_id: str) -> None:
448469
)
449470

450471
# Calculate whether the room requires an invite or can be
451-
# joined directly. Note that unless a join rule of public exists,
452-
# it is treated as requiring an invite.
453-
requires_invite = True
454-
455-
state = await self.store.get_filtered_current_state_ids(
456-
room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
472+
# joined directly. By default, we consider the room as requiring an
473+
# invite if the homeserver is in the room (unless told otherwise by the
474+
# join rules). Otherwise we consider it as being joinable, at the risk of
475+
# failing to join, but in this case there's little more we can do since
476+
# we don't have a local user in the room to craft up an invite with.
477+
requires_invite = await self.store.is_host_joined(
478+
room_id,
479+
self.server_name,
457480
)
458481

459-
event_id = state.get((EventTypes.JoinRules, ""))
460-
if event_id:
461-
join_rules_event = await self.store.get_event(
462-
event_id, allow_none=True
482+
if requires_invite:
483+
# If the server is in the room, check if the room is public.
484+
state = await self.store.get_filtered_current_state_ids(
485+
room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
463486
)
464-
if join_rules_event:
465-
join_rule = join_rules_event.content.get("join_rule", None)
466-
requires_invite = join_rule and join_rule != JoinRules.PUBLIC
487+
488+
event_id = state.get((EventTypes.JoinRules, ""))
489+
if event_id:
490+
join_rules_event = await self.store.get_event(
491+
event_id, allow_none=True
492+
)
493+
if join_rules_event:
494+
join_rule = join_rules_event.content.get("join_rule", None)
495+
requires_invite = (
496+
join_rule and join_rule != JoinRules.PUBLIC
497+
)
467498

468499
# Send the invite, if necessary.
469500
if requires_invite:

tests/handlers/test_register.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from synapse.api.constants import UserTypes
1919
from synapse.api.errors import Codes, ResourceLimitError, SynapseError
2020
from synapse.spam_checker_api import RegistrationBehaviour
21-
from synapse.types import RoomAlias, UserID, create_requester
21+
from synapse.types import RoomAlias, RoomID, UserID, create_requester
2222

2323
from tests.test_utils import make_awaitable
2424
from tests.unittest import override_config
@@ -643,3 +643,50 @@ async def get_or_create_user(
643643
)
644644

645645
return user_id, token
646+
647+
648+
class RemoteAutoJoinTestCase(unittest.HomeserverTestCase):
649+
"""Tests auto-join on remote rooms."""
650+
651+
def make_homeserver(self, reactor, clock):
652+
self.room_id = "!roomid:remotetest"
653+
654+
async def update_membership(*args, **kwargs):
655+
pass
656+
657+
async def lookup_room_alias(*args, **kwargs):
658+
return RoomID.from_string(self.room_id), ["remotetest"]
659+
660+
self.room_member_handler = Mock(spec=["update_membership", "lookup_room_alias"])
661+
self.room_member_handler.update_membership.side_effect = update_membership
662+
self.room_member_handler.lookup_room_alias.side_effect = lookup_room_alias
663+
664+
hs = self.setup_test_homeserver(room_member_handler=self.room_member_handler)
665+
return hs
666+
667+
def prepare(self, reactor, clock, hs):
668+
self.handler = self.hs.get_registration_handler()
669+
self.store = self.hs.get_datastore()
670+
671+
@override_config({"auto_join_rooms": ["#room:remotetest"]})
672+
def test_auto_create_auto_join_remote_room(self):
673+
"""Tests that we don't attempt to create remote rooms, and that we don't attempt
674+
to invite ourselves to rooms we're not in."""
675+
676+
# Register a first user; this should call _create_and_join_rooms
677+
self.get_success(self.handler.register_user(localpart="jeff"))
678+
679+
_, kwargs = self.room_member_handler.update_membership.call_args
680+
681+
self.assertEqual(kwargs["room_id"], self.room_id)
682+
self.assertEqual(kwargs["action"], "join")
683+
self.assertEqual(kwargs["remote_room_hosts"], ["remotetest"])
684+
685+
# Register a second user; this should call _join_rooms
686+
self.get_success(self.handler.register_user(localpart="jeff2"))
687+
688+
_, kwargs = self.room_member_handler.update_membership.call_args
689+
690+
self.assertEqual(kwargs["room_id"], self.room_id)
691+
self.assertEqual(kwargs["action"], "join")
692+
self.assertEqual(kwargs["remote_room_hosts"], ["remotetest"])

0 commit comments

Comments
 (0)