Example #1
0
class QuarantineMediaInRoom(RestServlet):
    """Quarantines all media in a room so that no one can download it via
    this server.
    """

    PATTERNS = (
        admin_patterns("/room/(?P<room_id>[^/]+)/media/quarantine") +
        # This path kept around for legacy reasons
        admin_patterns("/quarantine_media/(?P<room_id>[^/]+)"))

    def __init__(self, hs: "HomeServer"):
        self.store = hs.get_datastore()
        self.auth = hs.get_auth()

    async def on_POST(self, request: Request,
                      room_id: str) -> Tuple[int, JsonDict]:
        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)

        logging.info("Quarantining room: %s", room_id)

        # Quarantine all media in this room
        num_quarantined = await self.store.quarantine_media_ids_in_room(
            room_id, requester.user.to_string())

        return 200, {"num_quarantined": num_quarantined}
Example #2
0
 def register(self, json_resource: HttpServer) -> None:
     PATTERN = "/send_server_notice"
     json_resource.register_paths("POST", admin_patterns(PATTERN + "$"),
                                  self.on_POST, self.__class__.__name__)
     json_resource.register_paths(
         "PUT",
         admin_patterns(PATTERN + "/(?P<txn_id>[^/]*)$"),
         self.on_PUT,
         self.__class__.__name__,
     )
Example #3
0
class RoomRestServlet(RestServlet):
    """Get room details.

    TODO: Add on_POST to allow room creation without joining the room
    """

    PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]+)$")

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.auth = hs.get_auth()
        self.store = hs.get_datastore()

    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)
Example #4
0
class RoomStateRestServlet(RestServlet):
    """
    Get full state within a room.
    """

    PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]*)/state$")

    def __init__(self, hs: "HomeServer"):
        self.auth = hs.get_auth()
        self.store = hs.get_datastore()
        self.clock = hs.get_clock()
        self._event_serializer = hs.get_event_client_serializer()

    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
Example #5
0
class DeleteRoomStatusByRoomIdRestServlet(RestServlet):
    """Get the status of the delete room background task."""

    PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]*)/delete_status$", "v2")

    def __init__(self, hs: "HomeServer"):
        self._auth = hs.get_auth()
        self._pagination_handler = hs.get_pagination_handler()

    async def on_GET(self, request: SynapseRequest,
                     room_id: str) -> Tuple[int, JsonDict]:

        await assert_requester_is_admin(self._auth, request)

        if not RoomID.is_valid(room_id):
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "%s is not a legal room ID" % (room_id, ))

        delete_ids = self._pagination_handler.get_delete_ids_by_room(room_id)
        if delete_ids is None:
            raise NotFoundError("No delete task for room_id '%s' found" %
                                room_id)

        response = []
        for delete_id in delete_ids:
            delete = self._pagination_handler.get_delete_status(delete_id)
            if delete:
                response += [{
                    "delete_id": delete_id,
                    **delete.asdict(),
                }]
        return HTTPStatus.OK, {"results": cast(JsonDict, response)}
Example #6
0
class ShadowBanRestServlet(RestServlet):
    """An admin API for shadow-banning a user.

    A shadow-banned users receives successful responses to their client-server
    API requests, but the events are not propagated into rooms.

    Shadow-banning a user should be used as a tool of last resort and may lead
    to confusing or broken behaviour for the client.

    Example:

        POST /_synapse/admin/v1/users/@test:example.com/shadow_ban
        {}

        200 OK
        {}
    """

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]*)/shadow_ban")

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.store = hs.get_datastore()
        self.auth = hs.get_auth()

    async def on_POST(self, request, user_id):
        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 shadow-banned")

        await self.store.set_shadow_banned(UserID.from_string(user_id), True)

        return 200, {}
Example #7
0
class PurgeRoomServlet(RestServlet):
    """Servlet which will remove all trace of a room from the database

    POST /_synapse/admin/v1/purge_room
    {
        "room_id": "!room:id"
    }

    returns:

    {}
    """

    PATTERNS = admin_patterns("/purge_room$")

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.auth = hs.get_auth()
        self.pagination_handler = hs.get_pagination_handler()

    async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        body = parse_json_object_from_request(request)
        assert_params_in_dict(body, ("room_id", ))

        await self.pagination_handler.purge_room(body["room_id"])

        return 200, {}
