Beispiel #1
0
    async def on_DELETE(self, request: SynapseRequest,
                        room_alias: str) -> Tuple[int, JsonDict]:
        if not RoomAlias.is_valid(room_alias):
            raise SynapseError(400,
                               "Room alias invalid",
                               errcode=Codes.INVALID_PARAM)
        room_alias_obj = RoomAlias.from_string(room_alias)
        requester = await self.auth.get_user_by_req(request)

        if requester.app_service:
            await self.directory_handler.delete_appservice_association(
                requester.app_service, room_alias_obj)

            logger.info(
                "Application service at %s deleted alias %s",
                requester.app_service.url,
                room_alias_obj.to_string(),
            )

        else:
            await self.directory_handler.delete_association(
                requester, room_alias_obj)

            logger.info(
                "User %s deleted alias %s",
                requester.user.to_string(),
                room_alias_obj.to_string(),
            )

        return 200, {}
Beispiel #2
0
    async def on_PUT(self, request: SynapseRequest,
                     room_alias: str) -> Tuple[int, JsonDict]:
        if not RoomAlias.is_valid(room_alias):
            raise SynapseError(400,
                               "Room alias invalid",
                               errcode=Codes.INVALID_PARAM)
        room_alias_obj = RoomAlias.from_string(room_alias)

        content = parse_json_object_from_request(request)
        if "room_id" not in content:
            raise SynapseError(400,
                               'Missing params: ["room_id"]',
                               errcode=Codes.BAD_JSON)

        logger.debug("Got content: %s", content)
        logger.debug("Got room name: %s", room_alias_obj.to_string())

        room_id = content["room_id"]
        servers = content["servers"] if "servers" in content else None

        logger.debug("Got room_id: %s", room_id)
        logger.debug("Got servers: %s", servers)

        # TODO(erikj): Check types.

        room = await self.store.get_room(room_id)
        if room is None:
            raise SynapseError(400, "Room does not exist")

        requester = await self.auth.get_user_by_req(request)

        await self.directory_handler.create_association(
            requester, room_alias_obj, room_id, servers)

        return 200, {}
Beispiel #3
0
    def read_config(self, config):
        self.enable_registration = bool(
            strtobool(str(config["enable_registration"]))
        )
        if "disable_registration" in config:
            self.enable_registration = not bool(
                strtobool(str(config["disable_registration"]))
            )

        self.registrations_require_3pid = config.get("registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.registration_shared_secret = config.get("registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config["trusted_third_party_id_servers"]
        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        self.invite_3pid_guest = (
            self.allow_guest_access and config.get("invite_3pid_guest", False)
        )

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError('Invalid auto_join_rooms entry %s' % (room_alias,))
        self.autocreate_auto_join_rooms = config.get("autocreate_auto_join_rooms", True)
Beispiel #4
0
    def read_config(self, config):
        self.enable_registration = bool(
            strtobool(str(config["enable_registration"])))
        if "disable_registration" in config:
            self.enable_registration = not bool(
                strtobool(str(config["disable_registration"])))

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config[
            "trusted_third_party_id_servers"]
        self.allow_guest_access = config.get("allow_guest_access", False)

        self.invite_3pid_guest = (self.allow_guest_access
                                  and config.get("invite_3pid_guest", False))

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError('Invalid auto_join_rooms entry %s' %
                                  (room_alias, ))
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)
Beispiel #5
0
    async def on_POST(self, request, room_identifier):
        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)

        content = parse_json_object_from_request(request)

        assert_params_in_dict(content, ["user_id"])
        target_user = UserID.from_string(content["user_id"])

        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "This endpoint can only be used with local users")

        if not await self.admin_handler.get_user(target_user):
            raise NotFoundError("User not found")

        if RoomID.is_valid(room_identifier):
            room_id = room_identifier
            try:
                remote_room_hosts = [
                    x.decode("ascii") for x in request.args[b"server_name"]
                ]  # type: Optional[List[str]]
            except Exception:
                remote_room_hosts = None
        elif RoomAlias.is_valid(room_identifier):
            handler = self.room_member_handler
            room_alias = RoomAlias.from_string(room_identifier)
            room_id, remote_room_hosts = await 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,)
            )

        fake_requester = create_requester(target_user)

        # send invite if room has "JoinRules.INVITE"
        room_state = await self.state_handler.get_current_state(room_id)
        join_rules_event = room_state.get((EventTypes.JoinRules, ""))
        if join_rules_event:
            if not (join_rules_event.content.get("join_rule") == JoinRules.PUBLIC):
                await self.room_member_handler.update_membership(
                    requester=requester,
                    target=fake_requester.user,
                    room_id=room_id,
                    action="invite",
                    remote_room_hosts=remote_room_hosts,
                    ratelimit=False,
                )

        await self.room_member_handler.update_membership(
            requester=fake_requester,
            target=fake_requester.user,
            room_id=room_id,
            action="join",
            remote_room_hosts=remote_room_hosts,
            ratelimit=False,
        )

        return 200, {"room_id": room_id}
