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)pull/10242/head
parent
8beead66ae
commit
e19e3d452d
|
@ -0,0 +1 @@
|
||||||
|
Improve the reliability of auto-joining remote rooms.
|
|
@ -386,11 +386,32 @@ class RegistrationHandler(BaseHandler):
|
||||||
room_alias = RoomAlias.from_string(r)
|
room_alias = RoomAlias.from_string(r)
|
||||||
|
|
||||||
if self.hs.hostname != room_alias.domain:
|
if self.hs.hostname != room_alias.domain:
|
||||||
logger.warning(
|
# If the alias is remote, try to join the room. This might fail
|
||||||
"Cannot create room alias %s, "
|
# because the room might be invite only, but we don't have any local
|
||||||
"it does not match server domain",
|
# user in the room to invite this one with, so at this point that's
|
||||||
|
# the best we can do.
|
||||||
|
logger.info(
|
||||||
|
"Cannot automatically create room with alias %s as it isn't"
|
||||||
|
" local, trying to join the room instead",
|
||||||
r,
|
r,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
room,
|
||||||
|
remote_room_hosts,
|
||||||
|
) = await room_member_handler.lookup_room_alias(room_alias)
|
||||||
|
room_id = room.to_string()
|
||||||
|
|
||||||
|
await room_member_handler.update_membership(
|
||||||
|
requester=create_requester(
|
||||||
|
user_id, authenticated_entity=self._server_name
|
||||||
|
),
|
||||||
|
target=UserID.from_string(user_id),
|
||||||
|
room_id=room_id,
|
||||||
|
remote_room_hosts=remote_room_hosts,
|
||||||
|
action="join",
|
||||||
|
ratelimit=False,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# A shallow copy is OK here since the only key that is
|
# A shallow copy is OK here since the only key that is
|
||||||
# modified is room_alias_name.
|
# modified is room_alias_name.
|
||||||
|
@ -448,10 +469,18 @@ class RegistrationHandler(BaseHandler):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate whether the room requires an invite or can be
|
# Calculate whether the room requires an invite or can be
|
||||||
# joined directly. Note that unless a join rule of public exists,
|
# joined directly. By default, we consider the room as requiring an
|
||||||
# it is treated as requiring an invite.
|
# invite if the homeserver is in the room (unless told otherwise by the
|
||||||
requires_invite = True
|
# join rules). Otherwise we consider it as being joinable, at the risk of
|
||||||
|
# failing to join, but in this case there's little more we can do since
|
||||||
|
# we don't have a local user in the room to craft up an invite with.
|
||||||
|
requires_invite = await self.store.is_host_joined(
|
||||||
|
room_id,
|
||||||
|
self.server_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
if requires_invite:
|
||||||
|
# If the server is in the room, check if the room is public.
|
||||||
state = await self.store.get_filtered_current_state_ids(
|
state = await self.store.get_filtered_current_state_ids(
|
||||||
room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
|
room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
|
||||||
)
|
)
|
||||||
|
@ -463,7 +492,9 @@ class RegistrationHandler(BaseHandler):
|
||||||
)
|
)
|
||||||
if join_rules_event:
|
if join_rules_event:
|
||||||
join_rule = join_rules_event.content.get("join_rule", None)
|
join_rule = join_rules_event.content.get("join_rule", None)
|
||||||
requires_invite = join_rule and join_rule != JoinRules.PUBLIC
|
requires_invite = (
|
||||||
|
join_rule and join_rule != JoinRules.PUBLIC
|
||||||
|
)
|
||||||
|
|
||||||
# Send the invite, if necessary.
|
# Send the invite, if necessary.
|
||||||
if requires_invite:
|
if requires_invite:
|
||||||
|
|
|
@ -18,7 +18,7 @@ from synapse.api.auth import Auth
|
||||||
from synapse.api.constants import UserTypes
|
from synapse.api.constants import UserTypes
|
||||||
from synapse.api.errors import Codes, ResourceLimitError, SynapseError
|
from synapse.api.errors import Codes, ResourceLimitError, SynapseError
|
||||||
from synapse.spam_checker_api import RegistrationBehaviour
|
from synapse.spam_checker_api import RegistrationBehaviour
|
||||||
from synapse.types import RoomAlias, UserID, create_requester
|
from synapse.types import RoomAlias, RoomID, UserID, create_requester
|
||||||
|
|
||||||
from tests.test_utils import make_awaitable
|
from tests.test_utils import make_awaitable
|
||||||
from tests.unittest import override_config
|
from tests.unittest import override_config
|
||||||
|
@ -643,3 +643,50 @@ class RegistrationTestCase(unittest.HomeserverTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
return user_id, token
|
return user_id, token
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteAutoJoinTestCase(unittest.HomeserverTestCase):
|
||||||
|
"""Tests auto-join on remote rooms."""
|
||||||
|
|
||||||
|
def make_homeserver(self, reactor, clock):
|
||||||
|
self.room_id = "!roomid:remotetest"
|
||||||
|
|
||||||
|
async def update_membership(*args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def lookup_room_alias(*args, **kwargs):
|
||||||
|
return RoomID.from_string(self.room_id), ["remotetest"]
|
||||||
|
|
||||||
|
self.room_member_handler = Mock(spec=["update_membership", "lookup_room_alias"])
|
||||||
|
self.room_member_handler.update_membership.side_effect = update_membership
|
||||||
|
self.room_member_handler.lookup_room_alias.side_effect = lookup_room_alias
|
||||||
|
|
||||||
|
hs = self.setup_test_homeserver(room_member_handler=self.room_member_handler)
|
||||||
|
return hs
|
||||||
|
|
||||||
|
def prepare(self, reactor, clock, hs):
|
||||||
|
self.handler = self.hs.get_registration_handler()
|
||||||
|
self.store = self.hs.get_datastore()
|
||||||
|
|
||||||
|
@override_config({"auto_join_rooms": ["#room:remotetest"]})
|
||||||
|
def test_auto_create_auto_join_remote_room(self):
|
||||||
|
"""Tests that we don't attempt to create remote rooms, and that we don't attempt
|
||||||
|
to invite ourselves to rooms we're not in."""
|
||||||
|
|
||||||
|
# Register a first user; this should call _create_and_join_rooms
|
||||||
|
self.get_success(self.handler.register_user(localpart="jeff"))
|
||||||
|
|
||||||
|
_, kwargs = self.room_member_handler.update_membership.call_args
|
||||||
|
|
||||||
|
self.assertEqual(kwargs["room_id"], self.room_id)
|
||||||
|
self.assertEqual(kwargs["action"], "join")
|
||||||
|
self.assertEqual(kwargs["remote_room_hosts"], ["remotetest"])
|
||||||
|
|
||||||
|
# Register a second user; this should call _join_rooms
|
||||||
|
self.get_success(self.handler.register_user(localpart="jeff2"))
|
||||||
|
|
||||||
|
_, kwargs = self.room_member_handler.update_membership.call_args
|
||||||
|
|
||||||
|
self.assertEqual(kwargs["room_id"], self.room_id)
|
||||||
|
self.assertEqual(kwargs["action"], "join")
|
||||||
|
self.assertEqual(kwargs["remote_room_hosts"], ["remotetest"])
|
||||||
|
|
Loading…
Reference in New Issue