-
Notifications
You must be signed in to change notification settings - Fork 491
Remove undocumented transaction ID variants of various room endpoints #19557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Remove support for undocumented variants of `/send` and `/redact` without a transaction ID, and `/createRoom`, `/forget` and the membership endpoints (join, invite, leave, ban, unban, kick) with a transaction ID. Contributed by @tulir @ Beeper. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -165,32 +165,15 @@ def __init__(self, hs: "HomeServer"): | |
|
|
||
| class RoomCreateRestServlet(TransactionRestServlet): | ||
| CATEGORY = "Client API requests" | ||
| PATTERNS = client_patterns("/createRoom$", v1=True) | ||
|
|
||
| def __init__(self, hs: "HomeServer"): | ||
| super().__init__(hs) | ||
| self._room_creation_handler = hs.get_room_creation_handler() | ||
| self.auth = hs.get_auth() | ||
|
|
||
| def register(self, http_server: HttpServer) -> None: | ||
| PATTERNS = "/createRoom" | ||
| register_txn_path(self, PATTERNS, http_server) | ||
|
|
||
| async def on_PUT( | ||
| self, request: SynapseRequest, txn_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request) | ||
| set_tag("txn_id", txn_id) | ||
| return await self.txns.fetch_or_execute_request( | ||
| request, requester, self._do, request, requester | ||
| ) | ||
|
|
||
| async def on_POST(self, request: SynapseRequest) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request) | ||
| return await self._do(request, requester) | ||
|
|
||
| async def _do( | ||
| self, request: SynapseRequest, requester: Requester | ||
| ) -> tuple[int, JsonDict]: | ||
| room_id, _, _ = await self._room_creation_handler.create_room( | ||
| requester, self.get_room_config(request) | ||
| ) | ||
|
|
@@ -409,6 +392,10 @@ async def on_PUT( | |
| # TODO: Needs unit testing for generic events + feedback | ||
| class RoomSendEventRestServlet(TransactionRestServlet): | ||
| CATEGORY = "Event sending requests" | ||
| PATTERNS = client_patterns( | ||
| "/rooms/(?P<room_id>[^/]*)/send/(?P<event_type>[^/]*)/(?P<txn_id>[^/]*)$", | ||
| v1=True, | ||
| ) | ||
|
|
||
| def __init__(self, hs: "HomeServer"): | ||
| super().__init__(hs) | ||
|
|
@@ -418,11 +405,6 @@ def __init__(self, hs: "HomeServer"): | |
| self._max_event_delay_ms = hs.config.server.max_event_delay_ms | ||
| self._msc4354_enabled = hs.config.experimental.msc4354_enabled | ||
|
|
||
| def register(self, http_server: HttpServer) -> None: | ||
| # /rooms/$roomid/send/$event_type[/$txn_id] | ||
| PATTERNS = "/rooms/(?P<room_id>[^/]*)/send/(?P<event_type>[^/]*)" | ||
| register_txn_path(self, PATTERNS, http_server) | ||
|
|
||
| async def _do( | ||
| self, | ||
| request: SynapseRequest, | ||
|
|
@@ -487,15 +469,6 @@ async def _do( | |
| set_tag("event_id", event_id) | ||
| return 200, {"event_id": event_id} | ||
|
|
||
| async def on_POST( | ||
| self, | ||
| request: SynapseRequest, | ||
| room_id: str, | ||
| event_type: str, | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| return await self._do(request, requester, room_id, event_type, None) | ||
|
|
||
| async def on_PUT( | ||
| self, request: SynapseRequest, room_id: str, event_type: str, txn_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
|
|
@@ -560,24 +533,19 @@ def _parse_request_delay( | |
| # TODO: Needs unit testing for room ID + alias joins | ||
| class JoinRoomAliasServlet(ResolveRoomIdMixin, TransactionRestServlet): | ||
| CATEGORY = "Event sending requests" | ||
| PATTERNS = client_patterns("/join/(?P<room_identifier>[^/]*)", v1=True) | ||
|
|
||
| def __init__(self, hs: "HomeServer"): | ||
| super().__init__(hs) | ||
| super(ResolveRoomIdMixin, self).__init__(hs) # ensure the Mixin is set up | ||
| self.auth = hs.get_auth() | ||
|
|
||
| def register(self, http_server: HttpServer) -> None: | ||
| # /join/$room_identifier[/$txn_id] | ||
| PATTERNS = "/join/(?P<room_identifier>[^/]*)" | ||
| register_txn_path(self, PATTERNS, http_server) | ||
|
|
||
| async def _do( | ||
| async def on_POST( | ||
| self, | ||
| request: SynapseRequest, | ||
| requester: Requester, | ||
| room_identifier: str, | ||
| txn_id: str | None, | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| content = parse_json_object_from_request(request, allow_empty_body=True) | ||
|
|
||
| # twisted.web.server.Request.args is incorrectly defined as Any | None | ||
|
|
@@ -598,32 +566,14 @@ async def _do( | |
| target=requester.user, | ||
| room_id=room_id, | ||
| action="join", | ||
| txn_id=txn_id, | ||
| txn_id=None, | ||
| remote_room_hosts=remote_room_hosts, | ||
| content=content, | ||
| third_party_signed=content.get("third_party_signed", None), | ||
| ) | ||
|
|
||
| return 200, {"room_id": room_id} | ||
|
|
||
| async def on_POST( | ||
| self, | ||
| request: SynapseRequest, | ||
| room_identifier: str, | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| return await self._do(request, requester, room_identifier, None) | ||
|
|
||
| async def on_PUT( | ||
| self, request: SynapseRequest, room_identifier: str, txn_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| set_tag("txn_id", txn_id) | ||
|
|
||
| return await self.txns.fetch_or_execute_request( | ||
| request, requester, self._do, request, requester, room_identifier, txn_id | ||
| ) | ||
|
|
||
|
|
||
| # TODO: Needs unit testing | ||
| class PublicRoomListRestServlet(RestServlet): | ||
|
|
@@ -1184,63 +1134,45 @@ async def on_GET( | |
|
|
||
|
|
||
| class RoomForgetRestServlet(TransactionRestServlet): | ||
| PATTERNS = client_patterns("/rooms/(?P<room_id>[^/]*)/forget$", v1=True) | ||
|
|
||
| def __init__(self, hs: "HomeServer"): | ||
| super().__init__(hs) | ||
| self.room_member_handler = hs.get_room_member_handler() | ||
| self.auth = hs.get_auth() | ||
|
|
||
| def register(self, http_server: HttpServer) -> None: | ||
| PATTERNS = "/rooms/(?P<room_id>[^/]*)/forget" | ||
| register_txn_path(self, PATTERNS, http_server) | ||
|
|
||
| async def _do(self, requester: Requester, room_id: str) -> tuple[int, JsonDict]: | ||
| await self.room_member_handler.forget(user=requester.user, room_id=room_id) | ||
|
|
||
| return 200, {} | ||
|
|
||
| async def on_POST( | ||
| self, request: SynapseRequest, room_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=False) | ||
| return await self._do(requester, room_id) | ||
|
|
||
| async def on_PUT( | ||
| self, request: SynapseRequest, room_id: str, txn_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=False) | ||
| set_tag("txn_id", txn_id) | ||
| await self.room_member_handler.forget(user=requester.user, room_id=room_id) | ||
|
|
||
| return await self.txns.fetch_or_execute_request( | ||
| request, requester, self._do, requester, room_id | ||
| ) | ||
| return 200, {} | ||
|
|
||
|
|
||
| # TODO: Needs unit testing | ||
| class RoomMembershipRestServlet(TransactionRestServlet): | ||
| CATEGORY = "Event sending requests" | ||
| PATTERNS = client_patterns( | ||
| "/rooms/(?P<room_id>[^/]*)/" | ||
| "(?P<membership_action>join|invite|leave|ban|unban|kick)", | ||
| v1=True, | ||
| ) | ||
|
|
||
| def __init__(self, hs: "HomeServer"): | ||
| super().__init__(hs) | ||
| self.room_member_handler = hs.get_room_member_handler() | ||
| self.auth = hs.get_auth() | ||
| self.config = hs.config | ||
|
|
||
| def register(self, http_server: HttpServer) -> None: | ||
| # /rooms/$roomid/[join|invite|leave|ban|unban|kick] | ||
| PATTERNS = ( | ||
| "/rooms/(?P<room_id>[^/]*)/" | ||
| "(?P<membership_action>join|invite|leave|ban|unban|kick)" | ||
| ) | ||
| register_txn_path(self, PATTERNS, http_server) | ||
|
|
||
| async def _do( | ||
| async def on_POST( | ||
| self, | ||
| request: SynapseRequest, | ||
| requester: Requester, | ||
| room_id: str, | ||
| membership_action: str, | ||
| txn_id: str | None, | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| if requester.is_guest and membership_action not in { | ||
| Membership.JOIN, | ||
| Membership.LEAVE, | ||
|
|
@@ -1267,7 +1199,7 @@ async def _do( | |
| request_body["address"], | ||
| request_body["id_server"], | ||
| requester, | ||
| txn_id, | ||
| None, | ||
| request_body["id_access_token"], | ||
| ) | ||
| except ShadowBanError: | ||
|
|
@@ -1297,7 +1229,7 @@ async def _do( | |
| target=target, | ||
| room_id=room_id, | ||
| action=membership_action, | ||
| txn_id=txn_id, | ||
| txn_id=None, | ||
| third_party_signed=request_body.get("third_party_signed", None), | ||
| content=event_content, | ||
| ) | ||
|
|
@@ -1312,35 +1244,13 @@ async def _do( | |
|
|
||
| return 200, return_value | ||
|
|
||
| async def on_POST( | ||
| self, | ||
| request: SynapseRequest, | ||
| room_id: str, | ||
| membership_action: str, | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| return await self._do(request, requester, room_id, membership_action, None) | ||
|
|
||
| async def on_PUT( | ||
| self, request: SynapseRequest, room_id: str, membership_action: str, txn_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request, allow_guest=True) | ||
| set_tag("txn_id", txn_id) | ||
|
|
||
| return await self.txns.fetch_or_execute_request( | ||
| request, | ||
| requester, | ||
| self._do, | ||
| request, | ||
| requester, | ||
| room_id, | ||
| membership_action, | ||
| txn_id, | ||
| ) | ||
|
|
||
|
|
||
| class RoomRedactEventRestServlet(TransactionRestServlet): | ||
| CATEGORY = "Event sending requests" | ||
| PATTERNS = client_patterns( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry to say we need to keep the non-txnId form on Happy to throw away the other versions though. We should comment that this is out of spec for ECiOS and link to the ticket element-hq/element-ios#8011 In a follow-up PR I would not be against adding a user-agent check to ensure it's only ECiOS that can use this, to stop anyone else depending on it. (Needs further consideration though, I don't know if this would also backfire on ECiOS forks. Should probably give some grace time for a fix anyway.)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should also note in the comments that this can be removed once Element Classic iOS is shutdown in favor of Element X in the near-ish future |
||
| "/rooms/(?P<room_id>[^/]*)/redact/(?P<event_id>[^/]*)/(?P<txn_id>[^/]*)$", | ||
| v1=True, | ||
| ) | ||
|
|
||
| def __init__(self, hs: "HomeServer"): | ||
| super().__init__(hs) | ||
|
|
@@ -1352,10 +1262,6 @@ def __init__(self, hs: "HomeServer"): | |
| self._relation_handler = hs.get_relations_handler() | ||
| self._msc3912_enabled = hs.config.experimental.msc3912_enabled | ||
|
|
||
| def register(self, http_server: HttpServer) -> None: | ||
| PATTERNS = "/rooms/(?P<room_id>[^/]*)/redact/(?P<event_id>[^/]*)" | ||
| register_txn_path(self, PATTERNS, http_server) | ||
|
|
||
| async def _do( | ||
| self, | ||
| request: SynapseRequest, | ||
|
|
@@ -1444,15 +1350,6 @@ async def _do( | |
| set_tag("event_id", event_id) | ||
| return 200, {"event_id": event_id} | ||
|
|
||
| async def on_POST( | ||
| self, | ||
| request: SynapseRequest, | ||
| room_id: str, | ||
| event_id: str, | ||
| ) -> tuple[int, JsonDict]: | ||
| requester = await self.auth.get_user_by_req(request) | ||
| return await self._do(request, requester, room_id, event_id, None) | ||
|
|
||
| async def on_PUT( | ||
| self, request: SynapseRequest, room_id: str, event_id: str, txn_id: str | ||
| ) -> tuple[int, JsonDict]: | ||
|
|
@@ -1586,40 +1483,6 @@ async def on_GET(self, request: SynapseRequest) -> tuple[int, JsonDict]: | |
| return 200, {"joined_rooms": list(room_ids)} | ||
|
|
||
|
|
||
| def register_txn_path( | ||
| servlet: RestServlet, | ||
| regex_string: str, | ||
| http_server: HttpServer, | ||
| ) -> None: | ||
| """Registers a transaction-based path. | ||
|
|
||
| This registers two paths: | ||
| PUT regex_string/$txnid | ||
| POST regex_string | ||
|
|
||
| Args: | ||
| regex_string: The regex string to register. Must NOT have a | ||
| trailing $ as this string will be appended to. | ||
| http_server: The http_server to register paths with. | ||
| """ | ||
| on_POST = getattr(servlet, "on_POST", None) | ||
| on_PUT = getattr(servlet, "on_PUT", None) | ||
| if on_POST is None or on_PUT is None: | ||
| raise RuntimeError("on_POST and on_PUT must exist when using register_txn_path") | ||
| http_server.register_paths( | ||
| "POST", | ||
| client_patterns(regex_string + "$", v1=True), | ||
| on_POST, | ||
| servlet.__class__.__name__, | ||
| ) | ||
| http_server.register_paths( | ||
| "PUT", | ||
| client_patterns(regex_string + "/(?P<txn_id>[^/]*)$", v1=True), | ||
| on_PUT, | ||
| servlet.__class__.__name__, | ||
| ) | ||
|
|
||
|
|
||
| class TimestampLookupRestServlet(RestServlet): | ||
| """ | ||
| API endpoint to fetch the `event_id` of the closest event to the given | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sad to say, but after discussing with @erikjohnston, we need to preserve
/rooms/.../send/...without the txnId onr0andapi/v1as well.They've been recently used on m.org and it's going to be hard to just turn these off.
Should comment that although
api/v1is genuine (legacy/historical),r0was an accidental mistake that is widely used in practice.I'd be somewhat keen on somehow cracking down on it (e.g. restrict based on user registration date?) but that'd definitely be follow-up PR territory.