Пример #1
0
    def _async_render_POST(self, request):
        resp_bytes = parse_string(request, 'SAMLResponse', required=True)
        relay_state = parse_string(request, 'RelayState', required=True)

        try:
            saml2_auth = self._saml_client.parse_authn_request_response(
                resp_bytes, saml2.BINDING_HTTP_POST,
            )
        except Exception as e:
            logger.warning("Exception parsing SAML2 response", exc_info=1)
            raise CodeMessageException(
                400, "Unable to parse SAML2 response: %s" % (e,),
            )

        if saml2_auth.not_signed:
            raise CodeMessageException(400, "SAML2 response was not signed")

        if "uid" not in saml2_auth.ava:
            raise CodeMessageException(400, "uid not in SAML2 response")

        username = saml2_auth.ava["uid"][0]

        displayName = saml2_auth.ava.get("displayName", [None])[0]
        return self._sso_auth_handler.on_successful_auth(
            username, request, relay_state,
            user_display_name=displayName,
        )
Пример #2
0
    def on_GET(self, request, room_id, parent_id, relation_type=None, event_type=None):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

        yield self.auth.check_in_room_or_world_readable(
            room_id, requester.user.to_string()
        )

        # This checks that a) the event exists and b) the user is allowed to
        # view it.
        yield self.event_handler.get_event(requester.user, room_id, parent_id)

        if relation_type not in (RelationTypes.ANNOTATION, None):
            raise SynapseError(400, "Relation type must be 'annotation'")

        limit = parse_integer(request, "limit", default=5)
        from_token = parse_string(request, "from")
        to_token = parse_string(request, "to")

        if from_token:
            from_token = AggregationPaginationToken.from_string(from_token)

        if to_token:
            to_token = AggregationPaginationToken.from_string(to_token)

        res = yield self.store.get_aggregation_groups_for_event(
            event_id=parent_id,
            event_type=event_type,
            limit=limit,
            from_token=from_token,
            to_token=to_token,
        )

        defer.returnValue((200, res.to_dict()))
Пример #3
0
    def _async_render_POST(self, request):
        """
        Args:
            request (twisted.web.http.Request):
        """
        version = parse_string(request, "v", required=True)
        username = parse_string(request, "u", required=True)
        userhmac = parse_string(request, "h", required=True, encoding=None)

        self._check_hash(username, userhmac)

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

        try:
            yield self.store.user_set_consent_version(qualified_user_id, version)
        except StoreError as e:
            if e.code != 404:
                raise
            raise NotFoundError("Unknown user")
        yield self.registration_handler.post_consent_actions(qualified_user_id)

        try:
            self._render_template(request, "success.html")
        except TemplateNotFound:
            raise NotFoundError("success.html not found")
Пример #4
0
    def on_GET(self, request):
        server = parse_string(request, "server", default=None)

        try:
            yield self.auth.get_user_by_req(request, allow_guest=True)
        except AuthError as e:
            # We allow people to not be authed if they're just looking at our
            # room list, but require auth when we proxy the request.
            # In both cases we call the auth function, as that has the side
            # effect of logging who issued this request if an access token was
            # provided.
            if server:
                raise e
            else:
                pass

        limit = parse_integer(request, "limit", 0)
        since_token = parse_string(request, "since", None)

        handler = self.hs.get_room_list_handler()
        if server:
            data = yield handler.get_remote_public_room_list(
                server,
                limit=limit,
                since_token=since_token,
            )
        else:
            data = yield handler.get_local_public_room_list(
                limit=limit,
                since_token=since_token,
            )

        defer.returnValue((200, data))
Пример #5
0
    def from_request(cls, request, raise_invalid_params=True,
                     default_limit=None):
        direction = parse_string(request, "dir", default='f', allowed_values=['f', 'b'])

        from_tok = parse_string(request, "from")
        to_tok = parse_string(request, "to")

        try:
            if from_tok == "END":
                from_tok = None  # For backwards compat.
            elif from_tok:
                from_tok = StreamToken.from_string(from_tok)
        except Exception:
            raise SynapseError(400, "'from' paramater is invalid")

        try:
            if to_tok:
                to_tok = StreamToken.from_string(to_tok)
        except Exception:
            raise SynapseError(400, "'to' paramater is invalid")

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

        if limit and limit < 0:
            raise SynapseError(400, "Limit must be 0 or above")

        try:
            return PaginationConfig(from_tok, to_tok, direction, limit)
        except Exception:
            logger.exception("Failed to create pagination config")
            raise SynapseError(400, "Invalid request.")
Пример #6
0
    def _async_render_GET(self, request):
        server_name, media_id, _ = parse_media_id(request)
        width = parse_integer(request, "width")
        height = parse_integer(request, "height")
        method = parse_string(request, "method", "scale")
        m_type = parse_string(request, "type", "image/png")

        if server_name == self.server_name:
            if self.dynamic_thumbnails:
                yield self._select_or_generate_local_thumbnail(
                    request, media_id, width, height, method, m_type
                )
            else:
                yield self._respond_local_thumbnail(
                    request, media_id, width, height, method, m_type
                )
        else:
            if self.dynamic_thumbnails:
                yield self._select_or_generate_remote_thumbnail(
                    request, server_name, media_id,
                    width, height, method, m_type
                )
            else:
                yield self._respond_remote_thumbnail(
                    request, server_name, media_id,
                    width, height, method, m_type
                )
Пример #7
0
    def on_GET(self, request):
        requester = yield self.auth.get_user_by_req(request, rights="delete_pusher")
        user = requester.user

        app_id = parse_string(request, "app_id", required=True)
        pushkey = parse_string(request, "pushkey", required=True)

        try:
            yield self.pusher_pool.remove_pusher(
                app_id=app_id,
                pushkey=pushkey,
                user_id=user.to_string(),
            )
        except StoreError as se:
            if se.code != 404:
                # This is fine: they're already unsubscribed
                raise

        self.notifier.on_new_replication_data()

        request.setResponseCode(200)
        request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
        request.setHeader(b"Content-Length", b"%d" % (
            len(PushersRemoveRestServlet.SUCCESS_HTML),
        ))
        request.write(PushersRemoveRestServlet.SUCCESS_HTML)
        finish_request(request)
        defer.returnValue(None)