Beispiel #6
0
    def read_config(self, config, **kwargs):
        self.enable_registration = bool(
            strtobool(str(config.get("enable_registration", False))))
        if "disable_registration" in config:
            self.enable_registration = not bool(
                strtobool(str(config["disable_registration"])))

        self.account_validity = AccountValidityConfig(
            config.get("account_validity") or {}, config)

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config.get(
            "trusted_third_party_id_servers", ["matrix.org", "vector.im"])
        account_threepid_delegates = config.get(
            "account_threepid_delegates") or {}
        self.account_threepid_delegate_email = account_threepid_delegates.get(
            "email")
        self.account_threepid_delegate_msisdn = account_threepid_delegates.get(
            "msisdn")
        if self.account_threepid_delegate_msisdn and not self.public_baseurl:
            raise ConfigError(
                "The configuration option `public_baseurl` is required if "
                "`account_threepid_delegate.msisdn` is set, such that "
                "clients know where to submit validation tokens to. Please "
                "configure `public_baseurl`.")

        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        if config.get("invite_3pid_guest", False):
            raise ConfigError("invite_3pid_guest is no longer supported")

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError("Invalid auto_join_rooms entry %s" %
                                  (room_alias, ))
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)

        self.enable_set_displayname = config.get("enable_set_displayname",
                                                 True)
        self.enable_set_avatar_url = config.get("enable_set_avatar_url", True)
        self.enable_3pid_changes = config.get("enable_3pid_changes", True)

        self.disable_msisdn_registration = config.get(
            "disable_msisdn_registration", False)

        session_lifetime = config.get("session_lifetime")
        if session_lifetime is not None:
            session_lifetime = self.parse_duration(session_lifetime)
        self.session_lifetime = session_lifetime
Beispiel #7
0
    async def on_GET(self, request: Request,
                     room_alias: str) -> Tuple[int, JsonDict]:
        if not RoomAlias.is_valid(room_alias):
            raise SynapseError(400,
                               "Room alias invalid",
                               errcode=Codes.INVALID_PARAM)
        room_alias_obj = RoomAlias.from_string(room_alias)

        res = await self.directory_handler.get_association(room_alias_obj)

        return 200, res
Beispiel #8
0
    def read_config(self, config, **kwargs):
        self.enable_registration = bool(
            strtobool(str(config.get("enable_registration", False))))
        if "disable_registration" in config:
            self.enable_registration = not bool(
                strtobool(str(config["disable_registration"])))

        self.account_validity = AccountValidityConfig(
            config.get("account_validity", {}), config)

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config.get(
            "trusted_third_party_id_servers", ["matrix.org", "vector.im"])
        account_threepid_delegates = config.get(
            "account_threepid_delegates") or {}
        self.account_threepid_delegate_email = account_threepid_delegates.get(
            "email")
        self.account_threepid_delegate_msisdn = account_threepid_delegates.get(
            "msisdn")

        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        if config.get("invite_3pid_guest", False):
            raise ConfigError("invite_3pid_guest is no longer supported")

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError("Invalid auto_join_rooms entry %s" %
                                  (room_alias, ))
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)

        self.disable_msisdn_registration = config.get(
            "disable_msisdn_registration", False)

        session_lifetime = config.get("session_lifetime")
        if session_lifetime is not None:
            session_lifetime = self.parse_duration(session_lifetime)
        self.session_lifetime = session_lifetime
