From c833250182fe3dffd1b68433b2142cb242610b57 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Aug 2020 13:11:02 +0300 Subject: [PATCH] Add endpoint for sending forwards --- synapse/rest/__init__.py | 2 + synapse/rest/client/v2_alpha/forward_event.py | 118 ++++++++++++++++++ synapse/rest/client/versions.py | 2 + 3 files changed, 122 insertions(+) create mode 100644 synapse/rest/client/v2_alpha/forward_event.py diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py index 46e458e95..811982578 100644 --- a/synapse/rest/__init__.py +++ b/synapse/rest/__init__.py @@ -47,6 +47,7 @@ from synapse.rest.client.v2_alpha import ( register, relations, report_event, + forward_event, room_keys, room_upgrade_rest_servlet, sendtodevice, @@ -108,6 +109,7 @@ class ClientRestResource(JsonResource): tags.register_servlets(hs, client_resource) account_data.register_servlets(hs, client_resource) report_event.register_servlets(hs, client_resource) + forward_event.register_servlets(hs, client_resource) openid.register_servlets(hs, client_resource) notifications.register_servlets(hs, client_resource) devices.register_servlets(hs, client_resource) diff --git a/synapse/rest/client/v2_alpha/forward_event.py b/synapse/rest/client/v2_alpha/forward_event.py new file mode 100644 index 000000000..d77c412f1 --- /dev/null +++ b/synapse/rest/client/v2_alpha/forward_event.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Tulir Asokan +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import logging + +from synapse.api.errors import Codes, SynapseError, AuthError +from synapse.http.servlet import RestServlet, parse_integer +from synapse.logging.opentracing import set_tag + +from ._base import client_patterns + +logger = logging.getLogger(__name__) + + +class RoomEventForwardServlet(RestServlet): + """ + PUT /net.maunium.msc2730/rooms/{room_id}/event/{event_id}/forward/{target_room_id}/{txn_id} + """ + + PATTERNS = client_patterns( + ("/net.maunium.msc2730/rooms/(?P[^/]*)/event/(?P[^/]*)" + "/forward/(?P[^/]*)/(?P.*)"), + releases=(), # This is an unstable feature + ) + + _data_key = "net.maunium.msc2730.forwarded" + _err_not_forwardable = "NET.MAUNIUM.MSC2730_NOT_FORWARDABLE" + + def __init__(self, hs): + super().__init__() + self.event_creation_handler = hs.get_event_creation_handler() + self.event_handler = hs.get_event_handler() + self.store = hs.get_datastore() + self.auth = hs.get_auth() + + async def on_PUT(self, request, room_id, event_id, target_room_id, txn_id): + requester = await self.auth.get_user_by_req(request, allow_guest=True) + + try: + event = await self.event_handler.get_event( + requester.user, room_id, event_id + ) + except AuthError: + event = None + if not event: + raise SynapseError(404, "Event not found.", errcode=Codes.NOT_FOUND) + + if event.is_state(): + raise SynapseError(401, "State events cannot be forwarded.", + errcode=self._err_not_forwardable) + elif event.redacts: + raise SynapseError(401, "Redaction events cannot be forwarded.", + errcode=self._err_not_forwardable) + elif event.internal_metadata.is_redacted(): + raise SynapseError(401, "Redacted events cannot be forwarded.", + errcode=self._err_not_forwardable) + + event_id = event.event_id + event_dict = event.get_dict() + + content = event_dict.pop("content") + unsigned = event_dict.pop("unsigned", {}) + event_type = event_dict.pop("type") + has_forward_meta = self._data_key in content + try: + is_valid_forward = has_forward_meta and unsigned[self._data_key]["valid"] + except (KeyError, TypeError): + is_valid_forward = False + + if has_forward_meta and not is_valid_forward: + raise SynapseError(401, "Event contains invalid forward metadata.", + errcode=self._err_not_forwardable) + elif not has_forward_meta: + content[self._data_key] = event_dict + content[self._data_key]["unsigned"] = { + "room_version": await self.store.get_room_version(event.room_id), + # TODO add sender profile info here + } + + forwarded_event_dict = { + "type": event_type, + "content": content, + "room_id": target_room_id, + "sender": requester.user.to_string(), + "unsigned": { + self._data_key: { + "valid": True, + "event_id": event_id, + } + } + } + + if b"ts" in request.args and requester.app_service: + forwarded_event_dict["origin_server_ts"] = parse_integer(request, "ts", 0) + + forwarded_event, _ = await self.event_creation_handler.create_and_send_nonmember_event( + requester, forwarded_event_dict, txn_id=txn_id + ) + + set_tag("event_id", forwarded_event.event_id) + return 200, {"event_id": forwarded_event.event_id} + + +def register_servlets(hs, http_server): + RoomEventForwardServlet(hs).register(http_server) diff --git a/synapse/rest/client/versions.py b/synapse/rest/client/versions.py index 0d668df0b..d58664efb 100644 --- a/synapse/rest/client/versions.py +++ b/synapse/rest/client/versions.py @@ -60,6 +60,8 @@ class VersionsRestServlet(RestServlet): "org.matrix.e2e_cross_signing": True, # Implements additional endpoints as described in MSC2432 "org.matrix.msc2432": True, + # Implements endpoint and forwarded event validation as described in MSC2730 + "net.maunium.msc2730": True, }, }, )