Пример #8
0
    def on_PUT(self, request):
        spec = _rule_spec_from_path(request.postpath)
        try:
            priority_class = _priority_class_from_spec(spec)
        except InvalidRuleException as e:
            raise SynapseError(400, str(e))

        requester = yield self.auth.get_user_by_req(request)

        if '/' in spec['rule_id'] or '\\' in spec['rule_id']:
            raise SynapseError(400, "rule_id may not contain slashes")

        content = parse_json_value_from_request(request)

        user_id = requester.user.to_string()

        if 'attr' in spec:
            yield self.set_rule_attr(user_id, spec, content)
            self.notify_user(user_id)
            defer.returnValue((200, {}))

        if spec['rule_id'].startswith('.'):
            # Rule ids starting with '.' are reserved for server default rules.
            raise SynapseError(400, "cannot add new rule_ids that start with '.'")

        try:
            (conditions, actions) = _rule_tuple_from_request_object(
                spec['template'],
                spec['rule_id'],
                content,
            )
        except InvalidRuleException as e:
            raise SynapseError(400, str(e))

        before = parse_string(request, "before")
        if before:
            before = _namespaced_rule_id(spec, before)

        after = parse_string(request, "after")
        if after:
            after = _namespaced_rule_id(spec, after)

        try:
            yield self.store.add_push_rule(
                user_id=user_id,
                rule_id=_namespaced_rule_id_from_spec(spec),
                priority_class=priority_class,
                conditions=conditions,
                actions=actions,
                before=before,
                after=after
            )
            self.notify_user(user_id)
        except InconsistentRuleException as e:
            raise SynapseError(400, str(e))
        except RuleNotFoundException as e:
            raise SynapseError(400, str(e))

        defer.returnValue((200, {}))
Пример #9
0
    def on_GET(self, request):
        requester = yield self.auth.get_user_by_req(request)
        user_id = requester.user.to_string()

        from_token = parse_string(request, "from", required=False)
        limit = parse_integer(request, "limit", default=50)
        only = parse_string(request, "only", required=False)

        limit = min(limit, 500)

        push_actions = yield self.store.get_push_actions_for_user(
            user_id, from_token, limit, only_highlight=(only == "highlight")
        )

        receipts_by_room = yield self.store.get_receipts_for_user_with_orderings(
            user_id, 'm.read'
        )

        notif_event_ids = [pa["event_id"] for pa in push_actions]
        notif_events = yield self.store.get_events(notif_event_ids)

        returned_push_actions = []

        next_token = None

        for pa in push_actions:
            returned_pa = {
                "room_id": pa["room_id"],
                "profile_tag": pa["profile_tag"],
                "actions": pa["actions"],
                "ts": pa["received_ts"],
                "event": serialize_event(
                    notif_events[pa["event_id"]],
                    self.clock.time_msec(),
                    event_format=format_event_for_client_v2_without_room_id,
                ),
            }

            if pa["room_id"] not in receipts_by_room:
                returned_pa["read"] = False
            else:
                receipt = receipts_by_room[pa["room_id"]]

                returned_pa["read"] = (
                    receipt["topological_ordering"], receipt["stream_ordering"]
                ) >= (
                    pa["topological_ordering"], pa["stream_ordering"]
                )
            returned_push_actions.append(returned_pa)
            next_token = str(pa["stream_ordering"])

        defer.returnValue((200, {
            "notifications": returned_push_actions,
            "next_token": next_token,
        }))
Пример #10
0
    def on_GET(self, request):
        user, client = yield self.auth.get_user_by_req(request)

        timeout = parse_integer(request, "timeout", default=0)
        limit = parse_integer(request, "limit", required=True)
        gap = parse_boolean(request, "gap", default=True)
        sort = parse_string(request, "sort", default="timeline,asc", allowed_values=self.ALLOWED_SORT)
        since = parse_string(request, "since")
        set_presence = parse_string(request, "set_presence", default="online", allowed_values=self.ALLOWED_PRESENCE)
        backfill = parse_boolean(request, "backfill", default=False)
        filter_id = parse_string(request, "filter", default=None)

        logger.info(
            "/sync: user=%r, timeout=%r, limit=%r, gap=%r, sort=%r, since=%r,"
            " set_presence=%r, backfill=%r, filter_id=%r"
            % (user, timeout, limit, gap, sort, since, set_presence, backfill, filter_id)
        )

        # TODO(mjark): Load filter and apply overrides.
        try:
            filter = yield self.filtering.get_user_filter(user.localpart, filter_id)
        except:
            filter = Filter({})
        # filter = filter.apply_overrides(http_request)
        # if filter.matches(event):
        #   # stuff

        sync_config = SyncConfig(
            user=user, client_info=client, gap=gap, limit=limit, sort=sort, backfill=backfill, filter=filter
        )

        if since is not None:
            since_token = StreamToken.from_string(since)
        else:
            since_token = None

        sync_result = yield self.sync_handler.wait_for_sync_for_user(
            sync_config, since_token=since_token, timeout=timeout
        )

        time_now = self.clock.time_msec()

        response_content = {
            "public_user_data": self.encode_user_data(sync_result.public_user_data, filter, time_now),
            "private_user_data": self.encode_user_data(sync_result.private_user_data, filter, time_now),
            "rooms": self.encode_rooms(sync_result.rooms, filter, time_now, client.token_id),
            "next_batch": sync_result.next_batch.to_string(),
        }

        defer.returnValue((200, response_content))
Пример #11
0
    def on_GET(self, request, target_user_id):
        """Get request to search user table for specific users according to
        search term.
        This needs user to have a administrator access in Synapse.
        """
        target_user = UserID.from_string(target_user_id)
        requester = yield self.auth.get_user_by_req(request)
        is_admin = yield self.auth.is_server_admin(requester.user)

        if not is_admin:
            raise AuthError(403, "You are not a server admin")

        # To allow all users to get the users list
        # if not is_admin and target_user != auth_user:
        #     raise AuthError(403, "You are not a server admin")

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

        term = parse_string(request, "term", required=True)
        logger.info("term: %s ", term)

        ret = yield self.handlers.admin_handler.search_users(
            term
        )
        defer.returnValue((200, ret))
