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

Commit

Permalink
No longer permit empty body when sending receipts
Browse files Browse the repository at this point in the history
We made an exception for old Element Androids in #11157. We are now
reverting that exception and enforcing the spec.
  • Loading branch information
David Robertson committed May 11, 2022
1 parent a559c8b commit b145ba8
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 38 deletions.
13 changes: 1 addition & 12 deletions synapse/rest/client/receipts.py
Expand Up @@ -13,21 +13,17 @@
# limitations under the License.

import logging
import re
from typing import TYPE_CHECKING, Tuple

from synapse.api.constants import ReceiptTypes
from synapse.api.errors import SynapseError
from synapse.http import get_request_user_agent
from synapse.http.server import HttpServer
from synapse.http.servlet import RestServlet, parse_json_object_from_request
from synapse.http.site import SynapseRequest
from synapse.types import JsonDict

from ._base import client_patterns

pattern = re.compile(r"(?:Element|SchildiChat)/1\.[012]\.")

if TYPE_CHECKING:
from synapse.server import HomeServer

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

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

await self.presence_handler.bump_presence_active_time(requester.user)

Expand Down
30 changes: 4 additions & 26 deletions tests/rest/client/test_sync.py
Expand Up @@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from http import HTTPStatus
from typing import List, Optional

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

@parameterized.expand(
[
# Old Element version, expected to send an empty body
(
"agent1",
"Element/1.2.2 (Linux; U; Android 9; MatrixAndroidSDK_X 0.0.1)",
200,
),
# Old SchildiChat version, expected to send an empty body
("agent2", "SchildiChat/1.2.1 (Android 10)", 200),
# Expected 400: Denies empty body starting at version 1.3+
("agent3", "Element/1.3.6 (Android 10)", 400),
("agent4", "SchildiChat/1.3.6 (Android 11)", 400),
# Contains "Riot": Receipts with empty bodies expected
("agent5", "Element (Riot.im) (Android 9)", 200),
# Expected 400: Does not contain "Android"
("agent6", "Element/1.2.1", 400),
# Expected 400: Different format, missing "/" after Element; existing build that should allow empty bodies, but minimal ongoing usage
("agent7", "Element dbg/1.1.8-dev (Android)", 400),
]
)
def test_read_receipt_with_empty_body(
self, name: str, user_agent: str, expected_status_code: int
) -> None:
def test_read_receipt_with_empty_body_is_rejected(self) -> None:
# Send a message as the first user
res = self.helper.send(self.room_id, body="hello", tok=self.tok)

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

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

0 comments on commit b145ba8

Please sign in to comment.