Example #8
0
class ShutdownRoomRestServlet(RestServlet):
    """Shuts down a room by removing all local users from the room and blocking
    all future invites and joins to the room. Any local aliases will be repointed
    to a new room created by `new_room_user_id` and kicked users will be auto
    joined to the new room.
    """

    PATTERNS = admin_patterns("/shutdown_room/(?P<room_id>[^/]+)")

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.auth = hs.get_auth()
        self.room_shutdown_handler = hs.get_room_shutdown_handler()

    async def on_POST(self, request: SynapseRequest,
                      room_id: str) -> Tuple[int, JsonDict]:
        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, ["new_room_user_id"])

        ret = await self.room_shutdown_handler.shutdown_room(
            room_id=room_id,
            new_room_user_id=content["new_room_user_id"],
            new_room_name=content.get("room_name"),
            message=content.get("message"),
            requester_user_id=requester.user.to_string(),
            block=True,
        )

        return (200, ret)
Example #9
0
class DeleteRoomRestServlet(RestServlet):
    """Delete a room from server.

    It is a combination and improvement of shutdown and purge room.

    Shuts down a room by removing all local users from the room.
    Blocking all future invites and joins to the room is optional.

    If desired any local aliases will be repointed to a new room
    created by `new_room_user_id` and kicked users will be auto-
    joined to the new room.

    If 'purge' is true, it will remove all traces of a room from the database.
    """

    PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]+)/delete$")

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.auth = hs.get_auth()
        self.room_shutdown_handler = hs.get_room_shutdown_handler()
        self.pagination_handler = hs.get_pagination_handler()

    async def on_POST(
        self, request: SynapseRequest, room_id: str
    ) -> Tuple[int, JsonDict]:
        return await _delete_room(
            request,
            room_id,
            self.auth,
            self.room_shutdown_handler,
            self.pagination_handler,
        )
Example #10
0
class AccountValidityRenewServlet(RestServlet):
    PATTERNS = admin_patterns("/account_validity/validity$")

    def __init__(self, hs):
        """
        Args:
            hs (synapse.server.HomeServer): server
        """
        self.hs = hs
        self.account_activity_handler = hs.get_account_validity_handler()
        self.auth = hs.get_auth()

    async def on_POST(self, request):
        await assert_requester_is_admin(self.auth, request)

        body = parse_json_object_from_request(request)

        if "user_id" not in body:
            raise SynapseError(400, "Missing property 'user_id' in the request body")

        expiration_ts = await self.account_activity_handler.renew_account_for_user(
            body["user_id"],
            body.get("expiration_ts"),
            not body.get("enable_renewal_emails", True),
        )

        res = {"expiration_ts": expiration_ts}
        return 200, res
Example #11
0
class WhoisRestServlet(RestServlet):
    path_regex = "/whois/(?P<user_id>[^/]*)$"
    PATTERNS = (
        admin_patterns(path_regex)
        +
        # URL for spec reason
        # https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid
        client_patterns("/admin" + path_regex, v1=True)
    )

    def __init__(self, hs):
        self.hs = hs
        self.auth = hs.get_auth()
        self.admin_handler = hs.get_admin_handler()

    async def on_GET(self, request, user_id):
        target_user = UserID.from_string(user_id)
        requester = await self.auth.get_user_by_req(request)
        auth_user = requester.user

        if target_user != auth_user:
            await assert_user_is_admin(self.auth, auth_user)

        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "Can only whois a local user")

        ret = await self.admin_handler.get_whois(target_user)

        return 200, ret
Example #12
0
class BackgroundUpdateRestServlet(RestServlet):
    """Fetch information about background updates"""

    PATTERNS = admin_patterns("/background_updates/status$")

    def __init__(self, hs: "HomeServer"):
        self._auth = hs.get_auth()
        self._data_stores = hs.get_datastores()

    async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self._auth, request)

        # We need to check that all configured databases have updates enabled.
        # (They *should* all be in sync.)
        enabled = all(db.updates.enabled for db in self._data_stores.databases)

        current_updates = {}

        for db in self._data_stores.databases:
            update = db.updates.get_current_update()
            if not update:
                continue

            current_updates[db.name()] = {
                "name": update.name,
                "total_item_count": update.total_item_count,
                "total_duration_ms": update.total_duration_ms,
                "average_items_per_ms": update.average_items_per_ms(),
            }

        return HTTPStatus.OK, {
            "enabled": enabled,
            "current_updates": current_updates
        }