Пример #12
0
    def _async_render_GET(self, request):
        limit = parse_integer(request, "limit", 100)
        timeout = parse_integer(request, "timeout", 10 * 1000)

        request.setHeader(b"Content-Type", b"application/json")

        request_streams = {
            name: parse_integer(request, name)
            for names in STREAM_NAMES for name in names
        }
        request_streams["streams"] = parse_string(request, "streams")

        def replicate():
            return self.replicate(request_streams, limit)

        result = yield self.notifier.wait_for_replication(replicate, timeout)

        for stream_name, stream_content in result.items():
            logger.info(
                "Replicating %d rows of %s from %s -> %s",
                len(stream_content["rows"]),
                stream_name,
                request_streams.get(stream_name),
                stream_content["position"],
            )

        request.write(json.dumps(result, ensure_ascii=False))
        finish_request(request)
Пример #13
0
    def on_PUT_or_POST(
        self, request, room_id, parent_id, relation_type, event_type, txn_id=None
    ):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

        if event_type == EventTypes.Member:
            # Add relations to a membership is meaningless, so we just deny it
            # at the CS API rather than trying to handle it correctly.
            raise SynapseError(400, "Cannot send member events with relations")

        content = parse_json_object_from_request(request)

        aggregation_key = parse_string(request, "key", encoding="utf-8")

        content["m.relates_to"] = {
            "event_id": parent_id,
            "key": aggregation_key,
            "rel_type": relation_type,
        }

        event_dict = {
            "type": event_type,
            "content": content,
            "room_id": room_id,
            "sender": requester.user.to_string(),
        }

        event = yield self.event_creation_handler.create_and_send_nonmember_event(
            requester, event_dict=event_dict, txn_id=txn_id
        )

        defer.returnValue((200, {"event_id": event.event_id}))
Пример #14
0
    def on_POST(self, request):
        yield self.auth.get_user_by_req(request, allow_guest=True)

        server = parse_string(request, "server", default=None)
        content = parse_json_object_from_request(request)

        limit = int(content.get("limit", 100))
        since_token = content.get("since", None)
        search_filter = content.get("filter", None)

        handler = self.hs.get_room_list_handler()
        if server:
            data = yield handler.get_remote_public_room_list(
                server,
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
            )
        else:
            data = yield handler.get_local_public_room_list(
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
            )

        defer.returnValue((200, data))
Пример #15
0
 def on_GET(self, request):
     client_redirect_url = parse_string(request, "redirectUrl", required=True)
     http_client = self.hs.get_simple_http_client()
     uri = self.cas_server_url + "/proxyValidate"
     args = {
         "ticket": parse_string(request, "ticket", required=True),
         "service": self.cas_service_url
     }
     try:
         body = yield http_client.get_raw(uri, args)
     except PartialDownloadError as pde:
         # Twisted raises this error if the connection is closed,
         # even if that's being used old-http style to signal end-of-data
         body = pde.response
     result = yield self.handle_cas_response(request, body, client_redirect_url)
     defer.returnValue(result)
Пример #16
0
    def on_GET(self, request, room_id, parent_id, relation_type, event_type, key):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

        yield self.auth.check_in_room_or_world_readable(
            room_id, requester.user.to_string()
        )

        # This checks that a) the event exists and b) the user is allowed to
        # view it.
        yield self.event_handler.get_event(requester.user, room_id, parent_id)

        if relation_type != RelationTypes.ANNOTATION:
            raise SynapseError(400, "Relation type must be 'annotation'")

        limit = parse_integer(request, "limit", default=5)
        from_token = parse_string(request, "from")
        to_token = parse_string(request, "to")

        if from_token:
            from_token = RelationPaginationToken.from_string(from_token)

        if to_token:
            to_token = RelationPaginationToken.from_string(to_token)

        result = yield self.store.get_relations_for_event(
            event_id=parent_id,
            relation_type=relation_type,
            event_type=event_type,
            aggregation_key=key,
            limit=limit,
            from_token=from_token,
            to_token=to_token,
        )

        events = yield self.store.get_events_as_list(
            [c["event_id"] for c in result.chunk]
        )

        now = self.clock.time_msec()
        events = yield self._event_serializer.serialize_events(events, now)

        return_value = result.to_dict()
        return_value["chunk"] = events

        defer.returnValue((200, return_value))
Пример #17
0
    def on_GET(self, request):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

        from_token_string = parse_string(request, "from")

        # We want to enforce they do pass us one, but we ignore it and return
        # changes after the "to" as well as before.
        parse_string(request, "to")

        from_token = StreamToken.from_string(from_token_string)

        user_id = requester.user.to_string()

        results = yield self.device_handler.get_user_ids_changed(
            user_id, from_token,
        )

        defer.returnValue((200, results))
Пример #18
0
    def on_GET(self, request):
        ip = self.hs.get_ip_from_request(request)
        with self.ratelimiter.ratelimit(ip) as wait_deferred:
            yield wait_deferred

            username = parse_string(request, "username", required=True)

            yield self.registration_handler.check_username(username)

            defer.returnValue((200, {"available": True}))
Пример #19
0
    def on_GET(self, request, room_id):
        # TODO support Pagination stream API (limit/tokens)
        requester = yield self.auth.get_user_by_req(request)
        handler = self.message_handler

        # request the state as of a given event, as identified by a stream token,
        # for consistency with /messages etc.
        # useful for getting the membership in retrospect as of a given /sync
        # response.
        at_token_string = parse_string(request, "at")
        if at_token_string is None:
            at_token = None
        else:
            at_token = StreamToken.from_string(at_token_string)

        # let you filter down on particular memberships.
        # XXX: this may not be the best shape for this API - we could pass in a filter
        # instead, except filters aren't currently aware of memberships.
        # See https://github.com/matrix-org/matrix-doc/issues/1337 for more details.
        membership = parse_string(request, "membership")
        not_membership = parse_string(request, "not_membership")

        events = yield handler.get_state_events(
            room_id=room_id,
            user_id=requester.user.to_string(),
            at_token=at_token,
            state_filter=StateFilter.from_types([(EventTypes.Member, None)]),
        )

        chunk = []

        for event in events:
            if (
                (membership and event['content'].get("membership") != membership) or
                (not_membership and event['content'].get("membership") == not_membership)
            ):
                continue
            chunk.append(event)

        defer.returnValue((200, {
            "chunk": chunk
        }))
