Skip to content

Commit 2f5a1df

Browse files
committed
Add rate limit conf to client profile endpoint
1 parent 8b0083c commit 2f5a1df

File tree

5 files changed

+59
-14
lines changed

5 files changed

+59
-14
lines changed

changelog.d/19292.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a config to be able to rate limit profile lookups by clients.

docs/usage/configuration/config_documentation.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,25 @@ rc_room_creation:
20412041
burst_count: 5.0
20422042
```
20432043
---
2044+
### `rc_profile`
2045+
2046+
*(object)* This option allows admins to ratelimit profile lookups by clients.
2047+
2048+
_Added in Synapse 1.145.0._
2049+
2050+
This setting has the following sub-options:
2051+
2052+
* `per_second` (number): Maximum number of requests a client can send per second.
2053+
2054+
* `burst_count` (number): Maximum number of requests a client can send before being throttled.
2055+
2056+
Default configuration:
2057+
```yaml
2058+
rc_profile:
2059+
per_second: 0.016
2060+
burst_count: 10.0
2061+
```
2062+
---
20442063
### `federation_rr_transactions_per_room_per_second`
20452064

20462065
*(integer)* Sets outgoing federation transaction frequency for sending read-receipts, per-room.

schema/synapse-config.schema.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,6 +2274,16 @@ properties:
22742274
examples:
22752275
- per_second: 1.0
22762276
burst_count: 5.0
2277+
rc_profile:
2278+
$ref: "#/$defs/rc"
2279+
description: >-
2280+
This option allows admins to ratelimit profile lookups by clients.
2281+
2282+
2283+
_Added in Synapse 1.145.0._
2284+
default:
2285+
per_second: 1
2286+
burst_count: 500.0
22772287
federation_rr_transactions_per_room_per_second:
22782288
type: integer
22792289
description: >-

synapse/config/ratelimiting.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,9 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
252252
"rc_reports",
253253
defaults={"per_second": 1, "burst_count": 5},
254254
)
255+
256+
self.rc_profile = RatelimitSettings.parse(
257+
config,
258+
"rc_profile",
259+
defaults={"per_second": 1, "burst_count": 500},
260+
)

synapse/rest/client/profile.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
from synapse.api.constants import ProfileFields
2929
from synapse.api.errors import Codes, SynapseError
30+
from synapse.api.ratelimiting import Ratelimiter
3031
from synapse.handlers.profile import MAX_CUSTOM_FIELD_LEN
3132
from synapse.http.server import HttpServer
3233
from synapse.http.servlet import (
@@ -67,22 +68,26 @@ def __init__(self, hs: "HomeServer"):
6768
self.profile_handler = hs.get_profile_handler()
6869
self.auth = hs.get_auth()
6970

71+
self._per_user_limiter = Ratelimiter(
72+
store=hs.get_datastores().main,
73+
clock=hs.get_clock(),
74+
cfg=hs.config.ratelimiting.rc_profile,
75+
)
76+
7077
async def on_GET(
7178
self, request: SynapseRequest, user_id: str
7279
) -> tuple[int, JsonDict]:
73-
requester_user = None
74-
75-
if self.hs.config.server.require_auth_for_profile_requests:
76-
requester = await self.auth.get_user_by_req(request)
77-
requester_user = requester.user
78-
7980
if not UserID.is_valid(user_id):
8081
raise SynapseError(
8182
HTTPStatus.BAD_REQUEST, "Invalid user id", Codes.INVALID_PARAM
8283
)
8384

8485
user = UserID.from_string(user_id)
85-
await self.profile_handler.check_profile_query_allowed(user, requester_user)
86+
87+
requester = await self.auth.get_user_by_req(request)
88+
await self._per_user_limiter.ratelimit(requester)
89+
if self.hs.config.server.require_auth_for_profile_requests:
90+
await self.profile_handler.check_profile_query_allowed(user, requester.user)
8691

8792
ret = await self.profile_handler.get_profile(user_id)
8893

@@ -116,15 +121,15 @@ def __init__(self, hs: "HomeServer"):
116121
)
117122
)
118123

124+
self._per_user_limiter = Ratelimiter(
125+
store=hs.get_datastores().main,
126+
clock=hs.get_clock(),
127+
cfg=hs.config.ratelimiting.rc_profile,
128+
)
129+
119130
async def on_GET(
120131
self, request: SynapseRequest, user_id: str, field_name: str
121132
) -> tuple[int, JsonDict]:
122-
requester_user = None
123-
124-
if self.hs.config.server.require_auth_for_profile_requests:
125-
requester = await self.auth.get_user_by_req(request)
126-
requester_user = requester.user
127-
128133
if not UserID.is_valid(user_id):
129134
raise SynapseError(
130135
HTTPStatus.BAD_REQUEST, "Invalid user id", Codes.INVALID_PARAM
@@ -143,7 +148,11 @@ async def on_GET(
143148
)
144149

145150
user = UserID.from_string(user_id)
146-
await self.profile_handler.check_profile_query_allowed(user, requester_user)
151+
152+
requester = await self.auth.get_user_by_req(request)
153+
await self._per_user_limiter.ratelimit(requester)
154+
if self.hs.config.server.require_auth_for_profile_requests:
155+
await self.profile_handler.check_profile_query_allowed(user, requester.user)
147156

148157
if field_name == ProfileFields.DISPLAYNAME:
149158
field_value: JsonValue = await self.profile_handler.get_displayname(user)

0 commit comments

Comments
 (0)