Example #13
0
class PurgeMediaCacheRestServlet(RestServlet):
    PATTERNS = admin_patterns("/purge_media_cache$")

    def __init__(self, hs: "HomeServer"):
        self.media_repository = hs.get_media_repository()
        self.auth = hs.get_auth()

    async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        before_ts = parse_integer(request, "before_ts", required=True)
        logger.info("before_ts: %r", before_ts)

        if before_ts < 0:
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Query parameter before_ts must be a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )
        elif before_ts < 30000000000:  # Dec 1970 in milliseconds, Aug 2920 in seconds
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Query parameter before_ts you provided is from the year 1970. "
                +
                "Double check that you are providing a timestamp in milliseconds.",
                errcode=Codes.INVALID_PARAM,
            )

        ret = await self.media_repository.delete_old_remote_media(before_ts)

        return HTTPStatus.OK, ret
Example #14
0
class DevicesRestServlet(RestServlet):
    """
    Retrieve the given user's devices
    """

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]*)/devices$", "v2")

    def __init__(self, hs: "HomeServer"):
        self.auth = hs.get_auth()
        self.device_handler = hs.get_device_handler()
        self.store = hs.get_datastore()
        self.is_mine = hs.is_mine

    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.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)}
Example #15
0
class RoomMembersRestServlet(RestServlet):
    """
    Get members list of a room.
    """

    PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]+)/members")

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.auth = hs.get_auth()
        self.store = hs.get_datastore()

    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")

        members = await self.store.get_users_in_room(room_id)
        ret = {"members": members, "total": len(members)}

        return 200, ret
Example #16
0
class RoomEventContextServlet(RestServlet):
    """
    Provide the context for an event.
    This API is designed to be used when system administrators wish to look at
    an abuse report and understand what happened during and immediately prior
    to this event.
    """

    PATTERNS = admin_patterns(
        "/rooms/(?P<room_id>[^/]*)/context/(?P<event_id>[^/]*)$")

    def __init__(self, hs):
        super().__init__()
        self.clock = hs.get_clock()
        self.room_context_handler = hs.get_room_context_handler()
        self._event_serializer = hs.get_event_client_serializer()
        self.auth = hs.get_auth()

    async def on_GET(self, request, room_id, event_id):
        requester = await self.auth.get_user_by_req(request, allow_guest=False)
        await assert_user_is_admin(self.auth, requester.user)

        limit = parse_integer(request, "limit", default=10)

        # picking the API shape for symmetry with /messages
        filter_str = parse_string(request, b"filter", encoding="utf-8")
        if filter_str:
            filter_json = urlparse.unquote(filter_str)
            event_filter = Filter(
                json_decoder.decode(filter_json))  # type: Optional[Filter]
        else:
            event_filter = None

        results = await self.room_context_handler.get_event_context(
            requester,
            room_id,
            event_id,
            limit,
            event_filter,
            use_admin_priviledge=True,
        )

        if not results:
            raise SynapseError(404,
                               "Event not found.",
                               errcode=Codes.NOT_FOUND)

        time_now = self.clock.time_msec()
        results[
            "events_before"] = await self._event_serializer.serialize_events(
                results["events_before"], time_now)
        results["event"] = await self._event_serializer.serialize_event(
            results["event"], time_now)
        results[
            "events_after"] = await self._event_serializer.serialize_events(
                results["events_after"], time_now)
        results["state"] = await self._event_serializer.serialize_events(
            results["state"], time_now)

        return 200, results