Beispiel #9
0
 async def resolve_room_id(self, room_identifier: str) -> str:
     """Resolve to a room ID, if necessary."""
     if RoomID.is_valid(room_identifier):
         resolved_room_id = room_identifier
     elif RoomAlias.is_valid(room_identifier):
         room_alias = RoomAlias.from_string(room_identifier)
         room_id, _ = await self.room_member_handler.lookup_room_alias(
             room_alias)
         resolved_room_id = room_id.to_string()
     else:
         raise SynapseError(
             400,
             "%s was not legal room ID or room alias" % (room_identifier, ))
     if not resolved_room_id:
         raise SynapseError(
             400, "Unknown room ID or room alias %s" % room_identifier)
     return resolved_room_id
Beispiel #10
0
    async def on_POST(
        self,
        request: SynapseRequest,
        room_identifier: str,
        txn_id: Optional[str] = None,
    ) -> Tuple[int, JsonDict]:
        requester = await self.auth.get_user_by_req(request)

        content = parse_json_object_from_request(request)
        event_content = None
        if "reason" in content:
            event_content = {"reason": content["reason"]}

        if RoomID.is_valid(room_identifier):
            room_id = room_identifier

            # twisted.web.server.Request.args is incorrectly defined as Optional[Any]
            args: Dict[bytes, List[bytes]] = request.args  # type: ignore

            remote_room_hosts = parse_strings_from_args(args,
                                                        "server_name",
                                                        required=False)
        elif RoomAlias.is_valid(room_identifier):
            handler = self.room_member_handler
            room_alias = RoomAlias.from_string(room_identifier)
            room_id_obj, remote_room_hosts = await handler.lookup_room_alias(
                room_alias)
            room_id = room_id_obj.to_string()
        else:
            raise SynapseError(
                400,
                "%s was not legal room ID or room alias" % (room_identifier, ))

        await self.room_member_handler.update_membership(
            requester=requester,
            target=requester.user,
            room_id=room_id,
            action=Membership.KNOCK,
            txn_id=txn_id,
            third_party_signed=None,
            remote_room_hosts=remote_room_hosts,
            content=event_content,
        )

        return 200, {"room_id": room_id}
Beispiel #11
0
    def on_POST(self, request, room_identifier, txn_id=None):
        requester = yield self.auth.get_user_by_req(
            request,
            allow_guest=True,
        )

        try:
            content = parse_json_object_from_request(request)
        except Exception:
            # Turns out we used to ignore the body entirely, and some clients
            # cheekily send invalid bodies.
            content = {}

        if RoomID.is_valid(room_identifier):
            room_id = room_identifier
            try:
                remote_room_hosts = [
                    x.decode('ascii') for x in request.args[b"server_name"]
                ]
            except Exception:
                remote_room_hosts = None
        elif RoomAlias.is_valid(room_identifier):
            handler = self.room_member_handler
            room_alias = RoomAlias.from_string(room_identifier)
            room_id, remote_room_hosts = yield 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, ))

        yield self.room_member_handler.update_membership(
            requester=requester,
            target=requester.user,
            room_id=room_id,
            action="join",
            txn_id=txn_id,
            remote_room_hosts=remote_room_hosts,
            content=content,
            third_party_signed=content.get("third_party_signed", None),
        )

        defer.returnValue((200, {"room_id": room_id}))
Beispiel #12
0
    def on_POST(self, request, room_identifier, txn_id=None):
        requester = yield self.auth.get_user_by_req(
            request,
            allow_guest=True,
        )

        try:
            content = parse_json_object_from_request(request)
        except Exception:
            # Turns out we used to ignore the body entirely, and some clients
            # cheekily send invalid bodies.
            content = {}

        if RoomID.is_valid(room_identifier):
            room_id = room_identifier
            try:
                remote_room_hosts = [
                    x.decode('ascii') for x in request.args[b"server_name"]
                ]
            except Exception:
                remote_room_hosts = None
        elif RoomAlias.is_valid(room_identifier):
            handler = self.room_member_handler
            room_alias = RoomAlias.from_string(room_identifier)
            room_id, remote_room_hosts = yield 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,
            ))

        yield self.room_member_handler.update_membership(
            requester=requester,
            target=requester.user,
            room_id=room_id,
            action="join",
            txn_id=txn_id,
            remote_room_hosts=remote_room_hosts,
            content=content,
            third_party_signed=content.get("third_party_signed", None),
        )

        defer.returnValue((200, {"room_id": room_id}))
Beispiel #13
0
    def _join_user_to_room(self, requester, room_identifier):
        room_id = None
        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 = (
                yield self.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, ))

        yield self.room_member_handler.update_membership(
            requester=requester,
            target=requester.user,
            room_id=room_id,
            action="join",
        )
