|
@@ -17,7 +17,7 @@
|
|
|
import logging
|
|
|
|
|
|
from synapse import types
|
|
|
-from synapse.api.constants import MAX_USERID_LENGTH, LoginType
|
|
|
+from synapse.api.constants import MAX_USERID_LENGTH, EventTypes, JoinRules, LoginType
|
|
|
from synapse.api.errors import AuthError, Codes, ConsentNotGivenError, SynapseError
|
|
|
from synapse.config.server import is_threepid_reserved
|
|
|
from synapse.http.servlet import assert_params_in_dict
|
|
@@ -26,7 +26,8 @@ from synapse.replication.http.register import (
|
|
|
ReplicationPostRegisterActionsServlet,
|
|
|
ReplicationRegisterServlet,
|
|
|
)
|
|
|
-from synapse.types import RoomAlias, RoomID, UserID, create_requester
|
|
|
+from synapse.storage.state import StateFilter
|
|
|
+from synapse.types import RoomAlias, UserID, create_requester
|
|
|
from synapse.util.async_helpers import Linearizer
|
|
|
|
|
|
from ._base import BaseHandler
|
|
@@ -270,51 +271,157 @@ class RegistrationHandler(BaseHandler):
|
|
|
|
|
|
return user_id
|
|
|
|
|
|
- async def _auto_join_rooms(self, user_id):
|
|
|
- """Automatically joins users to auto join rooms - creating the room in the first place
|
|
|
- if the user is the first to be created.
|
|
|
+ async def _create_and_join_rooms(self, user_id: str):
|
|
|
+ """
|
|
|
+ Create the auto-join rooms and join or invite the user to them.
|
|
|
+
|
|
|
+ This should only be called when the first "real" user registers.
|
|
|
|
|
|
Args:
|
|
|
- user_id(str): The user to join
|
|
|
+ user_id: The user to join
|
|
|
"""
|
|
|
- # auto-join the user to any rooms we're supposed to dump them into
|
|
|
- fake_requester = create_requester(user_id)
|
|
|
+ # Getting the handlers during init gives a dependency loop.
|
|
|
+ room_creation_handler = self.hs.get_room_creation_handler()
|
|
|
+ room_member_handler = self.hs.get_room_member_handler()
|
|
|
|
|
|
- # try to create the room if we're the first real user on the server. Note
|
|
|
- # that an auto-generated support or bot user is not a real user and will never be
|
|
|
- # the user to create the room
|
|
|
- should_auto_create_rooms = False
|
|
|
- is_real_user = await self.store.is_real_user(user_id)
|
|
|
- if self.hs.config.autocreate_auto_join_rooms and is_real_user:
|
|
|
- count = await self.store.count_real_users()
|
|
|
- should_auto_create_rooms = count == 1
|
|
|
- for r in self.hs.config.auto_join_rooms:
|
|
|
+ # Generate a stub for how the rooms will be configured.
|
|
|
+ stub_config = {
|
|
|
+ "preset": self.hs.config.registration.autocreate_auto_join_room_preset,
|
|
|
+ }
|
|
|
+
|
|
|
+ # If the configuration providers a user ID to create rooms with, use
|
|
|
+ # that instead of the first user registered.
|
|
|
+ requires_join = False
|
|
|
+ if self.hs.config.registration.auto_join_user_id:
|
|
|
+ fake_requester = create_requester(
|
|
|
+ self.hs.config.registration.auto_join_user_id
|
|
|
+ )
|
|
|
+
|
|
|
+ # If the room requires an invite, add the user to the list of invites.
|
|
|
+ if self.hs.config.registration.auto_join_room_requires_invite:
|
|
|
+ stub_config["invite"] = [user_id]
|
|
|
+
|
|
|
+ # If the room is being created by a different user, the first user
|
|
|
+ # registered needs to join it. Note that in the case of an invitation
|
|
|
+ # being necessary this will occur after the invite was sent.
|
|
|
+ requires_join = True
|
|
|
+ else:
|
|
|
+ fake_requester = create_requester(user_id)
|
|
|
+
|
|
|
+ # Choose whether to federate the new room.
|
|
|
+ if not self.hs.config.registration.autocreate_auto_join_rooms_federated:
|
|
|
+ stub_config["creation_content"] = {"m.federate": False}
|
|
|
+
|
|
|
+ for r in self.hs.config.registration.auto_join_rooms:
|
|
|
logger.info("Auto-joining %s to %s", user_id, r)
|
|
|
+
|
|
|
try:
|
|
|
- if should_auto_create_rooms:
|
|
|
- room_alias = RoomAlias.from_string(r)
|
|
|
- if self.hs.hostname != room_alias.domain:
|
|
|
- logger.warning(
|
|
|
- "Cannot create room alias %s, "
|
|
|
- "it does not match server domain",
|
|
|
- r,
|
|
|
- )
|
|
|
- else:
|
|
|
- # create room expects the localpart of the room alias
|
|
|
- room_alias_localpart = room_alias.localpart
|
|
|
-
|
|
|
- # getting the RoomCreationHandler during init gives a dependency
|
|
|
- # loop
|
|
|
- await self.hs.get_room_creation_handler().create_room(
|
|
|
- fake_requester,
|
|
|
- config={
|
|
|
- "preset": "public_chat",
|
|
|
- "room_alias_name": room_alias_localpart,
|
|
|
- },
|
|
|
+ room_alias = RoomAlias.from_string(r)
|
|
|
+
|
|
|
+ if self.hs.hostname != room_alias.domain:
|
|
|
+ logger.warning(
|
|
|
+ "Cannot create room alias %s, "
|
|
|
+ "it does not match server domain",
|
|
|
+ r,
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ # A shallow copy is OK here since the only key that is
|
|
|
+ # modified is room_alias_name.
|
|
|
+ config = stub_config.copy()
|
|
|
+ # create room expects the localpart of the room alias
|
|
|
+ config["room_alias_name"] = room_alias.localpart
|
|
|
+
|
|
|
+ info, _ = await room_creation_handler.create_room(
|
|
|
+ fake_requester, config=config, ratelimit=False,
|
|
|
+ )
|
|
|
+
|
|
|
+ # If the room does not require an invite, but another user
|
|
|
+ # created it, then ensure the first user joins it.
|
|
|
+ if requires_join:
|
|
|
+ await room_member_handler.update_membership(
|
|
|
+ requester=create_requester(user_id),
|
|
|
+ target=UserID.from_string(user_id),
|
|
|
+ room_id=info["room_id"],
|
|
|
+ # Since it was just created, there are no remote hosts.
|
|
|
+ remote_room_hosts=[],
|
|
|
+ action="join",
|
|
|
ratelimit=False,
|
|
|
)
|
|
|
+
|
|
|
+ except ConsentNotGivenError as e:
|
|
|
+ # Technically not necessary to pull out this error though
|
|
|
+ # moving away from bare excepts is a good thing to do.
|
|
|
+ logger.error("Failed to join new user to %r: %r", r, e)
|
|
|
+ except Exception as e:
|
|
|
+ logger.error("Failed to join new user to %r: %r", r, e)
|
|
|
+
|
|
|
+ async def _join_rooms(self, user_id: str):
|
|
|
+ """
|
|
|
+ Join or invite the user to the auto-join rooms.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ user_id: The user to join
|
|
|
+ """
|
|
|
+ room_member_handler = self.hs.get_room_member_handler()
|
|
|
+
|
|
|
+ for r in self.hs.config.registration.auto_join_rooms:
|
|
|
+ logger.info("Auto-joining %s to %s", user_id, r)
|
|
|
+
|
|
|
+ try:
|
|
|
+ room_alias = RoomAlias.from_string(r)
|
|
|
+
|
|
|
+ if RoomAlias.is_valid(r):
|
|
|
+ (
|
|
|
+ room_id,
|
|
|
+ remote_room_hosts,
|
|
|
+ ) = await room_member_handler.lookup_room_alias(room_alias)
|
|
|
+ room_id = room_id.to_string()
|
|
|
else:
|
|
|
- await self._join_user_to_room(fake_requester, r)
|
|
|
+ raise SynapseError(
|
|
|
+ 400, "%s was not legal room ID or room alias" % (r,)
|
|
|
+ )
|
|
|
+
|
|
|
+ # 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
|
|
|
+
|
|
|
+ state = await self.store.get_filtered_current_state_ids(
|
|
|
+ room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
|
|
|
+ )
|
|
|
+
|
|
|
+ event_id = state.get((EventTypes.JoinRules, ""))
|
|
|
+ if event_id:
|
|
|
+ join_rules_event = await self.store.get_event(
|
|
|
+ event_id, allow_none=True
|
|
|
+ )
|
|
|
+ if join_rules_event:
|
|
|
+ join_rule = join_rules_event.content.get("join_rule", None)
|
|
|
+ requires_invite = join_rule and join_rule != JoinRules.PUBLIC
|
|
|
+
|
|
|
+ # Send the invite, if necessary.
|
|
|
+ if requires_invite:
|
|
|
+ await room_member_handler.update_membership(
|
|
|
+ requester=create_requester(
|
|
|
+ self.hs.config.registration.auto_join_user_id
|
|
|
+ ),
|
|
|
+ target=UserID.from_string(user_id),
|
|
|
+ room_id=room_id,
|
|
|
+ remote_room_hosts=remote_room_hosts,
|
|
|
+ action="invite",
|
|
|
+ ratelimit=False,
|
|
|
+ )
|
|
|
+
|
|
|
+ # Send the join.
|
|
|
+ await room_member_handler.update_membership(
|
|
|
+ requester=create_requester(user_id),
|
|
|
+ target=UserID.from_string(user_id),
|
|
|
+ room_id=room_id,
|
|
|
+ remote_room_hosts=remote_room_hosts,
|
|
|
+ action="join",
|
|
|
+ ratelimit=False,
|
|
|
+ )
|
|
|
+
|
|
|
except ConsentNotGivenError as e:
|
|
|
# Technically not necessary to pull out this error though
|
|
|
# moving away from bare excepts is a good thing to do.
|
|
@@ -322,6 +429,29 @@ class RegistrationHandler(BaseHandler):
|
|
|
except Exception as e:
|
|
|
logger.error("Failed to join new user to %r: %r", r, e)
|
|
|
|
|
|
+ async def _auto_join_rooms(self, user_id: str):
|
|
|
+ """Automatically joins users to auto join rooms - creating the room in the first place
|
|
|
+ if the user is the first to be created.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ user_id: The user to join
|
|
|
+ """
|
|
|
+ # auto-join the user to any rooms we're supposed to dump them into
|
|
|
+
|
|
|
+ # try to create the room if we're the first real user on the server. Note
|
|
|
+ # that an auto-generated support or bot user is not a real user and will never be
|
|
|
+ # the user to create the room
|
|
|
+ should_auto_create_rooms = False
|
|
|
+ is_real_user = await self.store.is_real_user(user_id)
|
|
|
+ if self.hs.config.registration.autocreate_auto_join_rooms and is_real_user:
|
|
|
+ count = await self.store.count_real_users()
|
|
|
+ should_auto_create_rooms = count == 1
|
|
|
+
|
|
|
+ if should_auto_create_rooms:
|
|
|
+ await self._create_and_join_rooms(user_id)
|
|
|
+ else:
|
|
|
+ await self._join_rooms(user_id)
|
|
|
+
|
|
|
async def post_consent_actions(self, user_id):
|
|
|
"""A series of registration actions that can only be carried out once consent
|
|
|
has been granted
|
|
@@ -392,30 +522,6 @@ class RegistrationHandler(BaseHandler):
|
|
|
self._next_generated_user_id += 1
|
|
|
return str(id)
|
|
|
|
|
|
- async def _join_user_to_room(self, requester, room_identifier):
|
|
|
- room_member_handler = self.hs.get_room_member_handler()
|
|
|
- if RoomID.is_valid(room_identifier):
|
|
|
- room_id = room_identifier
|
|
|
- elif RoomAlias.is_valid(room_identifier):
|
|
|
- room_alias = RoomAlias.from_string(room_identifier)
|
|
|
- room_id, remote_room_hosts = await room_member_handler.lookup_room_alias(
|
|
|
- room_alias
|
|
|
- )
|
|
|
- room_id = room_id.to_string()
|
|
|
- else:
|
|
|
- raise SynapseError(
|
|
|
- 400, "%s was not legal room ID or room alias" % (room_identifier,)
|
|
|
- )
|
|
|
-
|
|
|
- await room_member_handler.update_membership(
|
|
|
- requester=requester,
|
|
|
- target=requester.user,
|
|
|
- room_id=room_id,
|
|
|
- remote_room_hosts=remote_room_hosts,
|
|
|
- action="join",
|
|
|
- ratelimit=False,
|
|
|
- )
|
|
|
-
|
|
|
def check_registration_ratelimit(self, address):
|
|
|
"""A simple helper method to check whether the registration rate limit has been hit
|
|
|
for a given IP address
|