Пример #20
0
    async def _async_render_POST(self, request: Request) -> Tuple[int, bytes]:
        sid = parse_string(request, "sid", required=True)
        token = parse_string(request, "token", required=True)
        client_secret = parse_string(request, "client_secret", required=True)

        # Attempt to validate a 3PID session
        try:
            # Mark the session as valid
            next_link = await self.store.validate_threepid_session(
                sid, client_secret, token, self.clock.time_msec())

            # Perform a 302 redirect if next_link is set
            if next_link:
                if next_link.startswith("file:///"):
                    logger.warning(
                        "Not redirecting to next_link as it is a local file: address"
                    )
                else:
                    next_link_bytes = next_link.encode("utf-8")
                    request.setHeader("Location", next_link_bytes)
                    return (
                        302,
                        (b'You are being redirected to <a src="%s">%s</a>.' %
                         (next_link_bytes, next_link_bytes)),
                    )

            # Otherwise show the success template
            html_bytes = self._email_password_reset_template_success_html.encode(
                "utf-8")
            status_code = 200
        except ThreepidValidationError as e:
            status_code = e.code

            # Show a failure page with a reason
            template_vars = {"failure_reason": e.msg}
            html_bytes = self._failure_email_template.render(
                **template_vars).encode("utf-8")

        return status_code, html_bytes
Пример #21
0
    def on_POST(self, request):
        requester = yield self.auth.get_user_by_req(request)

        content = parse_json_object_from_request(request)

        batch = parse_string(request, "next_batch")
        results = yield self.handlers.search_handler.search(
            requester.user,
            content,
            batch,
        )

        defer.returnValue((200, results))
Пример #22
0
    async def on_GET(self, request: Request) -> Tuple[int, JsonDict]:
        await self.ratelimiter.ratelimit(None,
                                         (request.getClientAddress().host, ))

        if not self.hs.config.registration.enable_registration:
            raise SynapseError(403,
                               "Registration has been disabled",
                               errcode=Codes.FORBIDDEN)

        token = parse_string(request, "token", required=True)
        valid = await self.store.registration_token_is_valid(token)

        return 200, {"valid": valid}
Пример #23
0
    async def on_GET(self, request, room_id):
        # TODO support Pagination stream API (limit/tokens)
        requester = await self.auth.get_user_by_req(request, allow_guest=True)
        handler = self.message_handler

        # request the state as of a given event, as identified by a stream token,
        # for consistency with /messages etc.
        # useful for getting the membership in retrospect as of a given /sync
        # response.
        at_token_string = parse_string(request, "at")
        if at_token_string is None:
            at_token = None
        else:
            at_token = await StreamToken.from_string(self.store, at_token_string)

        # let you filter down on particular memberships.
        # XXX: this may not be the best shape for this API - we could pass in a filter
        # instead, except filters aren't currently aware of memberships.
        # See https://github.com/matrix-org/matrix-doc/issues/1337 for more details.
        membership = parse_string(request, "membership")
        not_membership = parse_string(request, "not_membership")

        events = await handler.get_state_events(
            room_id=room_id,
            user_id=requester.user.to_string(),
            at_token=at_token,
            state_filter=StateFilter.from_types([(EventTypes.Member, None)]),
        )

        chunk = []

        for event in events:
            if (membership and event["content"].get("membership") != membership) or (
                not_membership and event["content"].get("membership") == not_membership
            ):
                continue
            chunk.append(event)

        return 200, {"chunk": chunk}
Пример #24
0
    def on_POST(self, request):
        requester = yield self.auth.get_user_by_req(request)

        content = parse_json_object_from_request(request)

        batch = parse_string(request, "next_batch")
        results = yield self.handlers.search_handler.search(
            requester.user,
            content,
            batch,
        )

        defer.returnValue((200, results))
Пример #25
0
    def on_GET(self, request):
        server = parse_string(request, "server", default=None)

        try:
            yield self.auth.get_user_by_req(request, allow_guest=True)
        except AuthError as e:
            # Option to allow servers to require auth when accessing
            # /publicRooms via CS API. This is especially helpful in private
            # federations.
            if self.hs.config.restrict_public_rooms_to_local_users:
                raise

            # We allow people to not be authed if they're just looking at our
            # room list, but require auth when we proxy the request.
            # In both cases we call the auth function, as that has the side
            # effect of logging who issued this request if an access token was
            # provided.
            if server:
                raise e
            else:
                pass

        limit = parse_integer(request, "limit", 0)
        since_token = parse_string(request, "since", None)

        handler = self.hs.get_room_list_handler()
        if server:
            data = yield handler.get_remote_public_room_list(
                server,
                limit=limit,
                since_token=since_token,
            )
        else:
            data = yield handler.get_local_public_room_list(
                limit=limit,
                since_token=since_token,
            )

        defer.returnValue((200, data))
Пример #26
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")
Пример #27
0
    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
Пример #28
0
    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 = yield 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")
Пример #29
0
    async def on_POST(self, request):
        await self.auth.get_user_by_req(request, allow_guest=True)

        server = parse_string(request, "server", default=None)
        content = parse_json_object_from_request(request)

        limit = int(content.get("limit", 100))  # type: Optional[int]
        since_token = content.get("since", None)
        search_filter = content.get("filter", None)

        include_all_networks = content.get("include_all_networks", False)
        third_party_instance_id = content.get("third_party_instance_id", None)

        if include_all_networks:
            network_tuple = None
            if third_party_instance_id is not None:
                raise SynapseError(
                    400,
                    "Can't use include_all_networks with an explicit network")
        elif third_party_instance_id is None:
            network_tuple = ThirdPartyInstanceID(None, None)
        else:
            network_tuple = ThirdPartyInstanceID.from_string(
                third_party_instance_id)

        if limit == 0:
            # zero is a special value which corresponds to no limit.
            limit = None

        handler = self.hs.get_room_list_handler()
        if server and server != self.hs.config.server_name:
            try:
                data = await handler.get_remote_public_room_list(
                    server,
                    limit=limit,
                    since_token=since_token,
                    search_filter=search_filter,
                    include_all_networks=include_all_networks,
                    third_party_instance_id=third_party_instance_id,
                )
            except HttpResponseException as e:
                raise e.to_synapse_error()
        else:
            data = await handler.get_local_public_room_list(
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
                network_tuple=network_tuple,
            )

        return 200, data
