summary refs log tree commit diff
path: root/packages/overlays/matrix-synapse/patches/0013-RequestRatelimiter-expose-can_do_action.patch
blob: 2ad8e55b1847b5c3bd9e826d4aa6c68efb9b4ef4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
From 4b62d4e914d8ff7e21bcfbbc6572f1f2a363e066 Mon Sep 17 00:00:00 2001
From: Rory& <root@rory.gay>
Date: Fri, 25 Jul 2025 08:26:15 +0200
Subject: [PATCH 13/14] RequestRatelimiter: expose can_do_action

---
 synapse/api/ratelimiting.py | 75 +++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/synapse/api/ratelimiting.py b/synapse/api/ratelimiting.py
index 509ef6b2c1..5f22089a6b 100644
--- a/synapse/api/ratelimiting.py
+++ b/synapse/api/ratelimiting.py
@@ -435,3 +435,78 @@ class RequestRatelimiter:
                 update=update,
                 n_actions=n_actions,
             )
+
+    async def can_do_action(
+        self,
+        requester: Optional[Requester],
+        burst_count: Optional[int] = None,
+        update: bool = True,
+        is_admin_redaction: bool = False,
+        n_actions: int = 1,
+    ) -> Tuple[bool, float]:
+        """Can the entity (e.g. user or IP address) perform the action?
+
+        Checks if the user has ratelimiting disabled in the database by looking
+        for null/zero values in the `ratelimit_override` table. (Non-zero
+        values aren't honoured, as they're specific to the event sending
+        ratelimiter, rather than all ratelimiters)
+
+        Args:
+            requester: The requester that is doing the action, if any. Used to check
+                if the user has ratelimits disabled in the database.
+            key: An arbitrary key used to classify an action. Defaults to the
+                requester's user ID.
+            rate_hz: The long term number of actions that can be performed in a second.
+                Overrides the value set during instantiation if set.
+            burst_count: How many actions that can be performed before being limited.
+                Overrides the value set during instantiation if set.
+            update: Whether to count this check as performing the action. If the action
+                cannot be performed, the user's action count is not incremented at all.
+            n_actions: The number of times the user wants to do this action. If the user
+                cannot do all of the actions, the user's action count is not incremented
+                at all.
+            _time_now_s: The current time. Optional, defaults to the current time according
+                to self.clock. Only used by tests.
+
+        Returns:
+            A tuple containing:
+                * A bool indicating if they can perform the action now
+                * The reactor timestamp for when the action can be performed next.
+                  -1 if rate_hz is less than or equal to zero
+        """
+        user_id = requester.user.to_string()
+
+        # The AS user itself is never rate limited.
+        app_service = self.store.get_app_service_by_user_id(user_id)
+        if app_service is not None:
+            return True, 0  # do not ratelimit app service senders
+
+        messages_per_second = self._rc_message.per_second
+        burst_count = self._rc_message.burst_count
+
+        # Check if there is a per user override in the DB.
+        override = await self.store.get_ratelimit_for_user(user_id)
+        if override:
+            # If overridden with a null Hz then ratelimiting has been entirely
+            # disabled for the user
+            if not override.messages_per_second:
+                return True, 0
+
+            messages_per_second = override.messages_per_second
+            burst_count = override.burst_count
+
+        if is_admin_redaction and self.admin_redaction_ratelimiter:
+            # If we have separate config for admin redactions, use a separate
+            # ratelimiter as to not have user_ids clash
+            return await self.admin_redaction_ratelimiter.can_do_action(
+                requester, update=update, n_actions=n_actions
+            )
+        else:
+            # Override rate and burst count per-user
+            return await self.request_ratelimiter.can_do_action(
+                requester,
+                rate_hz=messages_per_second,
+                burst_count=burst_count,
+                update=update,
+                n_actions=n_actions,
+            )
-- 
2.49.0