Beispiel #14
0
    async def resolve_room_id(
        self,
        room_identifier: str,
        remote_room_hosts: Optional[List[str]] = None
    ) -> Tuple[str, Optional[List[str]]]:
        """
        Resolve a room identifier to a room ID, if necessary.

        This also performanes checks to ensure the room ID is of the proper form.

        Args:
            room_identifier: The room ID or alias.
            remote_room_hosts: The potential remote room hosts to use.

        Returns:
            The resolved room ID.

        Raises:
            SynapseError if the room ID is of the wrong form.
        """
        if RoomID.is_valid(room_identifier):
            resolved_room_id = room_identifier
        elif RoomAlias.is_valid(room_identifier):
            room_alias = RoomAlias.from_string(room_identifier)
            (
                room_id,
                remote_room_hosts,
            ) = await self.room_member_handler.lookup_room_alias(room_alias)
            resolved_room_id = room_id.to_string()
        else:
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "%s was not legal room ID or room alias" % (room_identifier, ),
            )
        if not resolved_room_id:
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Unknown room ID or room alias %s" % room_identifier,
            )
        return resolved_room_id, remote_room_hosts
Beispiel #15
0
    def read_config(self, config):
        self.enable_registration = bool(
            strtobool(str(config.get("enable_registration", False))))
        if "disable_registration" in config:
            self.enable_registration = not bool(
                strtobool(str(config["disable_registration"])))

        self.account_validity = AccountValidityConfig(
            config.get("account_validity", {}),
            config,
        )

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config.get(
            "trusted_third_party_id_servers",
            ["matrix.org", "vector.im"],
        )
        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        self.invite_3pid_guest = (self.allow_guest_access
                                  and config.get("invite_3pid_guest", False))

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError('Invalid auto_join_rooms entry %s' %
                                  (room_alias, ))
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)

        self.disable_msisdn_registration = (config.get(
            "disable_msisdn_registration", False))
Beispiel #16
0
    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,
        )
Beispiel #17
0
    def _join_user_to_room(self, requester, room_identifier):
        room_id = None
        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 = (
                yield 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,
            ))

        yield room_member_handler.update_membership(
            requester=requester,
            target=requester.user,
            room_id=room_id,
            remote_room_hosts=remote_room_hosts,
            action="join",
        )