Example #17
0
class AccountValidityRenewServlet(RestServlet):
    PATTERNS = admin_patterns("/account_validity/validity$")

    def __init__(self, hs: "HomeServer"):
        self.account_activity_handler = hs.get_account_validity_handler()
        self.auth = hs.get_auth()

    async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        if self.account_activity_handler.on_legacy_admin_request_callback:
            expiration_ts = await (self.account_activity_handler.
                                   on_legacy_admin_request_callback(request))
        else:
            body = parse_json_object_from_request(request)

            if "user_id" not in body:
                raise SynapseError(
                    HTTPStatus.BAD_REQUEST,
                    "Missing property 'user_id' in the request body",
                )

            expiration_ts = await self.account_activity_handler.renew_account_for_user(
                body["user_id"],
                body.get("expiration_ts"),
                not body.get("enable_renewal_emails", True),
            )

        res = {"expiration_ts": expiration_ts}
        return HTTPStatus.OK, res
Example #18
0
class WhoisRestServlet(RestServlet):
    path_regex = "/whois/(?P<user_id>[^/]*)$"
    PATTERNS = [
        *admin_patterns(path_regex),
        # URL for spec reason
        # https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid
        *client_patterns("/admin" + path_regex, v1=True),
    ]

    def __init__(self, hs: "HomeServer"):
        self.auth = hs.get_auth()
        self.admin_handler = hs.get_admin_handler()
        self.is_mine = hs.is_mine

    async def on_GET(self, request: SynapseRequest,
                     user_id: str) -> Tuple[int, JsonDict]:
        target_user = UserID.from_string(user_id)
        requester = await self.auth.get_user_by_req(request)
        auth_user = requester.user

        if target_user != auth_user:
            await assert_user_is_admin(self.auth, auth_user)

        if not self.is_mine(target_user):
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "Can only whois a local user")

        ret = await self.admin_handler.get_whois(target_user)

        return HTTPStatus.OK, ret
Example #19
0
class AccountDataRestServlet(RestServlet):
    """Retrieve the given user's account data"""

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]*)/accountdata")

    def __init__(self, hs: "HomeServer"):
        self._auth = hs.get_auth()
        self._store = hs.get_datastore()
        self._is_mine_id = hs.is_mine_id

    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_id(user_id):
            raise SynapseError(HTTPStatus.BAD_REQUEST,
                               "Can only look up local users")

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

        global_data, by_room_data = await self._store.get_account_data_for_user(
            user_id)
        return HTTPStatus.OK, {
            "account_data": {
                "global": global_data,
                "rooms": by_room_data,
            },
        }
Example #20
0
class UserMembershipRestServlet(RestServlet):
    """
    Get room list of an user.
    """

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]+)/joined_rooms$")

    def __init__(self, hs):
        self.is_mine = hs.is_mine
        self.auth = hs.get_auth()
        self.store = hs.get_datastore()

    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
Example #21
0
class DeactivateAccountRestServlet(RestServlet):
    PATTERNS = admin_patterns("/deactivate/(?P<target_user_id>[^/]*)")

    def __init__(self, hs):
        self._deactivate_account_handler = hs.get_deactivate_account_handler()
        self.auth = hs.get_auth()

    async def on_POST(self, request, target_user_id):
        await assert_requester_is_admin(self.auth, request)
        body = parse_json_object_from_request(request, allow_empty_body=True)
        erase = body.get("erase", False)
        if not isinstance(erase, bool):
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Param 'erase' must be a boolean, if given",
                Codes.BAD_JSON,
            )

        UserID.from_string(target_user_id)

        result = await self._deactivate_account_handler.deactivate_account(
            target_user_id, erase
        )
        if result:
            id_server_unbind_result = "success"
        else:
            id_server_unbind_result = "no-support"

        return 200, {"id_server_unbind_result": id_server_unbind_result}