Пример #30
0
    async def on_GET(self, request):
        server = parse_string(request, "server", default=None)

        try:
            await self.auth.get_user_by_req(request, allow_guest=True)
        except InvalidClientCredentialsError as e:
            # Option to allow servers to require auth when accessing
            # /publicRooms via CS API. This is especially helpful in private
            # federations.
            if not self.hs.config.allow_public_rooms_without_auth:
                raise

            # We allow people to not be authed if they're just looking at our
            # room list, but require auth when we proxy the request.
            # In both cases we call the auth function, as that has the side
            # effect of logging who issued this request if an access token was
            # provided.
            if server:
                raise e
            else:
                pass

        limit = parse_integer(request, "limit", 0)
        since_token = parse_string(request, "since", None)

        if limit == 0:
            # zero is a special value which corresponds to no limit.
            limit = None

        handler = self.hs.get_room_list_handler()
        if server:
            data = await handler.get_remote_public_room_list(
                server, limit=limit, since_token=since_token)
        else:
            data = await handler.get_local_public_room_list(
                limit=limit, since_token=since_token)

        return 200, data
Пример #31
0
    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)
        direction = parse_string(request, "dir", default="b")
        user_id = parse_string(request, "user_id")
        room_id = parse_string(request, "room_id")

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

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

        if direction not in ("f", "b"):
            raise SynapseError(
                HTTPStatus.BAD_REQUEST,
                "Unknown direction: %s" % (direction,),
                errcode=Codes.INVALID_PARAM,
            )

        event_reports, total = await self.store.get_event_reports_paginate(
            start, limit, direction, user_id, room_id
        )
        ret = {"event_reports": event_reports, "total": total}
        if (start + limit) < total:
            ret["next_token"] = start + len(event_reports)

        return HTTPStatus.OK, ret
Пример #32
0
    def on_GET(self, request, room_id, parent_id, relation_type=None, event_type=None):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

        yield self.auth.check_in_room_or_world_readable(
            room_id, requester.user.to_string()
        )

        # This checks that a) the event exists and b) the user is allowed to
        # view it.
        event = yield self.event_handler.get_event(requester.user, room_id, parent_id)

        if relation_type not in (RelationTypes.ANNOTATION, None):
            raise SynapseError(400, "Relation type must be 'annotation'")

        limit = parse_integer(request, "limit", default=5)
        from_token = parse_string(request, "from")
        to_token = parse_string(request, "to")

        if event.internal_metadata.is_redacted():
            # If the event is redacted, return an empty list of relations
            pagination_chunk = PaginationChunk(chunk=[])
        else:
            # Return the relations
            if from_token:
                from_token = AggregationPaginationToken.from_string(from_token)

            if to_token:
                to_token = AggregationPaginationToken.from_string(to_token)

            pagination_chunk = yield self.store.get_aggregation_groups_for_event(
                event_id=parent_id,
                event_type=event_type,
                limit=limit,
                from_token=from_token,
                to_token=to_token,
            )

        return 200, pagination_chunk.to_dict()
Пример #33
0
    def _async_render_GET(self, request):
        server_name, media_id, _ = parse_media_id(request)
        width = parse_integer(request, "width")
        height = parse_integer(request, "height")
        method = parse_string(request, "method", "scale")
        m_type = parse_string(request, "type", "image/png")

        if server_name == self.server_name:
            if self.dynamic_thumbnails:
                yield self._select_or_generate_local_thumbnail(
                    request, media_id, width, height, method, m_type)
            else:
                yield self._respond_local_thumbnail(request, media_id, width,
                                                    height, method, m_type)
        else:
            if self.dynamic_thumbnails:
                yield self._select_or_generate_remote_thumbnail(
                    request, server_name, media_id, width, height, method,
                    m_type)
            else:
                yield self._respond_remote_thumbnail(request, server_name,
                                                     media_id, width, height,
                                                     method, m_type)
Пример #34
0
    async def _async_render_POST(self, request):
        requester = await self.auth.get_user_by_req(request)
        # TODO: The checks here are a bit late. The content will have
        # already been uploaded to a tmp file at this point
        content_length = request.getHeader("Content-Length")
        if content_length is None:
            raise SynapseError(msg="Request must specify a Content-Length",
                               code=400)
        if int(content_length) > self.max_upload_size:
            raise SynapseError(
                msg="Upload request body is too large",
                code=413,
                errcode=Codes.TOO_LARGE,
            )

        upload_name = parse_string(request, b"filename", encoding=None)
        if upload_name:
            try:
                upload_name = upload_name.decode("utf8")
            except UnicodeDecodeError:
                raise SynapseError(msg="Invalid UTF-8 filename parameter: %r" %
                                   (upload_name),
                                   code=400)

        # If the name is falsey (e.g. an empty byte string) ensure it is None.
        else:
            upload_name = None

        headers = request.requestHeaders

        if headers.hasHeader(b"Content-Type"):
            media_type = headers.getRawHeaders(b"Content-Type")[0].decode(
                "ascii")
        else:
            raise SynapseError(msg="Upload request missing 'Content-Type'",
                               code=400)

        # if headers.hasHeader(b"Content-Disposition"):
        #     disposition = headers.getRawHeaders(b"Content-Disposition")[0]
        # TODO(markjh): parse content-dispostion

        content_uri = await self.media_repo.create_content(
            media_type, upload_name, request.content, content_length,
            requester.user)

        logger.info("Uploaded content with URI %r", content_uri)

        respond_with_json(request,
                          200, {"content_uri": content_uri},
                          send_cors=True)
Пример #35
0
    def on_GET(self,
               request,
               room_id,
               parent_id,
               relation_type=None,
               event_type=None):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

        yield self.auth.check_in_room_or_world_readable(
            room_id, requester.user.to_string())

        # This checks that a) the event exists and b) the user is allowed to
        # view it.
        yield self.event_handler.get_event(requester.user, room_id, parent_id)

        if relation_type not in (RelationTypes.ANNOTATION, None):
            raise SynapseError(400, "Relation type must be 'annotation'")

        limit = parse_integer(request, "limit", default=5)
        from_token = parse_string(request, "from")
        to_token = parse_string(request, "to")

        if from_token:
            from_token = AggregationPaginationToken.from_string(from_token)

        if to_token:
            to_token = AggregationPaginationToken.from_string(to_token)

        res = yield self.store.get_aggregation_groups_for_event(
            event_id=parent_id,
            event_type=event_type,
            limit=limit,
            from_token=from_token,
            to_token=to_token,
        )

        defer.returnValue((200, res.to_dict()))