Beispiel #18
0
    def read_config(self, config, **kwargs):
        self.enable_registration = strtobool(
            str(config.get("enable_registration", False)))
        if "disable_registration" in config:
            self.enable_registration = not strtobool(
                str(config["disable_registration"]))

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
        self.registration_requires_token = config.get(
            "registration_requires_token", False)
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config.get(
            "trusted_third_party_id_servers", ["matrix.org", "vector.im"])
        account_threepid_delegates = config.get(
            "account_threepid_delegates") or {}
        self.account_threepid_delegate_email = account_threepid_delegates.get(
            "email")
        self.account_threepid_delegate_msisdn = account_threepid_delegates.get(
            "msisdn")
        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        if config.get("invite_3pid_guest", False):
            raise ConfigError("invite_3pid_guest is no longer supported")

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError("Invalid auto_join_rooms entry %s" %
                                  (room_alias, ))

        # Options for creating auto-join rooms if they do not exist yet.
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)
        self.autocreate_auto_join_rooms_federated = config.get(
            "autocreate_auto_join_rooms_federated", True)
        self.autocreate_auto_join_room_preset = (
            config.get("autocreate_auto_join_room_preset")
            or RoomCreationPreset.PUBLIC_CHAT)
        self.auto_join_room_requires_invite = self.autocreate_auto_join_room_preset in {
            RoomCreationPreset.PRIVATE_CHAT,
            RoomCreationPreset.TRUSTED_PRIVATE_CHAT,
        }

        # Pull the creator/inviter from the configuration, this gets used to
        # send invites for invite-only rooms.
        mxid_localpart = config.get("auto_join_mxid_localpart")
        self.auto_join_user_id = None
        if mxid_localpart:
            # Convert the localpart to a full mxid.
            self.auto_join_user_id = UserID(
                mxid_localpart, self.root.server.server_name).to_string()

        if self.autocreate_auto_join_rooms:
            # Ensure the preset is a known value.
            if self.autocreate_auto_join_room_preset not in {
                    RoomCreationPreset.PUBLIC_CHAT,
                    RoomCreationPreset.PRIVATE_CHAT,
                    RoomCreationPreset.TRUSTED_PRIVATE_CHAT,
            }:
                raise ConfigError(
                    "Invalid value for autocreate_auto_join_room_preset")
            # If the preset requires invitations to be sent, ensure there's a
            # configured user to send them from.
            if self.auto_join_room_requires_invite:
                if not mxid_localpart:
                    raise ConfigError(
                        "The configuration option `auto_join_mxid_localpart` is required if "
                        "`autocreate_auto_join_room_preset` is set to private_chat or trusted_private_chat, such that "
                        "Synapse knows who to send invitations from. Please "
                        "configure `auto_join_mxid_localpart`.")

        self.auto_join_rooms_for_guests = config.get(
            "auto_join_rooms_for_guests", True)

        self.enable_set_displayname = config.get("enable_set_displayname",
                                                 True)
        self.enable_set_avatar_url = config.get("enable_set_avatar_url", True)
        self.enable_3pid_changes = config.get("enable_3pid_changes", True)

        self.disable_msisdn_registration = config.get(
            "disable_msisdn_registration", False)

        session_lifetime = config.get("session_lifetime")
        if session_lifetime is not None:
            session_lifetime = self.parse_duration(session_lifetime)
        self.session_lifetime = session_lifetime

        # The `access_token_lifetime` applies for tokens that can be renewed
        # using a refresh token, as per MSC2918. If it is `None`, the refresh
        # token mechanism is disabled.
        #
        # Since it is incompatible with the `session_lifetime` mechanism, it is set to
        # `None` by default if a `session_lifetime` is set.
        access_token_lifetime = config.get(
            "access_token_lifetime",
            "5m" if session_lifetime is None else None)
        if access_token_lifetime is not None:
            access_token_lifetime = self.parse_duration(access_token_lifetime)
        self.access_token_lifetime = access_token_lifetime

        if session_lifetime is not None and access_token_lifetime is not None:
            raise ConfigError(
                "The refresh token mechanism is incompatible with the "
                "`session_lifetime` option. Consider disabling the "
                "`session_lifetime` option or disabling the refresh token "
                "mechanism by removing the `access_token_lifetime` option.")

        # The fallback template used for authenticating using a registration token
        self.registration_token_template = self.read_template(
            "registration_token.html")

        # The success template used during fallback auth.
        self.fallback_success_template = self.read_template(
            "auth_success.html")
Beispiel #19
0
    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:
                    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.
                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)
