Don't allow tagnames longer than 255 bytes (#18660)

This commit is contained in:
Alex Durham 2025-07-18 15:23:28 +02:00 committed by GitHub
parent 5ea2cf2484
commit 6127aa0d50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 81 additions and 1 deletions

1
changelog.d/18660.bugfix Normal file
View File

@ -0,0 +1 @@
Don't allow creation of tags with names longer than 255 bytes, as per the spec.

View File

@ -20,9 +20,10 @@
#
import logging
from http import HTTPStatus
from typing import TYPE_CHECKING, Tuple
from synapse.api.errors import AuthError
from synapse.api.errors import AuthError, Codes, SynapseError
from synapse.http.server import HttpServer
from synapse.http.servlet import RestServlet, parse_json_object_from_request
from synapse.http.site import SynapseRequest
@ -35,6 +36,8 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
MAX_TAG_LENGTH = 255
class TagListServlet(RestServlet):
"""
@ -86,6 +89,16 @@ class TagServlet(RestServlet):
requester = await self.auth.get_user_by_req(request)
if user_id != requester.user.to_string():
raise AuthError(403, "Cannot add tags for other users.")
# check if the tag exceeds the length allowed by the matrix-specification
# as defined in: https://spec.matrix.org/v1.15/client-server-api/#events-14
if len(tag.encode("utf-8")) > MAX_TAG_LENGTH:
raise SynapseError(
HTTPStatus.BAD_REQUEST,
"tag parameter's length is over 255 bytes",
errcode=Codes.INVALID_PARAM,
)
# Check if the user has any membership in the room and raise error if not.
# Although it's not harmful for users to tag random rooms, it's just superfluous
# data we don't need to track or allow.

View File

@ -15,6 +15,7 @@
"""Tests REST events for /tags paths."""
from http import HTTPStatus
from urllib import parse as urlparse
import synapse.rest.admin
from synapse.rest.client import login, room, tags
@ -93,3 +94,68 @@ class RoomTaggingTestCase(unittest.HomeserverTestCase):
)
# Check that the request failed with the correct error
self.assertEqual(channel.code, HTTPStatus.FORBIDDEN, channel.result)
def test_put_tag_fails_if_tag_is_too_long(self) -> None:
"""
Test that a user cannot add a tag to a room that is longer than the 255 bytes
allowed by the matrix specification.
"""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
room_id = self.helper.create_room_as(user1_id, tok=user1_tok)
# create a string which is larger than 255 bytes
tag = "X" * 300
# Make the request
channel = self.make_request(
"PUT",
f"/user/{user1_id}/rooms/{room_id}/tags/{tag}",
content={"order": 0.5},
access_token=user1_tok,
)
# Check that the request failed
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST, channel.result)
def test_put_tag_fails_if_tag_is_too_long_with_graphemes(self) -> None:
"""
Test that a user cannot add a tag to a room that contains graphemes which are in total
longer than the 255 bytes allowed by the matrix specification.
"""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
room_id = self.helper.create_room_as(user1_id, tok=user1_tok)
# create a string which is larger than 255 bytes (275)
tag = "👩‍🚒" * 25
# Make the request
channel = self.make_request(
"PUT",
f"/user/{user1_id}/rooms/{room_id}/tags/"
+ urlparse.quote(tag.encode("utf-8")),
content={"order": 0.5},
access_token=user1_tok,
)
# Check that the request failed
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST, channel.result)
def test_put_tag_succeeds_with_graphemes(self) -> None:
"""
Test that a user can add a tag to a room that contains graphemes which are in total
less than the 255 bytes allowed by the matrix specification.
"""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
room_id = self.helper.create_room_as(user1_id, tok=user1_tok)
# create a string of acceptable length (220 bytes)
tag = "👩‍🚒" * 20
# Make the request
channel = self.make_request(
"PUT",
f"/user/{user1_id}/rooms/{room_id}/tags/"
+ urlparse.quote(tag.encode("utf-8")),
content={"order": 0.5},
access_token=user1_tok,
)
# Check that the request succeeded
self.assertEqual(channel.code, HTTPStatus.OK, channel.result)