Пример #36
0
    def _async_render_POST(self, request):
        requester = yield self.auth.get_user_by_req(request)
        # TODO: The checks here are a bit late. The content will have
        # already been uploaded to a tmp file at this point
        content_length = request.getHeader(b"Content-Length").decode('ascii')
        if content_length is None:
            raise SynapseError(
                msg="Request must specify a Content-Length", code=400
            )
        if int(content_length) > self.max_upload_size:
            raise SynapseError(
                msg="Upload request body is too large",
                code=413,
            )

        upload_name = parse_string(request, b"filename", encoding=None)
        if upload_name:
            try:
                upload_name = upload_name.decode('utf8')
            except UnicodeDecodeError:
                raise SynapseError(
                    msg="Invalid UTF-8 filename parameter: %r" % (upload_name),
                    code=400,
                )

        headers = request.requestHeaders

        if headers.hasHeader(b"Content-Type"):
            media_type = headers.getRawHeaders(b"Content-Type")[0].decode('ascii')
        else:
            raise SynapseError(
                msg="Upload request missing 'Content-Type'",
                code=400,
            )

        # if headers.hasHeader(b"Content-Disposition"):
        #     disposition = headers.getRawHeaders(b"Content-Disposition")[0]
        # TODO(markjh): parse content-dispostion

        content_uri = yield self.media_repo.create_content(
            media_type, upload_name, request.content,
            content_length, requester.user
        )

        logger.info("Uploaded content with URI %r", content_uri)

        respond_with_json(
            request, 200, {"content_uri": content_uri}, send_cors=True
        )
Пример #37
0
    def from_request(cls,
                     request,
                     raise_invalid_params=True,
                     default_limit=None):
        direction = parse_string(request,
                                 "dir",
                                 default="f",
                                 allowed_values=["f", "b"])

        from_tok = parse_string(request, "from")
        to_tok = parse_string(request, "to")

        try:
            if from_tok == "END":
                from_tok = None  # For backwards compat.
            elif from_tok:
                from_tok = StreamToken.from_string(from_tok)
        except Exception:
            raise SynapseError(400, "'from' paramater is invalid")

        try:
            if to_tok:
                to_tok = StreamToken.from_string(to_tok)
        except Exception:
            raise SynapseError(400, "'to' paramater is invalid")

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

        if limit and limit < 0:
            raise SynapseError(400, "Limit must be 0 or above")

        try:
            return PaginationConfig(from_tok, to_tok, direction, limit)
        except Exception:
            logger.exception("Failed to create pagination config")
            raise SynapseError(400, "Invalid request.")
Пример #38
0
    async def on_GET(self, request):
        requester = await self.auth.get_user_by_req(request, rights="delete_pusher")
        user = requester.user

        app_id = parse_string(request, "app_id", required=True)
        pushkey = parse_string(request, "pushkey", required=True)

        try:
            await self.pusher_pool.remove_pusher(
                app_id=app_id, pushkey=pushkey, user_id=user.to_string()
            )
        except StoreError as se:
            if se.code != 404:
                # This is fine: they're already unsubscribed
                raise

        self.notifier.on_new_replication_data()

        respond_with_html_bytes(
            request,
            200,
            PushersRemoveRestServlet.SUCCESS_HTML,
        )
        return None
Пример #39
0
    async def _async_render_GET(self, request: SynapseRequest) -> None:
        token = parse_string(request, "access_token", required=True)
        app_id = parse_string(request, "app_id", required=True)
        pushkey = parse_string(request, "pushkey", required=True)

        user_id = self.macaroon_generator.verify_delete_pusher_token(
            token, app_id, pushkey)

        try:
            await self.pusher_pool.remove_pusher(app_id=app_id,
                                                 pushkey=pushkey,
                                                 user_id=user_id)
        except StoreError as se:
            if se.code != 404:
                # This is fine: they're already unsubscribed
                raise

        self.notifier.on_new_replication_data()

        respond_with_html_bytes(
            request,
            200,
            UnsubscribeResource.SUCCESS_HTML,
        )
Пример #40
0
    def on_GET(self, request):
        if not self.hs.config.enable_registration:
            raise SynapseError(403,
                               "Registration has been disabled",
                               errcode=Codes.FORBIDDEN)

        ip = self.hs.get_ip_from_request(request)
        with self.ratelimiter.ratelimit(ip) as wait_deferred:
            yield wait_deferred

            username = parse_string(request, "username", required=True)

            yield self.registration_handler.check_username(username)

            return 200, {"available": True}
Пример #41
0
    async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        """Proxy a /_matrix/identity/api/v1/lookup request to an identity
        server
        """
        await self.auth.get_user_by_req(request)

        # Verify query parameters
        # Mypy will complain that request.args is of an incompatible type with JsonDict
        # because Twisted is badly typed, so we just ignore it.
        query_params: JsonDict = request.args  # type: ignore[assignment]
        assert_params_in_dict(query_params,
                              [b"medium", b"address", b"id_server"])

        # Retrieve needed information from query parameters
        medium = parse_string(request, "medium", required=True)
        address = parse_string(request, "address", required=True)
        id_server = parse_string(request, "id_server", required=True)

        # Proxy the request to the identity server. lookup_3pid handles checking
        # if the lookup is allowed so we don't need to do it here.
        ret = await self.identity_handler.proxy_lookup_3pid(
            id_server, medium, address)

        return 200, ret
Пример #42
0
    async def on_GET(self, request: Request) -> Tuple[int, JsonDict]:
        if not self.hs.config.registration.enable_registration:
            raise SynapseError(403,
                               "Registration has been disabled",
                               errcode=Codes.FORBIDDEN)

        ip = request.getClientIP()
        with self.ratelimiter.ratelimit(ip) as wait_deferred:
            await wait_deferred

            username = parse_string(request, "username", required=True)

            await self.registration_handler.check_username(username)

            return 200, {"available": True}
Пример #43
0
 async def on_GET(self,
                  request: SynapseRequest,
                  idp_id: Optional[str] = None) -> None:
     client_redirect_url = parse_string(request,
                                        "redirectUrl",
                                        required=True,
                                        encoding=None)
     sso_url = await self._sso_handler.handle_redirect_request(
         request,
         client_redirect_url,
         idp_id,
     )
     logger.info("Redirecting to %s", sso_url)
     request.redirect(sso_url)
     finish_request(request)
Пример #44
0
    async def on_GET(
        self, request: SynapseRequest, room_id: str, event_id: str
    ) -> Tuple[int, JsonDict]:
        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,
            # No need to bundle aggregations for state events
            bundle_aggregations=False,
        )

        return 200, results