Beispiel #20
0
    def read_config(self, config, **kwargs):
        self.enable_registration = strtobool(
            str(config.get("enable_registration", False)))
        if "disable_registration" in config:
            self.enable_registration = not strtobool(
                str(config["disable_registration"]))

        self.account_validity = AccountValidityConfig(
            config.get("account_validity") or {}, config)

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
        self.trusted_third_party_id_servers = config.get(
            "trusted_third_party_id_servers", ["matrix.org", "vector.im"])
        account_threepid_delegates = config.get(
            "account_threepid_delegates") or {}
        self.account_threepid_delegate_email = account_threepid_delegates.get(
            "email")
        self.account_threepid_delegate_msisdn = account_threepid_delegates.get(
            "msisdn")
        if self.account_threepid_delegate_msisdn and not self.public_baseurl:
            raise ConfigError(
                "The configuration option `public_baseurl` is required if "
                "`account_threepid_delegate.msisdn` is set, such that "
                "clients know where to submit validation tokens to. Please "
                "configure `public_baseurl`.")

        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        if config.get("invite_3pid_guest", False):
            raise ConfigError("invite_3pid_guest is no longer supported")

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError("Invalid auto_join_rooms entry %s" %
                                  (room_alias, ))

        # Options for creating auto-join rooms if they do not exist yet.
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)
        self.autocreate_auto_join_rooms_federated = config.get(
            "autocreate_auto_join_rooms_federated", True)
        self.autocreate_auto_join_room_preset = (
            config.get("autocreate_auto_join_room_preset")
            or RoomCreationPreset.PUBLIC_CHAT)
        self.auto_join_room_requires_invite = self.autocreate_auto_join_room_preset in {
            RoomCreationPreset.PRIVATE_CHAT,
            RoomCreationPreset.TRUSTED_PRIVATE_CHAT,
        }

        # Pull the creator/inviter from the configuration, this gets used to
        # send invites for invite-only rooms.
        mxid_localpart = config.get("auto_join_mxid_localpart")
        self.auto_join_user_id = None
        if mxid_localpart:
            # Convert the localpart to a full mxid.
            self.auto_join_user_id = UserID(mxid_localpart,
                                            self.server_name).to_string()

        if self.autocreate_auto_join_rooms:
            # Ensure the preset is a known value.
            if self.autocreate_auto_join_room_preset not in {
                    RoomCreationPreset.PUBLIC_CHAT,
                    RoomCreationPreset.PRIVATE_CHAT,
                    RoomCreationPreset.TRUSTED_PRIVATE_CHAT,
            }:
                raise ConfigError(
                    "Invalid value for autocreate_auto_join_room_preset")
            # If the preset requires invitations to be sent, ensure there's a
            # configured user to send them from.
            if self.auto_join_room_requires_invite:
                if not mxid_localpart:
                    raise ConfigError(
                        "The configuration option `auto_join_mxid_localpart` is required if "
                        "`autocreate_auto_join_room_preset` is set to private_chat or trusted_private_chat, such that "
                        "Synapse knows who to send invitations from. Please "
                        "configure `auto_join_mxid_localpart`.")

        self.auto_join_rooms_for_guests = config.get(
            "auto_join_rooms_for_guests", True)

        self.enable_set_displayname = config.get("enable_set_displayname",
                                                 True)
        self.enable_set_avatar_url = config.get("enable_set_avatar_url", True)
        self.enable_3pid_changes = config.get("enable_3pid_changes", True)

        self.disable_msisdn_registration = config.get(
            "disable_msisdn_registration", False)

        session_lifetime = config.get("session_lifetime")
        if session_lifetime is not None:
            session_lifetime = self.parse_duration(session_lifetime)
        self.session_lifetime = session_lifetime

        # The success template used during fallback auth.
        self.fallback_success_template = self.read_template(
            "auth_success.html")
Beispiel #21
0
    async def on_POST(self, request, room_identifier):
        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)
        content = parse_json_object_from_request(request,
                                                 allow_empty_body=True)

        # Resolve to a room ID, if necessary.
        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, _ = await self.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, ))

        # Which user to grant room admin rights to.
        user_to_add = content.get("user_id", requester.user.to_string())

        # Figure out which local users currently have power in the room, if any.
        room_state = await self.state_handler.get_current_state(room_id)
        if not room_state:
            raise SynapseError(400, "Server not in room")

        create_event = room_state[(EventTypes.Create, "")]
        power_levels = room_state.get((EventTypes.PowerLevels, ""))

        if power_levels is not None:
            # We pick the local user with the highest power.
            user_power = power_levels.content.get("users", {})
            admin_users = [
                user_id for user_id in user_power if self.is_mine_id(user_id)
            ]
            admin_users.sort(key=lambda user: user_power[user])

            if not admin_users:
                raise SynapseError(400, "No local admin user in room")

            admin_user_id = None

            for admin_user in reversed(admin_users):
                if room_state.get((EventTypes.Member, admin_user)):
                    admin_user_id = admin_user
                    break

            if not admin_user_id:
                raise SynapseError(
                    400,
                    "No local admin user in room",
                )

            pl_content = power_levels.content
        else:
            # If there is no power level events then the creator has rights.
            pl_content = {}
            admin_user_id = create_event.sender
            if not self.is_mine_id(admin_user_id):
                raise SynapseError(
                    400,
                    "No local admin user in room",
                )

        # Grant the user power equal to the room admin by attempting to send an
        # updated power level event.
        new_pl_content = dict(pl_content)
        new_pl_content["users"] = dict(pl_content.get("users", {}))
        new_pl_content["users"][user_to_add] = new_pl_content["users"][
            admin_user_id]

        fake_requester = create_requester(
            admin_user_id,
            authenticated_entity=requester.authenticated_entity,
        )

        try:
            await self.event_creation_handler.create_and_send_nonmember_event(
                fake_requester,
                event_dict={
                    "content": new_pl_content,
                    "sender": admin_user_id,
                    "type": EventTypes.PowerLevels,
                    "state_key": "",
                    "room_id": room_id,
                },
            )
        except AuthError:
            # The admin user we found turned out not to have enough power.
            raise SynapseError(
                400,
                "No local admin user in room with power to update power levels."
            )

        # Now we check if the user we're granting admin rights to is already in
        # the room. If not and it's not a public room we invite them.
        member_event = room_state.get((EventTypes.Member, user_to_add))
        is_joined = False
        if member_event:
            is_joined = member_event.content["membership"] in (
                Membership.JOIN,
                Membership.INVITE,
            )

        if is_joined:
            return 200, {}

        join_rules = room_state.get((EventTypes.JoinRules, ""))
        is_public = False
        if join_rules:
            is_public = join_rules.content.get("join_rule") == JoinRules.PUBLIC

        if is_public:
            return 200, {}

        await self.room_member_handler.update_membership(
            fake_requester,
            target=UserID.from_string(user_to_add),
            room_id=room_id,
            action=Membership.INVITE,
        )

        return 200, {}
