Ejemplo n.º 1
0
    async def on_GET(self, request: SynapseRequest, user_id: str,
                     account_data_type: str) -> Tuple[int, JsonDict]:
        requester = await self.auth.get_user_by_req(request)
        if user_id != requester.user.to_string():
            raise AuthError(403, "Cannot get account data for other users.")

        event = await self.store.get_global_account_data_by_type_for_user(
            user_id, account_data_type)

        if event is None:
            raise NotFoundError("Account data not found")

        return 200, event
Ejemplo n.º 2
0
    def on_GET(self, request, user_id, account_data_type):
        requester = yield self.auth.get_user_by_req(request)
        if user_id != requester.user.to_string():
            raise AuthError(403, "Cannot get account data for other users.")

        event = yield self.store.get_global_account_data_by_type_for_user(
            account_data_type, user_id,
        )

        if event is None:
            raise NotFoundError("Account data not found")

        defer.returnValue((200, event))
Ejemplo n.º 3
0
    async def on_DELETE(self, request: SynapseRequest,
                        user_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        if not self.hs.is_mine_id(user_id):
            raise SynapseError(400, "Only local users can be ratelimited")

        if not await self.store.get_user_by_id(user_id):
            raise NotFoundError("User not found")

        await self.store.delete_ratelimit_for_user(user_id)

        return 200, {}
Ejemplo n.º 4
0
    async def on_GET(self, request, user_id):
        await assert_requester_is_admin(self.auth, request)

        if not self.is_mine(UserID.from_string(user_id)):
            raise SynapseError(400, "Can only lookup local users")

        user = await self.store.get_user_by_id(user_id)
        if user is None:
            raise NotFoundError("Unknown user")

        room_ids = await self.store.get_rooms_for_user(user_id)
        ret = {"joined_rooms": list(room_ids), "total": len(room_ids)}
        return 200, ret
Ejemplo n.º 5
0
    async def on_GET(self, request, user_id):
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "Can only lookup local users")

        ret = await self.admin_handler.get_user(target_user)

        if not ret:
            raise NotFoundError("User not found")

        return 200, ret
Ejemplo n.º 6
0
    async def _async_render_GET(self, request):
        """
        Args:
            request (twisted.web.http.Request):
        """
        version = parse_string(request, "v", default=self._default_consent_version)
        username = parse_string(request, "u", required=False, default="")
        userhmac = None
        has_consented = False
        public_version = username == ""
        if not public_version:
            userhmac_bytes = parse_string(request, "h", required=True, encoding=None)

            self._check_hash(username, userhmac_bytes)

            if username.startswith("@"):
                qualified_user_id = username
            else:
                qualified_user_id = UserID(username, self.hs.hostname).to_string()

            u = await self.store.get_user_by_id(qualified_user_id)
            if u is None:
                raise NotFoundError("Unknown user")

            has_consented = u["consent_version"] == version
            userhmac = userhmac_bytes.decode("ascii")

        try:
            self._render_template(
                request,
                "%s.html" % (version,),
                user=username,
                userhmac=userhmac,
                version=version,
                has_consented=has_consented,
                public_version=public_version,
            )
        except TemplateNotFound:
            raise NotFoundError("Unknown policy version")