Пример #45
0
    async def on_GET(self, request):
        await assert_requester_is_admin(self.auth, request)

        start = parse_integer(request, "from", default=0)
        limit = parse_integer(request, "limit", default=100)
        user_id = parse_string(request, "user_id", 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, guests, deactivated)
        ret = {"users": users, "total": total}
        if len(users) >= limit:
            ret["next_token"] = str(start + len(users))

        return 200, ret
Пример #46
0
    def on_GET(self, request, room_id, event_id):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

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

        # picking the API shape for symmetry with /messages
        filter_bytes = parse_string(request, "filter")
        if filter_bytes:
            filter_json = urlparse.unquote(filter_bytes)
            event_filter = Filter(json.loads(filter_json))
        else:
            event_filter = None

        results = yield self.room_context_handler.get_event_context(
            requester.user,
            room_id,
            event_id,
            limit,
            event_filter,
        )

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

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

        defer.returnValue((200, results))
Пример #47
0
    def streams(self, writer, current_token):
        request_token = parse_string(writer.request, "streams")

        streams = []

        if request_token is not None:
            if request_token == "-1":
                for names, position in zip(STREAM_NAMES, current_token):
                    streams.extend((name, position) for name in names)
            else:
                items = zip(STREAM_NAMES, current_token, _ReplicationToken(request_token))
                for names, current_id, last_id in items:
                    if last_id < current_id:
                        streams.extend((name, current_id) for name in names)

            if streams:
                writer.write_header_and_rows("streams", streams, ("name", "position"), position=str(current_token))
Пример #48
0
    def on_GET(self, request):
        token = parse_string(request, "access_token")
        if token is None:
            defer.returnValue((401, {
                "errcode": "M_MISSING_TOKEN", "error": "Access Token required"
            }))
            return

        user_id = yield self.handler.on_openid_userinfo(token)

        if user_id is None:
            defer.returnValue((401, {
                "errcode": "M_UNKNOWN_TOKEN",
                "error": "Access Token unknown or expired"
            }))

        defer.returnValue((200, {"sub": user_id}))
Пример #49
0
    async def on_PUT_or_POST(
        self,
        request: SynapseRequest,
        room_id: str,
        parent_id: str,
        relation_type: str,
        event_type: str,
        txn_id: Optional[str] = None,
    ) -> Tuple[int, JsonDict]:
        requester = await self.auth.get_user_by_req(request, allow_guest=True)

        if event_type == EventTypes.Member:
            # Add relations to a membership is meaningless, so we just deny it
            # at the CS API rather than trying to handle it correctly.
            raise SynapseError(400, "Cannot send member events with relations")

        content = parse_json_object_from_request(request)

        aggregation_key = parse_string(request, "key", encoding="utf-8")

        content["m.relates_to"] = {
            "event_id": parent_id,
            "rel_type": relation_type,
        }
        if aggregation_key is not None:
            content["m.relates_to"]["key"] = aggregation_key

        event_dict = {
            "type": event_type,
            "content": content,
            "room_id": room_id,
            "sender": requester.user.to_string(),
        }

        try:
            (
                event,
                _,
            ) = await self.event_creation_handler.create_and_send_nonmember_event(
                requester, event_dict=event_dict, txn_id=txn_id
            )
            event_id = event.event_id
        except ShadowBanError:
            event_id = "$" + random_string(43)

        return 200, {"event_id": event_id}
Пример #50
0
    async def _async_render_POST(self, request: Request):
        try:
            session_id = get_username_mapping_session_cookie_from_request(request)
        except SynapseError as e:
            logger.warning("Error fetching session cookie: %s", e)
            self._sso_handler.render_error(request, "bad_session", e.msg, code=e.code)
            return

        try:
            accepted_version = parse_string(request, "accepted_version", required=True)
        except SynapseError as e:
            self._sso_handler.render_error(request, "bad_param", e.msg, code=e.code)
            return

        await self._sso_handler.handle_terms_accepted(
            request, session_id, accepted_version
        )
Пример #51
0
    def on_GET(self, request, stagetype):
        session = parse_string(request, "session")
        if not session:
            raise SynapseError(400, "No session supplied")

        if stagetype == LoginType.RECAPTCHA:
            html = RECAPTCHA_TEMPLATE % {
                'session':
                session,
                'myurl':
                "%s/auth/%s/fallback/web" %
                (CLIENT_V2_ALPHA_PREFIX, LoginType.RECAPTCHA),
                'sitekey':
                self.hs.config.recaptcha_public_key,
            }
            html_bytes = html.encode("utf8")
            request.setResponseCode(200)
            request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
            request.setHeader(b"Content-Length", b"%d" % (len(html_bytes), ))

            request.write(html_bytes)
            finish_request(request)
            return None
        elif stagetype == LoginType.TERMS:
            html = TERMS_TEMPLATE % {
                'session':
                session,
                'terms_url':
                "%s_matrix/consent?v=%s" % (
                    self.hs.config.public_baseurl,
                    self.hs.config.user_consent_version,
                ),
                'myurl':
                "%s/auth/%s/fallback/web" %
                (CLIENT_V2_ALPHA_PREFIX, LoginType.TERMS),
            }
            html_bytes = html.encode("utf8")
            request.setResponseCode(200)
            request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
            request.setHeader(b"Content-Length", b"%d" % (len(html_bytes), ))

            request.write(html_bytes)
            finish_request(request)
            return None
        else:
            raise SynapseError(404, "Unknown auth stage type")
Пример #52
0
    def on_GET(self, request):
        token = parse_string(request, "access_token")
        if token is None:
            defer.returnValue((401, {
                "errcode": "M_MISSING_TOKEN",
                "error": "Access Token required"
            }))
            return

        user_id = yield self.handler.on_openid_userinfo(token)

        if user_id is None:
            defer.returnValue((401, {
                "errcode": "M_UNKNOWN_TOKEN",
                "error": "Access Token unknown or expired"
            }))

        defer.returnValue((200, {"sub": user_id}))
Пример #53
0
    def on_POST(self, request):
        yield self.auth.get_user_by_req(request, allow_guest=True)

        server = parse_string(request, "server", default=None)
        content = parse_json_object_from_request(request)

        limit = int(content.get("limit", 100))
        since_token = content.get("since", None)
        search_filter = content.get("filter", None)

        include_all_networks = content.get("include_all_networks", False)
        third_party_instance_id = content.get("third_party_instance_id", None)

        if include_all_networks:
            network_tuple = None
            if third_party_instance_id is not None:
                raise SynapseError(
                    400,
                    "Can't use include_all_networks with an explicit network")
        elif third_party_instance_id is None:
            network_tuple = ThirdPartyInstanceID(None, None)
        else:
            network_tuple = ThirdPartyInstanceID.from_string(
                third_party_instance_id)

        handler = self.hs.get_room_list_handler()
        if server:
            data = yield handler.get_remote_public_room_list(
                server,
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
                include_all_networks=include_all_networks,
                third_party_instance_id=third_party_instance_id,
            )
        else:
            data = yield handler.get_local_public_room_list(
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
                network_tuple=network_tuple,
            )

        defer.returnValue((200, data))
