diff --git a/synapse/handlers/federation_event.py b/synapse/handlers/federation_event.py
index b7c54e642f..479d936dc0 100644
--- a/synapse/handlers/federation_event.py
+++ b/synapse/handlers/federation_event.py
@@ -1092,20 +1092,19 @@ class FederationEventHandler:
logger.debug("Processing event: %s", event)
assert not event.internal_metadata.outlier
+ context = await self._state_handler.compute_event_context(
+ event,
+ state_ids_before_event=state_ids,
+ )
try:
- context = await self._state_handler.compute_event_context(
- event,
- state_ids_before_event=state_ids,
- )
context = await self._check_event_auth(
origin,
event,
context,
)
except AuthError as e:
- # FIXME richvdh 2021/10/07 I don't think this is reachable. Let's log it
- # for now
- logger.exception("Unexpected AuthError from _check_event_auth")
+ # This happens only if we couldn't find the auth events. We'll already have
+ # logged a warning, so now we just convert to a FederationError.
raise FederationError("ERROR", e.code, e.msg, affected=event.event_id)
if not backfilled and not context.rejected:
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 189f52fe5a..c6b40a5b7a 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -903,6 +903,9 @@ class EventCreationHandler:
await self.clock.sleep(random.randint(1, 10))
raise ShadowBanError()
+ if ratelimit:
+ await self.request_ratelimiter.ratelimit(requester, update=False)
+
# We limit the number of concurrent event sends in a room so that we
# don't fork the DAG too much. If we don't limit then we can end up in
# a situation where event persistence can't keep up, causing
diff --git a/synapse/handlers/room_list.py b/synapse/handlers/room_list.py
index 183d4ae3c4..29868eb743 100644
--- a/synapse/handlers/room_list.py
+++ b/synapse/handlers/room_list.py
@@ -25,6 +25,7 @@ from synapse.api.constants import (
GuestAccess,
HistoryVisibility,
JoinRules,
+ PublicRoomsFilterFields,
)
from synapse.api.errors import (
Codes,
@@ -181,6 +182,7 @@ class RoomListHandler:
== HistoryVisibility.WORLD_READABLE,
"guest_can_join": room["guest_access"] == "can_join",
"join_rule": room["join_rules"],
+ "org.matrix.msc3827.room_type": room["room_type"],
}
# Filter out Nones – rather omit the field altogether
@@ -239,7 +241,9 @@ class RoomListHandler:
response["chunk"] = results
response["total_room_count_estimate"] = await self.store.count_public_rooms(
- network_tuple, ignore_non_federatable=from_federation
+ network_tuple,
+ ignore_non_federatable=from_federation,
+ search_filter=search_filter,
)
return response
@@ -508,8 +512,21 @@ class RoomListNextBatch:
def _matches_room_entry(room_entry: JsonDict, search_filter: dict) -> bool:
- if search_filter and search_filter.get("generic_search_term", None):
- generic_search_term = search_filter["generic_search_term"].upper()
+ """Determines whether the given search filter matches a room entry returned over
+ federation.
+
+ Only used if the remote server does not support MSC2197 remote-filtered search, and
+ hence does not support MSC3827 filtering of `/publicRooms` by room type either.
+
+ In this case, we cannot apply the `room_type` filter since no `room_type` field is
+ returned.
+ """
+ if search_filter and search_filter.get(
+ PublicRoomsFilterFields.GENERIC_SEARCH_TERM, None
+ ):
+ generic_search_term = search_filter[
+ PublicRoomsFilterFields.GENERIC_SEARCH_TERM
+ ].upper()
if generic_search_term in room_entry.get("name", "").upper():
return True
elif generic_search_term in room_entry.get("topic", "").upper():
diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py
index bf6bae1232..a1d8875dd8 100644
--- a/synapse/handlers/room_member.py
+++ b/synapse/handlers/room_member.py
@@ -101,19 +101,33 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
burst_count=hs.config.ratelimiting.rc_joins_remote.burst_count,
)
+ # Ratelimiter for invites, keyed by room (across all issuers, all
+ # recipients).
self._invites_per_room_limiter = Ratelimiter(
store=self.store,
clock=self.clock,
rate_hz=hs.config.ratelimiting.rc_invites_per_room.per_second,
burst_count=hs.config.ratelimiting.rc_invites_per_room.burst_count,
)
- self._invites_per_user_limiter = Ratelimiter(
+
+ # Ratelimiter for invites, keyed by recipient (across all rooms, all
+ # issuers).
+ self._invites_per_recipient_limiter = Ratelimiter(
store=self.store,
clock=self.clock,
rate_hz=hs.config.ratelimiting.rc_invites_per_user.per_second,
burst_count=hs.config.ratelimiting.rc_invites_per_user.burst_count,
)
+ # Ratelimiter for invites, keyed by issuer (across all rooms, all
+ # recipients).
+ self._invites_per_issuer_limiter = Ratelimiter(
+ store=self.store,
+ clock=self.clock,
+ rate_hz=hs.config.ratelimiting.rc_invites_per_issuer.per_second,
+ burst_count=hs.config.ratelimiting.rc_invites_per_issuer.burst_count,
+ )
+
self._third_party_invite_limiter = Ratelimiter(
store=self.store,
clock=self.clock,
@@ -258,7 +272,9 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
if room_id:
await self._invites_per_room_limiter.ratelimit(requester, room_id)
- await self._invites_per_user_limiter.ratelimit(requester, invitee_user_id)
+ await self._invites_per_recipient_limiter.ratelimit(requester, invitee_user_id)
+ if requester is not None:
+ await self._invites_per_issuer_limiter.ratelimit(requester)
async def _local_membership_update(
self,
@@ -830,10 +846,17 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
content["membership"] = Membership.JOIN
- profile = self.profile_handler
- if not content_specified:
- content["displayname"] = await profile.get_displayname(target)
- content["avatar_url"] = await profile.get_avatar_url(target)
+ try:
+ profile = self.profile_handler
+ if not content_specified:
+ content["displayname"] = await profile.get_displayname(target)
+ content["avatar_url"] = await profile.get_avatar_url(target)
+ except Exception as e:
+ logger.info(
+ "Failed to get profile information while processing remote join for %r: %s",
+ target,
+ e,
+ )
if requester.is_guest:
content["kind"] = "guest"
@@ -910,11 +933,18 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
content["membership"] = Membership.KNOCK
- profile = self.profile_handler
- if "displayname" not in content:
- content["displayname"] = await profile.get_displayname(target)
- if "avatar_url" not in content:
- content["avatar_url"] = await profile.get_avatar_url(target)
+ try:
+ profile = self.profile_handler
+ if "displayname" not in content:
+ content["displayname"] = await profile.get_displayname(target)
+ if "avatar_url" not in content:
+ content["avatar_url"] = await profile.get_avatar_url(target)
+ except Exception as e:
+ logger.info(
+ "Failed to get profile information while processing remote knock for %r: %s",
+ target,
+ e,
+ )
return await self.remote_knock(
remote_room_hosts, room_id, target, content
diff --git a/synapse/handlers/stats.py b/synapse/handlers/stats.py
index f45e06eb0e..5c01482acf 100644
--- a/synapse/handlers/stats.py
+++ b/synapse/handlers/stats.py
@@ -271,6 +271,9 @@ class StatsHandler:
room_state["is_federatable"] = (
event_content.get(EventContentFields.FEDERATE, True) is True
)
+ room_type = event_content.get(EventContentFields.ROOM_TYPE)
+ if isinstance(room_type, str):
+ room_state["room_type"] = room_type
elif typ == EventTypes.JoinRules:
room_state["join_rules"] = event_content.get("join_rule")
elif typ == EventTypes.RoomHistoryVisibility:
|