diff --git a/changelog.d/19291.misc b/changelog.d/19291.misc new file mode 100644 index 0000000000..bac12b8506 --- /dev/null +++ b/changelog.d/19291.misc @@ -0,0 +1 @@ +Add a config to be able to rate limit search in the user directory. diff --git a/demo/start.sh b/demo/start.sh index e010302bf4..0b61ac9991 100755 --- a/demo/start.sh +++ b/demo/start.sh @@ -145,6 +145,12 @@ for port in 8080 8081 8082; do rc_delayed_event_mgmt: per_second: 1000 burst_count: 1000 + rc_room_creation: + per_second: 1000 + burst_count: 1000 + rc_user_directory: + per_second: 1000 + burst_count: 1000 RC ) echo "${ratelimiting}" >> "$port.config" diff --git a/docker/complement/conf/workers-shared-extra.yaml.j2 b/docker/complement/conf/workers-shared-extra.yaml.j2 index 94e74df9d1..101ff153a5 100644 --- a/docker/complement/conf/workers-shared-extra.yaml.j2 +++ b/docker/complement/conf/workers-shared-extra.yaml.j2 @@ -102,6 +102,10 @@ rc_room_creation: per_second: 9999 burst_count: 9999 +rc_user_directory: + per_second: 9999 + burst_count: 9999 + federation_rr_transactions_per_room_per_second: 9999 allow_device_name_lookup_over_federation: true diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 7509e4d715..badfe0a03f 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -2041,6 +2041,25 @@ rc_room_creation: burst_count: 5.0 ``` --- +### `rc_user_directory` + +*(object)* This option allows admins to ratelimit searches in the user directory. + +_Added in Synapse 1.145.0._ + +This setting has the following sub-options: + +* `per_second` (number): Maximum number of requests a client can send per second. + +* `burst_count` (number): Maximum number of requests a client can send before being throttled. + +Default configuration: +```yaml +rc_user_directory: + per_second: 0.016 + burst_count: 200.0 +``` +--- ### `federation_rr_transactions_per_room_per_second` *(integer)* Sets outgoing federation transaction frequency for sending read-receipts, per-room. diff --git a/schema/synapse-config.schema.yaml b/schema/synapse-config.schema.yaml index bf9346995d..ca8db9c9ee 100644 --- a/schema/synapse-config.schema.yaml +++ b/schema/synapse-config.schema.yaml @@ -2274,6 +2274,16 @@ properties: examples: - per_second: 1.0 burst_count: 5.0 + rc_user_directory: + $ref: "#/$defs/rc" + description: >- + This option allows admins to ratelimit searches in the user directory. + + + _Added in Synapse 1.145.0._ + default: + per_second: 0.016 + burst_count: 200.0 federation_rr_transactions_per_room_per_second: type: integer description: >- diff --git a/synapse/config/ratelimiting.py b/synapse/config/ratelimiting.py index 78d9d61d3c..13c9c4dba0 100644 --- a/synapse/config/ratelimiting.py +++ b/synapse/config/ratelimiting.py @@ -252,3 +252,9 @@ class RatelimitConfig(Config): "rc_reports", defaults={"per_second": 1, "burst_count": 5}, ) + + self.rc_user_directory = RatelimitSettings.parse( + config, + "rc_user_directory", + defaults={"per_second": 0.016, "burst_count": 200}, + ) diff --git a/synapse/rest/client/user_directory.py b/synapse/rest/client/user_directory.py index 0f561c2e61..fa1342d0bf 100644 --- a/synapse/rest/client/user_directory.py +++ b/synapse/rest/client/user_directory.py @@ -23,6 +23,7 @@ import logging from typing import TYPE_CHECKING from synapse.api.errors import SynapseError +from synapse.api.ratelimiting import Ratelimiter from synapse.http.server import HttpServer from synapse.http.servlet import RestServlet, parse_json_object_from_request from synapse.http.site import SynapseRequest @@ -46,6 +47,12 @@ class UserDirectorySearchRestServlet(RestServlet): self.auth = hs.get_auth() self.user_directory_handler = hs.get_user_directory_handler() + self._per_user_limiter = Ratelimiter( + store=hs.get_datastores().main, + clock=hs.get_clock(), + cfg=hs.config.ratelimiting.rc_user_directory, + ) + async def on_POST(self, request: SynapseRequest) -> tuple[int, JsonMapping]: """Searches for users in directory @@ -69,6 +76,8 @@ class UserDirectorySearchRestServlet(RestServlet): if not self.hs.config.userdirectory.user_directory_search_enabled: return 200, {"limited": False, "results": []} + await self._per_user_limiter.ratelimit(requester) + body = parse_json_object_from_request(request) limit = int(body.get("limit", 10))