Example #22
0
class ListDestinationsRestServlet(RestServlet):
    """Get request to list all destinations.
    This needs user to have administrator access in Synapse.

    GET /_synapse/admin/v1/federation/destinations?from=0&limit=10

    returns:
        200 OK with list of destinations if success otherwise an error.

    The parameters `from` and `limit` are required only for pagination.
    By default, a `limit` of 100 is used.
    The parameter `destination` can be used to filter by destination.
    The parameter `order_by` can be used to order the result.
    """

    PATTERNS = admin_patterns("/federation/destinations$")

    def __init__(self, hs: "HomeServer"):
        self._auth = hs.get_auth()
        self._store = hs.get_datastores().main

    async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self._auth, request)

        start = parse_integer(request, "from", default=0)
        limit = parse_integer(request, "limit", default=100)

        if start < 0:
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Query parameter from must be a string representing a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )

        if limit < 0:
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Query parameter limit must be a string representing a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )

        destination = parse_string(request, "destination")

        order_by = parse_string(
            request,
            "order_by",
            default=DestinationSortOrder.DESTINATION.value,
            allowed_values=[dest.value for dest in DestinationSortOrder],
        )

        direction = parse_string(request, "dir", default="f", allowed_values=("f", "b"))

        destinations, total = await self._store.get_destinations_paginate(
            start, limit, destination, order_by, direction
        )
        response = {"destinations": destinations, "total": total}
        if (start + limit) < total:
            response["next_token"] = str(start + len(destinations))

        return HTTPStatus.OK, response
Example #23
0
class DeleteMediaByID(RestServlet):
    """Delete local media by a given ID. Removes it from this server.
    """

    PATTERNS = admin_patterns(
        "/media/(?P<server_name>[^/]+)/(?P<media_id>[^/]+)")

    def __init__(self, hs: "HomeServer"):
        self.store = hs.get_datastore()
        self.auth = hs.get_auth()
        self.server_name = hs.hostname
        self.media_repository = hs.get_media_repository()

    async def on_DELETE(self, request: Request, 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(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}
Example #24
0
class QuarantineMediaByID(RestServlet):
    """Quarantines local or remote media by a given ID so that no one can download
    it via this server.
    """

    PATTERNS = admin_patterns(
        "/media/quarantine/(?P<server_name>[^/]+)/(?P<media_id>[^/]+)")

    def __init__(self, hs: "HomeServer"):
        self.store = hs.get_datastore()
        self.auth = hs.get_auth()

    async def on_POST(self, request: Request, server_name: str,
                      media_id: str) -> Tuple[int, JsonDict]:
        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)

        logging.info("Quarantining local media by ID: %s/%s", server_name,
                     media_id)

        # Quarantine this media id
        await self.store.quarantine_media_by_id(server_name, media_id,
                                                requester.user.to_string())

        return 200, {}
Example #25
0
class DevicesRestServlet(RestServlet):
    """
    Retrieve the given user's devices
    """

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]*)/devices$", "v2")

    def __init__(self, hs):
        """
        Args:
            hs (synapse.server.HomeServer): server
        """
        self.hs = hs
        self.auth = hs.get_auth()
        self.device_handler = hs.get_device_handler()
        self.store = hs.get_datastore()

    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)}
