Skip to content

Commit 43e14e9

Browse files
committed
Enforce max delayed event config to be positive
If delayed events are to be disabled, it should be done by leaving the max_event_delay_duration config unspecified, not by setting the delayed event limit to 0. Also add test coverage, and tweak the error thrown for max_delay_event_ms to be consistent with the newly-added error.
1 parent 448bf17 commit 43e14e9

3 files changed

Lines changed: 55 additions & 6 deletions

File tree

synapse/config/server.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,9 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
914914
max_event_delay_duration
915915
)
916916
if self.max_event_delay_ms <= 0:
917-
raise ConfigError("max_event_delay_duration must be a positive value")
917+
raise ConfigError(
918+
"Expected a positive value", ("max_event_delay_duration",)
919+
)
918920
else:
919921
self.max_event_delay_ms = None
920922

@@ -923,6 +925,14 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
923925
self.max_delayed_events_per_user: int = config.get(
924926
"experimental_features", {}
925927
).get("msc4140_max_delayed_events_per_user", 100)
928+
if (
929+
not isinstance(self.max_delayed_events_per_user, int)
930+
or self.max_delayed_events_per_user <= 0
931+
):
932+
raise ConfigError(
933+
"Expected a positive value",
934+
("experimental", "msc4140_max_delayed_events_per_user"),
935+
)
926936

927937
def has_tls_listener(self) -> bool:
928938
return any(listener.is_tls() for listener in self.listeners)

synapse/storage/databases/main/delayed_events.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ async def add_delayed_event(
137137
LimitExceededError: if the user has reached the limit of
138138
how many delayed events they may have scheduled at once.
139139
"""
140+
assert limit > 0 # Should be enforced at config read time
140141
delay_id = _generate_delay_id()
141142
send_ts = Timestamp(creation_ts + delay)
142143

@@ -148,21 +149,18 @@ def add_delayed_event_txn(txn: LoggingTransaction) -> Timestamp:
148149
retcol="COUNT(*)",
149150
)
150151
if num_existing >= limit:
151-
next_send_ms: int | None = self.db_pool.simple_select_one_onecol_txn(
152+
next_send_ms: int = self.db_pool.simple_select_one_onecol_txn(
152153
txn,
153154
table="delayed_events",
154155
keyvalues={
155156
"is_processed": False,
156157
"user_localpart": user_localpart,
157158
},
158159
retcol="MIN(send_ts)",
159-
allow_none=True,
160160
)
161161
e = LimitExceededError(
162162
limiter_name="add_delayed_event",
163-
retry_after_ms=next_send_ms - creation_ts
164-
if next_send_ms is not None
165-
else None,
163+
retry_after_ms=next_send_ms - creation_ts,
166164
)
167165
e.msg = "The maximum number of delayed events has been reached."
168166
raise e

tests/config/test_server.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
#
1919
#
2020

21+
2122
import yaml
2223

2324
from synapse.config._base import ConfigError, RootConfig
2425
from synapse.config.homeserver import HomeServerConfig
2526
from synapse.config.server import ServerConfig, generate_ip_set, is_threepid_reserved
27+
from synapse.types import JsonDict
2628

2729
from tests import unittest
2830

@@ -189,6 +191,45 @@ def test_listeners_set_correctly_open_private_ports_true(self) -> None:
189191

190192
self.assertEqual(conf["listeners"], expected_listeners)
191193

194+
def test_max_delayed_events_enforces_positive(self) -> None:
195+
def generate_config(value: int) -> JsonDict:
196+
return {"max_event_delay_duration": value}
197+
198+
_read_config(generate_config(1))
199+
200+
with self.assertRaises(ConfigError):
201+
_read_config(generate_config(0))
202+
203+
with self.assertRaises(ConfigError):
204+
_read_config(generate_config(-1))
205+
206+
def test_max_delayed_events_per_user_enforces_positive(self) -> None:
207+
def generate_config(value: int) -> JsonDict:
208+
return {
209+
"experimental_features": {"msc4140_max_delayed_events_per_user": value}
210+
}
211+
212+
_read_config(generate_config(1))
213+
214+
with self.assertRaises(ConfigError):
215+
_read_config(generate_config(0))
216+
217+
with self.assertRaises(ConfigError):
218+
_read_config(generate_config(-1))
219+
220+
221+
def _read_config(config_values: JsonDict) -> None:
222+
ServerConfig(RootConfig()).read_config(
223+
yaml.safe_load(
224+
HomeServerConfig().generate_config(
225+
config_dir_path="CONFDIR",
226+
data_dir_path="/data_dir_path",
227+
server_name="che.org",
228+
)
229+
)
230+
| config_values
231+
)
232+
192233

193234
class GenerateIpSetTestCase(unittest.TestCase):
194235
def test_empty(self) -> None:

0 commit comments

Comments
 (0)