Fix `m.room_key_request` to-device messages (#9961)

fixes #9960
This commit is contained in:
Richard van der Hoff 2021-05-11 11:02:56 +01:00 committed by GitHub
parent 2b2985b5cf
commit 7967b36efe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 26 deletions

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

@ -0,0 +1 @@
Fix a bug introduced in Synapse 1.29.0 which caused `m.room_key_request` to-device messages sent from one user to another to be dropped.

View File

@ -116,9 +116,12 @@ class EventTypes:
MSC1772_SPACE_PARENT = "org.matrix.msc1772.space.parent" MSC1772_SPACE_PARENT = "org.matrix.msc1772.space.parent"
class ToDeviceEventTypes:
RoomKeyRequest = "m.room_key_request"
class EduTypes: class EduTypes:
Presence = "m.presence" Presence = "m.presence"
RoomKeyRequest = "m.room_key_request"
class RejectedReason: class RejectedReason:

View File

@ -44,7 +44,6 @@ from synapse.api.errors import (
SynapseError, SynapseError,
UnsupportedRoomVersionError, UnsupportedRoomVersionError,
) )
from synapse.api.ratelimiting import Ratelimiter
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.events import EventBase from synapse.events import EventBase
from synapse.federation.federation_base import FederationBase, event_from_pdu_json from synapse.federation.federation_base import FederationBase, event_from_pdu_json
@ -865,14 +864,6 @@ class FederationHandlerRegistry:
# EDU received. # EDU received.
self._edu_type_to_instance = {} # type: Dict[str, List[str]] self._edu_type_to_instance = {} # type: Dict[str, List[str]]
# A rate limiter for incoming room key requests per origin.
self._room_key_request_rate_limiter = Ratelimiter(
store=hs.get_datastore(),
clock=self.clock,
rate_hz=self.config.rc_key_requests.per_second,
burst_count=self.config.rc_key_requests.burst_count,
)
def register_edu_handler( def register_edu_handler(
self, edu_type: str, handler: Callable[[str, JsonDict], Awaitable[None]] self, edu_type: str, handler: Callable[[str, JsonDict], Awaitable[None]]
) -> None: ) -> None:
@ -926,16 +917,6 @@ class FederationHandlerRegistry:
if not self.config.use_presence and edu_type == EduTypes.Presence: if not self.config.use_presence and edu_type == EduTypes.Presence:
return return
# If the incoming room key requests from a particular origin are over
# the limit, drop them.
if (
edu_type == EduTypes.RoomKeyRequest
and not await self._room_key_request_rate_limiter.can_do_action(
None, origin
)
):
return
# Check if we have a handler on this instance # Check if we have a handler on this instance
handler = self.edu_handlers.get(edu_type) handler = self.edu_handlers.get(edu_type)
if handler: if handler:

View File

@ -15,7 +15,7 @@
import logging import logging
from typing import TYPE_CHECKING, Any, Dict from typing import TYPE_CHECKING, Any, Dict
from synapse.api.constants import EduTypes from synapse.api.constants import ToDeviceEventTypes
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
from synapse.api.ratelimiting import Ratelimiter from synapse.api.ratelimiting import Ratelimiter
from synapse.logging.context import run_in_background from synapse.logging.context import run_in_background
@ -79,6 +79,8 @@ class DeviceMessageHandler:
ReplicationUserDevicesResyncRestServlet.make_client(hs) ReplicationUserDevicesResyncRestServlet.make_client(hs)
) )
# a rate limiter for room key requests. The keys are
# (sending_user_id, sending_device_id).
self._ratelimiter = Ratelimiter( self._ratelimiter = Ratelimiter(
store=self.store, store=self.store,
clock=hs.get_clock(), clock=hs.get_clock(),
@ -100,12 +102,25 @@ class DeviceMessageHandler:
for user_id, by_device in content["messages"].items(): for user_id, by_device in content["messages"].items():
# we use UserID.from_string to catch invalid user ids # we use UserID.from_string to catch invalid user ids
if not self.is_mine(UserID.from_string(user_id)): if not self.is_mine(UserID.from_string(user_id)):
logger.warning("Request for keys for non-local user %s", user_id) logger.warning("To-device message to non-local user %s", user_id)
raise SynapseError(400, "Not a user here") raise SynapseError(400, "Not a user here")
if not by_device: if not by_device:
continue continue
# Ratelimit key requests by the sending user.
if message_type == ToDeviceEventTypes.RoomKeyRequest:
allowed, _ = await self._ratelimiter.can_do_action(
None, (sender_user_id, None)
)
if not allowed:
logger.info(
"Dropping room_key_request from %s to %s due to rate limit",
sender_user_id,
user_id,
)
continue
messages_by_device = { messages_by_device = {
device_id: { device_id: {
"content": message_content, "content": message_content,
@ -192,13 +207,19 @@ class DeviceMessageHandler:
for user_id, by_device in messages.items(): for user_id, by_device in messages.items():
# Ratelimit local cross-user key requests by the sending device. # Ratelimit local cross-user key requests by the sending device.
if ( if (
message_type == EduTypes.RoomKeyRequest message_type == ToDeviceEventTypes.RoomKeyRequest
and user_id != sender_user_id and user_id != sender_user_id
and await self._ratelimiter.can_do_action( ):
allowed, _ = await self._ratelimiter.can_do_action(
requester, (sender_user_id, requester.device_id) requester, (sender_user_id, requester.device_id)
) )
): if not allowed:
continue logger.info(
"Dropping room_key_request from %s to %s due to rate limit",
sender_user_id,
user_id,
)
continue
# we use UserID.from_string to catch invalid user ids # we use UserID.from_string to catch invalid user ids
if self.is_mine(UserID.from_string(user_id)): if self.is_mine(UserID.from_string(user_id)):