Example #26
0
class DeviceRestServlet(RestServlet):
    """
    Get, update or delete the given user's device
    """

    PATTERNS = admin_patterns(
        "/users/(?P<user_id>[^/]*)/devices/(?P<device_id>[^/]*)$", "v2")

    def __init__(self, hs):
        super().__init__()
        self.hs = hs
        self.auth = hs.get_auth()
        self.device_handler = hs.get_device_handler()
        self.store = hs.get_datastore()

    async def on_GET(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")

        device = await self.device_handler.get_device(target_user.to_string(),
                                                      device_id)
        return 200, device

    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, {}

    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, {}
Example #27
0
class DeleteDevicesRestServlet(RestServlet):
    """
    API for bulk deletion of devices. Accepts a JSON object with a devices
    key which lists the device_ids to delete.
    """

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]*)/delete_devices$",
                              "v2")

    def __init__(self, hs):
        self.hs = hs
        self.auth = hs.get_auth()
        self.device_handler = hs.get_device_handler()
        self.store = hs.get_datastore()

    async def on_POST(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")

        body = parse_json_object_from_request(request, allow_empty_body=False)
        assert_params_in_dict(body, ["devices"])

        await self.device_handler.delete_devices(target_user.to_string(),
                                                 body["devices"])
        return 200, {}
Example #28
0
class UserMediaRestServlet(RestServlet):
    """
    Gets information about all uploaded local media for a specific `user_id`.

    Example:
        http://localhost:8008/_synapse/admin/v1/users/
        @user:server/media

    Args:
        The parameters `from` and `limit` are required for pagination.
        By default, a `limit` of 100 is used.
    Returns:
        A list of media and an integer representing the total number of
        media that exist given for this user
    """

    PATTERNS = admin_patterns("/users/(?P<user_id>[^/]+)/media$")

    def __init__(self, hs):
        self.is_mine = hs.is_mine
        self.auth = hs.get_auth()
        self.store = hs.get_datastore()

    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")

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

        start = parse_integer(request, "from", default=0)
        limit = parse_integer(request, "limit", default=100)

        if start < 0:
            raise SynapseError(
                400,
                "Query parameter from must be a string representing a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )

        if limit < 0:
            raise SynapseError(
                400,
                "Query parameter limit must be a string representing a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )

        media, total = await self.store.get_local_media_by_user_paginate(
            start, limit, user_id)

        ret = {"media": media, "total": total}
        if (start + limit) < total:
            ret["next_token"] = start + len(media)

        return 200, ret
Example #29
0
class BackgroundUpdateStartJobRestServlet(RestServlet):
    """Allows to start specific background updates"""

    PATTERNS = admin_patterns("/background_updates/start_job$")

    def __init__(self, hs: "HomeServer"):
        self._auth = hs.get_auth()
        self._store = hs.get_datastores().main

    async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self._auth, request)

        body = parse_json_object_from_request(request)
        assert_params_in_dict(body, ["job_name"])

        job_name = body["job_name"]

        if job_name == "populate_stats_process_rooms":
            jobs = [("populate_stats_process_rooms", "{}", "")]
        elif job_name == "regenerate_directory":
            jobs = [
                ("populate_user_directory_createtables", "{}", ""),
                (
                    "populate_user_directory_process_rooms",
                    "{}",
                    "populate_user_directory_createtables",
                ),
                (
                    "populate_user_directory_process_users",
                    "{}",
                    "populate_user_directory_process_rooms",
                ),
                (
                    "populate_user_directory_cleanup",
                    "{}",
                    "populate_user_directory_process_users",
                ),
            ]
        else:
            raise SynapseError(HTTPStatus.BAD_REQUEST, "Invalid job_name")

        try:
            await self._store.db_pool.simple_insert_many(
                table="background_updates",
                keys=("update_name", "progress_json", "depends_on"),
                values=jobs,
                desc=f"admin_api_run_{job_name}",
            )
        except self._store.db_pool.engine.module.IntegrityError:
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Job %s is already in queue of background updates." %
                (job_name, ),
            )

        self._store.db_pool.updates.start_doing_background_updates()

        return HTTPStatus.OK, {}
Example #30
0
class UsersRestServletV2(RestServlet):
    PATTERNS = admin_patterns("/users$", "v2")

    """Get request to list all local users.
    This needs user to have administrator access in Synapse.

    GET /_synapse/admin/v2/users?from=0&limit=10&guests=false

    returns:
        200 OK with list of users if success otherwise an error.

    The parameters `from` and `limit` are required only for pagination.
    By default, a `limit` of 100 is used.
    The parameter `user_id` can be used to filter by user id.
    The parameter `name` can be used to filter by user id or display name.
    The parameter `guests` can be used to exclude guest users.
    The parameter `deactivated` can be used to include deactivated users.
    """

    def __init__(self, hs: "HomeServer"):
        self.hs = hs
        self.store = hs.get_datastore()
        self.auth = hs.get_auth()
        self.admin_handler = hs.get_admin_handler()

    async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        await assert_requester_is_admin(self.auth, request)

        start = parse_integer(request, "from", default=0)
        limit = parse_integer(request, "limit", default=100)

        if start < 0:
            raise SynapseError(
                400,
                "Query parameter from must be a string representing a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )

        if limit < 0:
            raise SynapseError(
                400,
                "Query parameter limit must be a string representing a positive integer.",
                errcode=Codes.INVALID_PARAM,
            )

        user_id = parse_string(request, "user_id", default=None)
        name = parse_string(request, "name", default=None)
        guests = parse_boolean(request, "guests", default=True)
        deactivated = parse_boolean(request, "deactivated", default=False)

        users, total = await self.store.get_users_paginate(
            start, limit, user_id, name, guests, deactivated
        )
        ret = {"users": users, "total": total}
        if (start + limit) < total:
            ret["next_token"] = str(start + len(users))

        return 200, ret