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, )
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()))
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")
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))
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.")
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 )
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)
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, {}))
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, }))
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))
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))
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)
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}))
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))
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)
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))
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))
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}))
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 }))
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
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))
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}
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}
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))
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")
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
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")
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
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
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
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()
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)
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)
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()))
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 )
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.")
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
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, )
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}
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
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}
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)
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
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
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))
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))
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}))
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}
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 )
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")
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))
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))
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")
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))
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))
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, {}))
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"]))