Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit db10f2c

Browse files
author
David Robertson
authored
No longer permit empty body when sending receipts (#12709)
1 parent 6ee61b9 commit db10f2c

File tree

3 files changed

+6
-38
lines changed

3 files changed

+6
-38
lines changed

changelog.d/12709.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Require a body in POST requests to `/rooms/{roomId}/receipt/{receiptType}/{eventId}`, as required by the [Matrix specification](https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidreceiptreceipttypeeventid). This breaks compatibility with Element Android 1.2.0 and earlier: users of those clients will be unable to send read receipts.

synapse/rest/client/receipts.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,17 @@
1313
# limitations under the License.
1414

1515
import logging
16-
import re
1716
from typing import TYPE_CHECKING, Tuple
1817

1918
from synapse.api.constants import ReceiptTypes
2019
from synapse.api.errors import SynapseError
21-
from synapse.http import get_request_user_agent
2220
from synapse.http.server import HttpServer
2321
from synapse.http.servlet import RestServlet, parse_json_object_from_request
2422
from synapse.http.site import SynapseRequest
2523
from synapse.types import JsonDict
2624

2725
from ._base import client_patterns
2826

29-
pattern = re.compile(r"(?:Element|SchildiChat)/1\.[012]\.")
30-
3127
if TYPE_CHECKING:
3228
from synapse.server import HomeServer
3329

@@ -69,14 +65,7 @@ async def on_POST(
6965
):
7066
raise SynapseError(400, "Receipt type must be 'm.read'")
7167

72-
# Do not allow older SchildiChat and Element Android clients (prior to Element/1.[012].x) to send an empty body.
73-
user_agent = get_request_user_agent(request)
74-
allow_empty_body = False
75-
if "Android" in user_agent:
76-
if pattern.match(user_agent) or "Riot" in user_agent:
77-
allow_empty_body = True
78-
# This call makes sure possible empty body is handled correctly
79-
parse_json_object_from_request(request, allow_empty_body)
68+
parse_json_object_from_request(request, allow_empty_body=False)
8069

8170
await self.presence_handler.bump_presence_active_time(requester.user)
8271

tests/rest/client/test_sync.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
import json
16+
from http import HTTPStatus
1617
from typing import List, Optional
1718

1819
from parameterized import parameterized
@@ -485,30 +486,7 @@ def test_private_receipt_cannot_override_public(self) -> None:
485486
# Test that we didn't override the public read receipt
486487
self.assertIsNone(self._get_read_receipt())
487488

488-
@parameterized.expand(
489-
[
490-
# Old Element version, expected to send an empty body
491-
(
492-
"agent1",
493-
"Element/1.2.2 (Linux; U; Android 9; MatrixAndroidSDK_X 0.0.1)",
494-
200,
495-
),
496-
# Old SchildiChat version, expected to send an empty body
497-
("agent2", "SchildiChat/1.2.1 (Android 10)", 200),
498-
# Expected 400: Denies empty body starting at version 1.3+
499-
("agent3", "Element/1.3.6 (Android 10)", 400),
500-
("agent4", "SchildiChat/1.3.6 (Android 11)", 400),
501-
# Contains "Riot": Receipts with empty bodies expected
502-
("agent5", "Element (Riot.im) (Android 9)", 200),
503-
# Expected 400: Does not contain "Android"
504-
("agent6", "Element/1.2.1", 400),
505-
# Expected 400: Different format, missing "/" after Element; existing build that should allow empty bodies, but minimal ongoing usage
506-
("agent7", "Element dbg/1.1.8-dev (Android)", 400),
507-
]
508-
)
509-
def test_read_receipt_with_empty_body(
510-
self, name: str, user_agent: str, expected_status_code: int
511-
) -> None:
489+
def test_read_receipt_with_empty_body_is_rejected(self) -> None:
512490
# Send a message as the first user
513491
res = self.helper.send(self.room_id, body="hello", tok=self.tok)
514492

@@ -517,9 +495,9 @@ def test_read_receipt_with_empty_body(
517495
"POST",
518496
f"/rooms/{self.room_id}/receipt/m.read/{res['event_id']}",
519497
access_token=self.tok2,
520-
custom_headers=[("User-Agent", user_agent)],
521498
)
522-
self.assertEqual(channel.code, expected_status_code)
499+
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST)
500+
self.assertEqual(channel.json_body["errcode"], "M_NOT_JSON", channel.json_body)
523501

524502
def _get_read_receipt(self) -> Optional[JsonDict]:
525503
"""Syncs and returns the read receipt."""

0 commit comments

Comments
 (0)