Ejemplo n.º 7
0
    async def on_GET(self, request: SynapseRequest,
                     room_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        ret = await self.store.get_room_with_stats(room_id)
        if not ret:
            raise NotFoundError("Room not found")

        members = await self.store.get_users_in_room(room_id)
        ret["joined_local_devices"] = await self.store.count_devices_by_users(
            members)

        return (200, ret)
Ejemplo n.º 8
0
    async def on_query(self, query_type: str, args: dict):
        handler = self.query_handlers.get(query_type)
        if handler:
            return await handler(args)

        # Check if we can route it somewhere else that isn't us
        if self._instance_name == "master":
            return await self._get_query_client(query_type=query_type, args=args)

        # Uh oh, no handler! Let's raise an exception so the request returns an
        # error.
        logger.warning("No handler registered for query type %s", query_type)
        raise NotFoundError("No handler for Query type '%s'" % (query_type,))
Ejemplo n.º 9
0
    def delete_association(self, requester, room_alias):
        """Remove an alias from the directory

        (this is only meant for human users; AS users should call
        delete_appservice_association)

        Args:
            requester (Requester):
            room_alias (RoomAlias):

        Returns:
            Deferred[unicode]: room id that the alias used to point to

        Raises:
            NotFoundError: if the alias doesn't exist

            AuthError: if the user doesn't have perms to delete the alias (ie, the user
                is neither the creator of the alias, nor a server admin.

            SynapseError: if the alias belongs to an AS
        """
        user_id = requester.user.to_string()

        try:
            can_delete = yield self._user_can_delete_alias(room_alias, user_id)
        except StoreError as e:
            if e.code == 404:
                raise NotFoundError("Unknown room alias")
            raise

        if not can_delete:
            raise AuthError(403, "You don't have permission to delete the alias.")

        can_delete = yield self.can_modify_alias(room_alias, user_id=user_id)
        if not can_delete:
            raise SynapseError(
                400,
                "This alias is reserved by an application service.",
                errcode=Codes.EXCLUSIVE,
            )

        room_id = yield self._delete_association(room_alias)

        try:
            yield self._update_canonical_alias(
                requester, requester.user.to_string(), room_id, room_alias
            )
        except AuthError as e:
            logger.info("Failed to update alias events: %s", e)

        return room_id
Ejemplo n.º 10
0
    async def on_DELETE(self, request, server_name: str, media_id: str):
        await assert_requester_is_admin(self.auth, request)

        if self.server_name != server_name:
            raise SynapseError(400, "Can only delete local media")

        if await self.store.get_local_media(media_id) is None:
            raise NotFoundError("Unknown media")

        logging.info("Deleting local media by ID: %s", media_id)

        deleted_media, total = await self.media_repository.delete_local_media(
            media_id)
        return 200, {"deleted_media": deleted_media, "total": total}
Ejemplo n.º 11
0
    async def on_GET(self, request: SynapseRequest,
                     user_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "Can only look up local users")

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

        return HTTPStatus.OK, user_info_dict
Ejemplo n.º 12
0
    async def on_DELETE(self, request, user_id, device_id):
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        await self.device_handler.delete_device(target_user.to_string(),
                                                device_id)
        return 200, {}
Ejemplo n.º 13
0
    async def on_GET(self, request, user_id):
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        devices = await self.device_handler.get_devices_by_user(
            target_user.to_string())
        return 200, {"devices": devices, "total": len(devices)}
    async def on_PUT(self, request: SynapseRequest, token: str) -> Tuple[int, JsonDict]:
        """Update a registration token."""
        await assert_requester_is_admin(self.auth, request)
        body = parse_json_object_from_request(request)
        new_attributes = {}

        # Only add uses_allowed to new_attributes if it is present and valid
        if "uses_allowed" in body:
            uses_allowed = body["uses_allowed"]
            if not (
                uses_allowed is None
                or (isinstance(uses_allowed, int) and uses_allowed >= 0)
            ):
                raise SynapseError(
                    HTTPStatus.BAD_REQUEST,
                    "uses_allowed must be a non-negative integer or null",
                    Codes.INVALID_PARAM,
                )
            new_attributes["uses_allowed"] = uses_allowed

        if "expiry_time" in body:
            expiry_time = body["expiry_time"]
            if not isinstance(expiry_time, (int, type(None))):
                raise SynapseError(
                    HTTPStatus.BAD_REQUEST,
                    "expiry_time must be an integer or null",
                    Codes.INVALID_PARAM,
                )
            if isinstance(expiry_time, int) and expiry_time < self.clock.time_msec():
                raise SynapseError(
                    HTTPStatus.BAD_REQUEST,
                    "expiry_time must not be in the past",
                    Codes.INVALID_PARAM,
                )
            new_attributes["expiry_time"] = expiry_time

        if len(new_attributes) == 0:
            # Nothing to update, get token info to return
            token_info = await self.store.get_one_registration_token(token)
        else:
            token_info = await self.store.update_registration_token(
                token, new_attributes
            )

        # If no result return a 404
        if token_info is None:
            raise NotFoundError(f"No such registration token: {token}")

        return HTTPStatus.OK, token_info
Ejemplo n.º 15
0
    async def on_DELETE(
        self, request: SynapseRequest, user_id: str, device_id: str
    ) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.is_mine(target_user):
            raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        await self.device_handler.delete_device(target_user.to_string(), device_id)
        return HTTPStatus.OK, {}
Ejemplo n.º 16
0
    async def on_GET(self, request: SynapseRequest, user_id,
                     device_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        device = await self.device_handler.get_device(target_user.to_string(),
                                                      device_id)
        return 200, device
Ejemplo n.º 17
0
    async def on_PUT(self, request, user_id, device_id):
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        body = parse_json_object_from_request(request, allow_empty_body=True)
        await self.device_handler.update_device(target_user.to_string(),
                                                device_id, body)
        return 200, {}
Ejemplo n.º 18
0
    async def on_DELETE(self, request: SynapseRequest, server_name: str,
                        media_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        if self.server_name != server_name:
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "Can only delete local media")

        if await self.store.get_local_media(media_id) is None:
            raise NotFoundError("Unknown media")

        logging.info("Deleting local media by ID: %s", media_id)

        deleted_media, total = await self.media_repository.delete_local_media_ids(
            [media_id])
        return HTTPStatus.OK, {"deleted_media": deleted_media, "total": total}
Ejemplo n.º 19
0
    async def on_GET(
        self, request: SynapseRequest, user_id: str
    ) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        if not self.is_mine(UserID.from_string(user_id)):
            raise SynapseError(400, "Can only lookup local users")

        if not await self.store.get_user_by_id(user_id):
            raise NotFoundError("User not found")

        pushers = await self.store.get_pushers_by_user_id(user_id)

        filtered_pushers = [p.as_dict() for p in pushers]

        return 200, {"pushers": filtered_pushers, "total": len(filtered_pushers)}
Ejemplo n.º 20
0
    async def on_GET(self, request: SynapseRequest,
                     room_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        ret = await self.store.get_room(room_id)
        if not ret:
            raise NotFoundError("Room not found")

        event_ids = await self.store.get_current_state_ids(room_id)
        events = await self.store.get_events(event_ids.values())
        now = self.clock.time_msec()
        room_state = self._event_serializer.serialize_events(
            events.values(), now)
        ret = {"state": room_state}

        return HTTPStatus.OK, ret
Ejemplo n.º 21
0
 def _get_remote_media_impl(self, server_name, media_id):
     media_info = yield self.store.get_cached_remote_media(
         server_name, media_id
     )
     if not media_info:
         media_info = yield self._download_remote_file(
             server_name, media_id
         )
     elif media_info["quarantined_by"]:
         raise NotFoundError()
     else:
         self.recently_accessed_remotes.add((server_name, media_id))
         yield self.store.update_cached_last_access_time(
             [(server_name, media_id)], self.clock.time_msec()
         )
     defer.returnValue(media_info)
Ejemplo n.º 22
0
    async def on_GET(self, request: SynapseRequest,
                     user_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.hs.is_mine(target_user):
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        devices = await self.device_handler.get_devices_by_user(
            target_user.to_string())
        return HTTPStatus.OK, {"devices": devices, "total": len(devices)}
Ejemplo n.º 23
0
    def on_DELETE(self, request):
        spec = _rule_spec_from_path(request.postpath)

        user, _ = yield self.auth.get_user_by_req(request)

        namespaced_rule_id = _namespaced_rule_id_from_spec(spec)

        try:
            yield self.hs.get_datastore().delete_push_rule(
                user.to_string(), namespaced_rule_id)
            defer.returnValue((200, {}))
        except StoreError as e:
            if e.code == 404:
                raise NotFoundError()
            else:
                raise
Ejemplo n.º 24
0
    async def set_rule_attr(self, user_id: str, spec: RuleSpec,
                            val: Union[bool, JsonDict]) -> None:
        if spec.attr not in ("enabled", "actions"):
            # for the sake of potential future expansion, shouldn't report
            # 404 in the case of an unknown request so check it corresponds to
            # a known attribute first.
            raise UnrecognizedRequestError()

        namespaced_rule_id = _namespaced_rule_id_from_spec(spec)
        rule_id = spec.rule_id
        is_default_rule = rule_id.startswith(".")
        if is_default_rule:
            if namespaced_rule_id not in BASE_RULE_IDS:
                raise NotFoundError("Unknown rule %s" % (namespaced_rule_id, ))
        if spec.attr == "enabled":
            if isinstance(val, dict) and "enabled" in val:
                val = val["enabled"]
            if not isinstance(val, bool):
                # Legacy fallback
                # This should *actually* take a dict, but many clients pass
                # bools directly, so let's not break them.
                raise SynapseError(400, "Value for 'enabled' must be boolean")
            await self.store.set_push_rule_enabled(user_id, namespaced_rule_id,
                                                   val, is_default_rule)
        elif spec.attr == "actions":
            if not isinstance(val, dict):
                raise SynapseError(400, "Value must be a dict")
            actions = val.get("actions")
            if not isinstance(actions, list):
                raise SynapseError(400, "Value for 'actions' must be dict")
            _check_actions(actions)
            namespaced_rule_id = _namespaced_rule_id_from_spec(spec)
            rule_id = spec.rule_id
            is_default_rule = rule_id.startswith(".")
            if is_default_rule:
                if user_id in self._users_new_default_push_rules:
                    rule_ids = NEW_RULE_IDS
                else:
                    rule_ids = BASE_RULE_IDS

                if namespaced_rule_id not in rule_ids:
                    raise SynapseError(
                        404, "Unknown rule %r" % (namespaced_rule_id, ))
            await self.store.set_push_rule_actions(user_id, namespaced_rule_id,
                                                   actions, is_default_rule)
        else:
            raise UnrecognizedRequestError()
Ejemplo n.º 25
0
    def get_event(
        self,
        event_id,
        check_redacted=True,
        get_prev_content=False,
        allow_rejected=False,
        allow_none=False,
        check_room_id=None,
    ):
        """Get an event from the database by event_id.

        Args:
            event_id (str): The event_id of the event to fetch
            check_redacted (bool): If True, check if event has been redacted
                and redact it.
            get_prev_content (bool): If True and event is a state event,
                include the previous states content in the unsigned field.
            allow_rejected (bool): If True return rejected events.
            allow_none (bool): If True, return None if no event found, if
                False throw a NotFoundError
            check_room_id (str|None): if not None, check the room of the found event.
                If there is a mismatch, behave as per allow_none.

        Returns:
            Deferred[EventBase|None]
        """
        if not isinstance(event_id, str):
            raise TypeError("Invalid event event_id %r" % (event_id, ))

        events = yield self.get_events_as_list(
            [event_id],
            check_redacted=check_redacted,
            get_prev_content=get_prev_content,
            allow_rejected=allow_rejected,
        )

        event = events[0] if events else None

        if event is not None and check_room_id is not None:
            if event.room_id != check_room_id:
                event = None

        if event is None and not allow_none:
            raise NotFoundError("Could not find event %s" % (event_id, ))

        return event
Ejemplo n.º 26
0
    async def on_PUT(self, request: SynapseRequest, user_id: str,
                     device_id: str) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        target_user = UserID.from_string(user_id)
        if not self.is_mine(target_user):
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "Can only lookup local users")

        u = await self.store.get_user_by_id(target_user.to_string())
        if u is None:
            raise NotFoundError("Unknown user")

        body = parse_json_object_from_request(request, allow_empty_body=True)
        await self.device_handler.update_device(target_user.to_string(),
                                                device_id, body)
        return HTTPStatus.OK, {}
Ejemplo n.º 27
0
    async def ensure_media_is_in_local_cache(self, file_info: FileInfo) -> str:
        """Ensures that the given file is in the local cache. Attempts to
        download it from storage providers if it isn't.

        Args:
            file_info

        Returns:
            Full path to local file
        """
        path = self._file_info_to_path(file_info)
        local_path = os.path.join(self.local_media_directory, path)
        if os.path.exists(local_path):
            return local_path

        # Fallback for paths without method names
        # Should be removed in the future
        if file_info.thumbnail and file_info.server_name:
            legacy_path = self.filepaths.remote_media_thumbnail_rel_legacy(
                server_name=file_info.server_name,
                file_id=file_info.file_id,
                width=file_info.thumbnail_width,
                height=file_info.thumbnail_height,
                content_type=file_info.thumbnail_type,
            )
            legacy_local_path = os.path.join(self.local_media_directory,
                                             legacy_path)
            if os.path.exists(legacy_local_path):
                return legacy_local_path

        dirname = os.path.dirname(local_path)
        if not os.path.exists(dirname):
            os.makedirs(dirname)

        for provider in self.storage_providers:
            res = await provider.fetch(path, file_info)  # type: Any
            if res:
                with res:
                    consumer = BackgroundFileConsumer(open(local_path, "wb"),
                                                      self.reactor)
                    await res.write_to_consumer(consumer)
                    await consumer.wait()
                return local_path

        raise NotFoundError()
Ejemplo n.º 28
0
    def delete_association(self, requester, room_alias):
        # association deletion for human users

        user_id = requester.user.to_string()

        try:
            can_delete = yield self._user_can_delete_alias(room_alias, user_id)
        except StoreError as e:
            if e.code == 404:
                raise NotFoundError("Unknown room alias")
            raise

        if not can_delete:
            raise AuthError(
                403, "You don't have permission to delete the alias.",
            )

        can_delete = yield self.can_modify_alias(
            room_alias,
            user_id=user_id
        )
        if not can_delete:
            raise SynapseError(
                400, "This alias is reserved by an application service.",
                errcode=Codes.EXCLUSIVE
            )

        room_id = yield self._delete_association(room_alias)

        try:
            yield self.send_room_alias_update_event(
                requester,
                room_id
            )

            yield self._update_canonical_alias(
                requester,
                requester.user.to_string(),
                room_id,
                room_alias,
            )
        except AuthError as e:
            logger.info("Failed to update alias events: %s", e)

        defer.returnValue(room_id)
Ejemplo n.º 29
0
    async def delete_room_keys(
        self,
        user_id: str,
        version: str,
        room_id: Optional[str] = None,
        session_id: Optional[str] = None,
    ) -> JsonDict:
        """Bulk delete the E2E room keys for a given backup, optionally filtered to a given
        room or a given session.
        See EndToEndRoomKeyStore.delete_e2e_room_keys for full details.

        Args:
            user_id: the user whose backup we're deleting
            version: the version ID of the backup we're deleting
            room_id: room ID to delete keys for, for None to delete keys for all
                rooms
            session_id: session ID to delete keys for, for None to delete keys
                for all sessions
        Raises:
            NotFoundError: if the backup version does not exist
        Returns:
            A dict containing the count and etag for the backup version
        """

        # lock for consistency with uploading
        with (await self._upload_linearizer.queue(user_id)):
            # make sure the backup version exists
            try:
                version_info = await self.store.get_e2e_room_keys_version_info(
                    user_id, version)
            except StoreError as e:
                if e.code == 404:
                    raise NotFoundError("Unknown backup version")
                else:
                    raise

            await self.store.delete_e2e_room_keys(user_id, version, room_id,
                                                  session_id)

            version_etag = version_info["etag"] + 1
            await self.store.update_e2e_room_keys_version(
                user_id, version, None, version_etag)

            count = await self.store.count_e2e_room_keys(user_id, version)
            return {"etag": str(version_etag), "count": count}
Ejemplo n.º 30
0
        def set_push_rule_actions_txn(txn, stream_id, event_stream_ordering):
            if is_default_rule:
                # Add a dummy rule to the rules table with the user specified
                # actions.
                priority_class = -1
                priority = 1
                self._upsert_push_rule_txn(
                    txn,
                    stream_id,
                    event_stream_ordering,
                    user_id,
                    rule_id,
                    priority_class,
                    priority,
                    "[]",
                    actions_json,
                    update_stream=False,
                )
            else:
                try:
                    self.db_pool.simple_update_one_txn(
                        txn,
                        "push_rules",
                        {
                            "user_name": user_id,
                            "rule_id": rule_id
                        },
                        {"actions": actions_json},
                    )
                except StoreError as serr:
                    if serr.code == 404:
                        # this sets the NOT_FOUND error Code
                        raise NotFoundError("Push rule does not exist")
                    else:
                        raise

            self._insert_push_rules_update_txn(
                txn,
                stream_id,
                event_stream_ordering,
                user_id,
                rule_id,
                op="ACTIONS",
                data={"actions": actions_json},
            )