Beispiel #22
0
 def test_validate(self):
     id_string = "#test:domain,test"
     self.assertFalse(RoomAlias.is_valid(id_string))
Beispiel #23
0
    def read_config(self, config: JsonDict, **kwargs: Any) -> None:
        self.enable_registration = strtobool(
            str(config.get("enable_registration", False)))
        if "disable_registration" in config:
            self.enable_registration = not strtobool(
                str(config["disable_registration"]))

        self.enable_registration_without_verification = strtobool(
            str(config.get("enable_registration_without_verification", False)))

        self.registrations_require_3pid = config.get(
            "registrations_require_3pid", [])
        self.allowed_local_3pids = config.get("allowed_local_3pids", [])
        self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
        self.registration_requires_token = config.get(
            "registration_requires_token", False)
        self.enable_registration_token_3pid_bypass = config.get(
            "enable_registration_token_3pid_bypass", False)
        self.registration_shared_secret = config.get(
            "registration_shared_secret")

        self.bcrypt_rounds = config.get("bcrypt_rounds", 12)

        account_threepid_delegates = config.get(
            "account_threepid_delegates") or {}
        self.account_threepid_delegate_email = account_threepid_delegates.get(
            "email")
        self.account_threepid_delegate_msisdn = account_threepid_delegates.get(
            "msisdn")
        self.default_identity_server = config.get("default_identity_server")
        self.allow_guest_access = config.get("allow_guest_access", False)

        if config.get("invite_3pid_guest", False):
            raise ConfigError("invite_3pid_guest is no longer supported")

        self.auto_join_rooms = config.get("auto_join_rooms", [])
        for room_alias in self.auto_join_rooms:
            if not RoomAlias.is_valid(room_alias):
                raise ConfigError("Invalid auto_join_rooms entry %s" %
                                  (room_alias, ))

        # Options for creating auto-join rooms if they do not exist yet.
        self.autocreate_auto_join_rooms = config.get(
            "autocreate_auto_join_rooms", True)
        self.autocreate_auto_join_rooms_federated = config.get(
            "autocreate_auto_join_rooms_federated", True)
        self.autocreate_auto_join_room_preset = (
            config.get("autocreate_auto_join_room_preset")
            or RoomCreationPreset.PUBLIC_CHAT)
        self.auto_join_room_requires_invite = self.autocreate_auto_join_room_preset in {
            RoomCreationPreset.PRIVATE_CHAT,
            RoomCreationPreset.TRUSTED_PRIVATE_CHAT,
        }

        # Pull the creator/inviter from the configuration, this gets used to
        # send invites for invite-only rooms.
        mxid_localpart = config.get("auto_join_mxid_localpart")
        self.auto_join_user_id = None
        if mxid_localpart:
            # Convert the localpart to a full mxid.
            self.auto_join_user_id = UserID(
                mxid_localpart, self.root.server.server_name).to_string()

        if self.autocreate_auto_join_rooms:
            # Ensure the preset is a known value.
            if self.autocreate_auto_join_room_preset not in {
                    RoomCreationPreset.PUBLIC_CHAT,
                    RoomCreationPreset.PRIVATE_CHAT,
                    RoomCreationPreset.TRUSTED_PRIVATE_CHAT,
            }:
                raise ConfigError(
                    "Invalid value for autocreate_auto_join_room_preset")
            # If the preset requires invitations to be sent, ensure there's a
            # configured user to send them from.
            if self.auto_join_room_requires_invite:
                if not mxid_localpart:
                    raise ConfigError(
                        "The configuration option `auto_join_mxid_localpart` is required if "
                        "`autocreate_auto_join_room_preset` is set to private_chat or trusted_private_chat, such that "
                        "Synapse knows who to send invitations from. Please "
                        "configure `auto_join_mxid_localpart`.")

        self.auto_join_rooms_for_guests = config.get(
            "auto_join_rooms_for_guests", True)

        self.enable_set_displayname = config.get("enable_set_displayname",
                                                 True)
        self.enable_set_avatar_url = config.get("enable_set_avatar_url", True)
        self.enable_3pid_changes = config.get("enable_3pid_changes", True)

        self.disable_msisdn_registration = config.get(
            "disable_msisdn_registration", False)

        session_lifetime = config.get("session_lifetime")
        if session_lifetime is not None:
            session_lifetime = self.parse_duration(session_lifetime)
        self.session_lifetime = session_lifetime

        # The `refreshable_access_token_lifetime` applies for tokens that can be renewed
        # using a refresh token, as per MSC2918.
        # If it is `None`, the refresh token mechanism is disabled.
        refreshable_access_token_lifetime = config.get(
            "refreshable_access_token_lifetime",
            "5m",
        )
        if refreshable_access_token_lifetime is not None:
            refreshable_access_token_lifetime = self.parse_duration(
                refreshable_access_token_lifetime)
        self.refreshable_access_token_lifetime: Optional[
            int] = refreshable_access_token_lifetime

        if (self.session_lifetime is not None
                and "refreshable_access_token_lifetime" in config):
            if self.session_lifetime < self.refreshable_access_token_lifetime:
                raise ConfigError(
                    "Both `session_lifetime` and `refreshable_access_token_lifetime` "
                    "configuration options have been set, but `refreshable_access_token_lifetime` "
                    " exceeds `session_lifetime`!")

        # The `nonrefreshable_access_token_lifetime` applies for tokens that can NOT be
        # refreshed using a refresh token.
        # If it is None, then these tokens last for the entire length of the session,
        # which is infinite by default.
        # The intention behind this configuration option is to help with requiring
        # all clients to use refresh tokens, if the homeserver administrator requires.
        nonrefreshable_access_token_lifetime = config.get(
            "nonrefreshable_access_token_lifetime",
            None,
        )
        if nonrefreshable_access_token_lifetime is not None:
            nonrefreshable_access_token_lifetime = self.parse_duration(
                nonrefreshable_access_token_lifetime)
        self.nonrefreshable_access_token_lifetime = nonrefreshable_access_token_lifetime

        if (self.session_lifetime is not None
                and self.nonrefreshable_access_token_lifetime is not None):
            if self.session_lifetime < self.nonrefreshable_access_token_lifetime:
                raise ConfigError(
                    "Both `session_lifetime` and `nonrefreshable_access_token_lifetime` "
                    "configuration options have been set, but `nonrefreshable_access_token_lifetime` "
                    " exceeds `session_lifetime`!")

        refresh_token_lifetime = config.get("refresh_token_lifetime")
        if refresh_token_lifetime is not None:
            refresh_token_lifetime = self.parse_duration(
                refresh_token_lifetime)
        self.refresh_token_lifetime: Optional[int] = refresh_token_lifetime

        if (self.session_lifetime is not None
                and self.refresh_token_lifetime is not None):
            if self.session_lifetime < self.refresh_token_lifetime:
                raise ConfigError(
                    "Both `session_lifetime` and `refresh_token_lifetime` "
                    "configuration options have been set, but `refresh_token_lifetime` "
                    " exceeds `session_lifetime`!")

        # The fallback template used for authenticating using a registration token
        self.registration_token_template = self.read_template(
            "registration_token.html")

        # The success template used during fallback auth.
        self.fallback_success_template = self.read_template(
            "auth_success.html")

        self.inhibit_user_in_use_error = config.get(
            "inhibit_user_in_use_error", False)
Beispiel #24
0
    async def _join_rooms(self, user_id: str) -> None:
        """
        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,
                        remote_room_hosts,
                    ) = await room_member_handler.lookup_room_alias(room_alias)
                    room_id = room.to_string()
                else:
                    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. 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.
                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(
                        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:
                    # If an invite is required, there must be a auto-join user ID.
                    assert self.hs.config.registration.auto_join_user_id

                    await room_member_handler.update_membership(
                        requester=create_requester(
                            self.hs.config.registration.auto_join_user_id,
                            authenticated_entity=self._server_name,
                        ),
                        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, 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,
                )

            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)