Пример #54
0
    def on_POST(self, request):
        yield self.auth.get_user_by_req(request, allow_guest=True)

        server = parse_string(request, "server", default=None)
        content = parse_json_object_from_request(request)

        limit = int(content.get("limit", 100))
        since_token = content.get("since", None)
        search_filter = content.get("filter", None)

        include_all_networks = content.get("include_all_networks", False)
        third_party_instance_id = content.get("third_party_instance_id", None)

        if include_all_networks:
            network_tuple = None
            if third_party_instance_id is not None:
                raise SynapseError(
                    400, "Can't use include_all_networks with an explicit network"
                )
        elif third_party_instance_id is None:
            network_tuple = ThirdPartyInstanceID(None, None)
        else:
            network_tuple = ThirdPartyInstanceID.from_string(third_party_instance_id)

        handler = self.hs.get_room_list_handler()
        if server:
            data = yield handler.get_remote_public_room_list(
                server,
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
                include_all_networks=include_all_networks,
                third_party_instance_id=third_party_instance_id,
            )
        else:
            data = yield handler.get_local_public_room_list(
                limit=limit,
                since_token=since_token,
                search_filter=search_filter,
                network_tuple=network_tuple,
            )

        defer.returnValue((200, data))
Пример #55
0
    def on_GET(self, request, stagetype):
        session = parse_string(request, "session")
        if not session:
            raise SynapseError(400, "No session supplied")

        if stagetype == LoginType.RECAPTCHA:
            html = RECAPTCHA_TEMPLATE % {
                'session': session,
                'myurl': "%s/r0/auth/%s/fallback/web" % (
                    CLIENT_API_PREFIX, LoginType.RECAPTCHA
                ),
                'sitekey': self.hs.config.recaptcha_public_key,
            }
            html_bytes = html.encode("utf8")
            request.setResponseCode(200)
            request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
            request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))

            request.write(html_bytes)
            finish_request(request)
            return None
        elif stagetype == LoginType.TERMS:
            html = TERMS_TEMPLATE % {
                'session': session,
                'terms_url': "%s_matrix/consent?v=%s" % (
                    self.hs.config.public_baseurl,
                    self.hs.config.user_consent_version,
                ),
                'myurl': "%s/r0/auth/%s/fallback/web" % (
                    CLIENT_API_PREFIX, LoginType.TERMS
                ),
            }
            html_bytes = html.encode("utf8")
            request.setResponseCode(200)
            request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
            request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))

            request.write(html_bytes)
            finish_request(request)
            return None
        else:
            raise SynapseError(404, "Unknown auth stage type")
Пример #56
0
    def streams(self, writer, current_token):
        request_token = parse_string(writer.request, "streams")

        streams = []

        if request_token is not None:
            if request_token == "-1":
                for names, position in zip(STREAM_NAMES, current_token):
                    streams.extend((name, position) for name in names)
            else:
                items = zip(STREAM_NAMES, current_token,
                            _ReplicationToken(request_token))
                for names, current_id, last_id in items:
                    if last_id < current_id:
                        streams.extend((name, current_id) for name in names)

            if streams:
                writer.write_header_and_rows("streams",
                                             streams, ("name", "position"),
                                             position=str(current_token))
Пример #57
0
    def on_GET(self, request, room_id, event_id):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)

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

        # picking the API shape for symmetry with /messages
        filter_bytes = parse_string(request, "filter")
        if filter_bytes:
            filter_json = urlparse.unquote(filter_bytes)
            event_filter = Filter(json.loads(filter_json))
        else:
            event_filter = None

        results = yield self.room_context_handler.get_event_context(
            requester.user,
            room_id,
            event_id,
            limit,
            event_filter,
        )

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

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

        defer.returnValue((200, results))
Пример #58
0
    def on_GET(self, request, room_id):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)
        pagination_config = PaginationConfig.from_request(
            request, default_limit=10,
        )
        as_client_event = b"raw" not in request.args
        filter_bytes = parse_string(request, b"filter", encoding=None)
        if filter_bytes:
            filter_json = urlparse.unquote(filter_bytes.decode("UTF-8"))
            event_filter = Filter(json.loads(filter_json))
        else:
            event_filter = None
        msgs = yield self.pagination_handler.get_messages(
            room_id=room_id,
            requester=requester,
            pagin_config=pagination_config,
            as_client_event=as_client_event,
            event_filter=event_filter,
        )

        defer.returnValue((200, msgs))
Пример #59
0
    def on_DELETE(self, request, room_id, session_id):
        """
        Deletes one or more encrypted E2E room keys for a user for backup purposes.

        DELETE /room_keys/keys/!abc:matrix.org/c0ff33?version=1
        HTTP/1.1 200 OK
        {}

        room_id: the ID of the room whose keys to delete (optional)
        session_id: the ID for the E2E session to delete (optional)
        version: the version of the user's backup which this data is for.
        the version must already have been created via the /change_secret API.
        """

        requester = yield self.auth.get_user_by_req(request, allow_guest=False)
        user_id = requester.user.to_string()
        version = parse_string(request, "version")

        yield self.e2e_room_keys_handler.delete_room_keys(
            user_id, version, room_id, session_id
        )
        defer.returnValue((200, {}))
Пример #60
0
    def on_GET(self, request, room_id, event_type, state_key):
        requester = yield self.auth.get_user_by_req(request, allow_guest=True)
        format = parse_string(request, "format", default="content",
                              allowed_values=["content", "event"])

        msg_handler = self.message_handler
        data = yield msg_handler.get_room_data(
            user_id=requester.user.to_string(),
            room_id=room_id,
            event_type=event_type,
            state_key=state_key,
            is_guest=requester.is_guest,
        )

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

        if format == "event":
            event = format_event_for_client_v2(data.get_dict())
            defer.returnValue((200, event))
        elif format == "content":
            defer.returnValue((200, data.get_dict()["content"]))