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

Improve the reliability of auto-joining remote rooms #10237

Merged
merged 9 commits into from
Jun 23, 2021
1 change: 1 addition & 0 deletions changelog.d/10237.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve the reliability of auto-joining remote rooms.
44 changes: 39 additions & 5 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,32 @@ async def _create_and_join_rooms(self, user_id: str) -> None:
room_alias = RoomAlias.from_string(r)

if self.hs.hostname != room_alias.domain:
# If the alias is remote, try to join the room. This might fail
# because the room might be invite only, but we don't have any local
# user in the room to invite this one with, so at this point that's
# the best we can do.
logger.warning(
"Cannot create room alias %s, "
"it does not match server domain",
"Cannot automatically create room with alias %s as it isn't"
" local, trying to join the room instead",
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:
# A shallow copy is OK here since the only key that is
# modified is room_alias_name.
Expand Down Expand Up @@ -448,9 +469,15 @@ async def _join_rooms(self, user_id: str) -> None:
)

# Calculate whether the room requires an invite or can be
# joined directly. Note that unless a join rule of public exists,
# it is treated as requiring an invite.
requires_invite = True
# joined directly. By default, we consider the room as requiring an
# invite if the homeserver is in the room (unless told otherwise by the
# 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.
hosts_in_room = await self.state_handler.get_current_hosts_in_room(
room_id
)
requires_invite = self.server_name in hosts_in_room

state = await self.store.get_filtered_current_state_ids(
room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
Expand All @@ -465,6 +492,13 @@ async def _join_rooms(self, user_id: str) -> None:
join_rule = join_rules_event.content.get("join_rule", None)
requires_invite = join_rule and join_rule != JoinRules.PUBLIC

if requires_invite and self.server_name not in hosts_in_room:
raise SynapseError(
400,
"Auto-join room is invite only but there are no local"
" user to invite with",
)

# Send the invite, if necessary.
if requires_invite:
# If an invite is required, there must be a auto-join user ID.
Expand Down