Skip to content

Commit 9e23cde

Browse files
MSC4140: Remove auth from delayed event management endpoints (#19152)
As per recent proposals in MSC4140, remove authentication for restarting/cancelling/sending a delayed event, and give each of those actions its own endpoint. (The original consolidated endpoint is still supported for backwards compatibility.) ### Pull Request Checklist <!-- Please read https://element-hq.github.io/synapse/latest/development/contributing_guide.html before submitting your pull request --> * [x] Pull request is based on the develop branch * [x] Pull request includes a [changelog file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog). The entry should: - Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from `EventStore` to `EventWorkerStore`.". - Use markdown where necessary, mostly for `code blocks`. - End with either a period (.) or an exclamation mark (!). - Start with a capital letter. - Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry. * [x] [Code style](https://element-hq.github.io/synapse/latest/code_style.html) is correct (run the [linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters)) --------- Co-authored-by: Half-Shot <will@half-shot.uk>
1 parent 4494cc0 commit 9e23cde

File tree

8 files changed

+198
-212
lines changed

8 files changed

+198
-212
lines changed

changelog.d/19152.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove authentication from `POST /_matrix/client/v1/delayed_events`, and allow calling this endpoint with the update action to take (`send`/`cancel`/`restart`) in the request path instead of the body.

synapse/_scripts/synapse_port_db.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from synapse.storage.databases.main import FilteringWorkerStore
5959
from synapse.storage.databases.main.account_data import AccountDataWorkerStore
6060
from synapse.storage.databases.main.client_ips import ClientIpBackgroundUpdateStore
61+
from synapse.storage.databases.main.delayed_events import DelayedEventsStore
6162
from synapse.storage.databases.main.deviceinbox import DeviceInboxBackgroundUpdateStore
6263
from synapse.storage.databases.main.devices import DeviceBackgroundUpdateStore
6364
from synapse.storage.databases.main.e2e_room_keys import EndToEndRoomKeyBackgroundStore
@@ -273,6 +274,7 @@ class Store(
273274
RelationsWorkerStore,
274275
EventFederationWorkerStore,
275276
SlidingSyncStore,
277+
DelayedEventsStore,
276278
):
277279
def execute(self, f: Callable[..., R], *args: Any, **kwargs: Any) -> Awaitable[R]:
278280
return self.db_pool.runInteraction(f.__name__, f, *args, **kwargs)

synapse/handlers/delayed_events.py

Lines changed: 14 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from synapse.api.errors import ShadowBanError, SynapseError
2222
from synapse.api.ratelimiting import Ratelimiter
2323
from synapse.config.workers import MAIN_PROCESS_INSTANCE_NAME
24+
from synapse.http.site import SynapseRequest
2425
from synapse.logging.context import make_deferred_yieldable
2526
from synapse.logging.opentracing import set_tag
2627
from synapse.metrics import SERVER_NAME_LABEL, event_processing_positions
@@ -29,11 +30,9 @@
2930
)
3031
from synapse.storage.databases.main.delayed_events import (
3132
DelayedEventDetails,
32-
DelayID,
3333
EventType,
3434
StateKey,
3535
Timestamp,
36-
UserLocalpart,
3736
)
3837
from synapse.storage.databases.main.state_deltas import StateDelta
3938
from synapse.types import (
@@ -399,96 +398,63 @@ def on_added(self, next_send_ts: int) -> None:
399398
if self._next_send_ts_changed(next_send_ts):
400399
self._schedule_next_at(next_send_ts)
401400

402-
async def cancel(self, requester: Requester, delay_id: str) -> None:
401+
async def cancel(self, request: SynapseRequest, delay_id: str) -> None:
403402
"""
404403
Cancels the scheduled delivery of the matching delayed event.
405404
406-
Args:
407-
requester: The owner of the delayed event to act on.
408-
delay_id: The ID of the delayed event to act on.
409-
410405
Raises:
411406
NotFoundError: if no matching delayed event could be found.
412407
"""
413408
assert self._is_master
414409
await self._delayed_event_mgmt_ratelimiter.ratelimit(
415-
requester,
416-
(requester.user.to_string(), requester.device_id),
410+
None, request.getClientAddress().host
417411
)
418412
await make_deferred_yieldable(self._initialized_from_db)
419413

420-
next_send_ts = await self._store.cancel_delayed_event(
421-
delay_id=delay_id,
422-
user_localpart=requester.user.localpart,
423-
)
414+
next_send_ts = await self._store.cancel_delayed_event(delay_id)
424415

425416
if self._next_send_ts_changed(next_send_ts):
426417
self._schedule_next_at_or_none(next_send_ts)
427418

428-
async def restart(self, requester: Requester, delay_id: str) -> None:
419+
async def restart(self, request: SynapseRequest, delay_id: str) -> None:
429420
"""
430421
Restarts the scheduled delivery of the matching delayed event.
431422
432-
Args:
433-
requester: The owner of the delayed event to act on.
434-
delay_id: The ID of the delayed event to act on.
435-
436423
Raises:
437424
NotFoundError: if no matching delayed event could be found.
438425
"""
439426
assert self._is_master
440427
await self._delayed_event_mgmt_ratelimiter.ratelimit(
441-
requester,
442-
(requester.user.to_string(), requester.device_id),
428+
None, request.getClientAddress().host
443429
)
444430
await make_deferred_yieldable(self._initialized_from_db)
445431

446432
next_send_ts = await self._store.restart_delayed_event(
447-
delay_id=delay_id,
448-
user_localpart=requester.user.localpart,
449-
current_ts=self._get_current_ts(),
433+
delay_id, self._get_current_ts()
450434
)
451435

452436
if self._next_send_ts_changed(next_send_ts):
453437
self._schedule_next_at(next_send_ts)
454438

455-
async def send(self, requester: Requester, delay_id: str) -> None:
439+
async def send(self, request: SynapseRequest, delay_id: str) -> None:
456440
"""
457441
Immediately sends the matching delayed event, instead of waiting for its scheduled delivery.
458442
459-
Args:
460-
requester: The owner of the delayed event to act on.
461-
delay_id: The ID of the delayed event to act on.
462-
463443
Raises:
464444
NotFoundError: if no matching delayed event could be found.
465445
"""
466446
assert self._is_master
467-
# Use standard request limiter for sending delayed events on-demand,
468-
# as an on-demand send is similar to sending a regular event.
469-
await self._request_ratelimiter.ratelimit(requester)
447+
await self._delayed_event_mgmt_ratelimiter.ratelimit(
448+
None, request.getClientAddress().host
449+
)
470450
await make_deferred_yieldable(self._initialized_from_db)
471451

472-
event, next_send_ts = await self._store.process_target_delayed_event(
473-
delay_id=delay_id,
474-
user_localpart=requester.user.localpart,
475-
)
452+
event, next_send_ts = await self._store.process_target_delayed_event(delay_id)
476453

477454
if self._next_send_ts_changed(next_send_ts):
478455
self._schedule_next_at_or_none(next_send_ts)
479456

480-
await self._send_event(
481-
DelayedEventDetails(
482-
delay_id=DelayID(delay_id),
483-
user_localpart=UserLocalpart(requester.user.localpart),
484-
room_id=event.room_id,
485-
type=event.type,
486-
state_key=event.state_key,
487-
origin_server_ts=event.origin_server_ts,
488-
content=event.content,
489-
device_id=event.device_id,
490-
)
491-
)
457+
await self._send_event(event)
492458

493459
async def _send_on_timeout(self) -> None:
494460
self._next_delayed_event_call = None
@@ -611,9 +577,7 @@ async def _send_event(
611577
finally:
612578
# TODO: If this is a temporary error, retry. Otherwise, consider notifying clients of the failure
613579
try:
614-
await self._store.delete_processed_delayed_event(
615-
event.delay_id, event.user_localpart
616-
)
580+
await self._store.delete_processed_delayed_event(event.delay_id)
617581
except Exception:
618582
logger.exception("Failed to delete processed delayed event")
619583

synapse/rest/client/delayed_events.py

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,11 @@ class UpdateDelayedEventServlet(RestServlet):
4747

4848
def __init__(self, hs: "HomeServer"):
4949
super().__init__()
50-
self.auth = hs.get_auth()
5150
self.delayed_events_handler = hs.get_delayed_events_handler()
5251

5352
async def on_POST(
5453
self, request: SynapseRequest, delay_id: str
5554
) -> tuple[int, JsonDict]:
56-
requester = await self.auth.get_user_by_req(request)
57-
5855
body = parse_json_object_from_request(request)
5956
try:
6057
action = str(body["action"])
@@ -75,11 +72,65 @@ async def on_POST(
7572
)
7673

7774
if enum_action == _UpdateDelayedEventAction.CANCEL:
78-
await self.delayed_events_handler.cancel(requester, delay_id)
75+
await self.delayed_events_handler.cancel(request, delay_id)
7976
elif enum_action == _UpdateDelayedEventAction.RESTART:
80-
await self.delayed_events_handler.restart(requester, delay_id)
77+
await self.delayed_events_handler.restart(request, delay_id)
8178
elif enum_action == _UpdateDelayedEventAction.SEND:
82-
await self.delayed_events_handler.send(requester, delay_id)
79+
await self.delayed_events_handler.send(request, delay_id)
80+
return 200, {}
81+
82+
83+
class CancelDelayedEventServlet(RestServlet):
84+
PATTERNS = client_patterns(
85+
r"/org\.matrix\.msc4140/delayed_events/(?P<delay_id>[^/]+)/cancel$",
86+
releases=(),
87+
)
88+
CATEGORY = "Delayed event management requests"
89+
90+
def __init__(self, hs: "HomeServer"):
91+
super().__init__()
92+
self.delayed_events_handler = hs.get_delayed_events_handler()
93+
94+
async def on_POST(
95+
self, request: SynapseRequest, delay_id: str
96+
) -> tuple[int, JsonDict]:
97+
await self.delayed_events_handler.cancel(request, delay_id)
98+
return 200, {}
99+
100+
101+
class RestartDelayedEventServlet(RestServlet):
102+
PATTERNS = client_patterns(
103+
r"/org\.matrix\.msc4140/delayed_events/(?P<delay_id>[^/]+)/restart$",
104+
releases=(),
105+
)
106+
CATEGORY = "Delayed event management requests"
107+
108+
def __init__(self, hs: "HomeServer"):
109+
super().__init__()
110+
self.delayed_events_handler = hs.get_delayed_events_handler()
111+
112+
async def on_POST(
113+
self, request: SynapseRequest, delay_id: str
114+
) -> tuple[int, JsonDict]:
115+
await self.delayed_events_handler.restart(request, delay_id)
116+
return 200, {}
117+
118+
119+
class SendDelayedEventServlet(RestServlet):
120+
PATTERNS = client_patterns(
121+
r"/org\.matrix\.msc4140/delayed_events/(?P<delay_id>[^/]+)/send$",
122+
releases=(),
123+
)
124+
CATEGORY = "Delayed event management requests"
125+
126+
def __init__(self, hs: "HomeServer"):
127+
super().__init__()
128+
self.delayed_events_handler = hs.get_delayed_events_handler()
129+
130+
async def on_POST(
131+
self, request: SynapseRequest, delay_id: str
132+
) -> tuple[int, JsonDict]:
133+
await self.delayed_events_handler.send(request, delay_id)
83134
return 200, {}
84135

85136

@@ -108,4 +159,7 @@ def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
108159
# The following can't currently be instantiated on workers.
109160
if hs.config.worker.worker_app is None:
110161
UpdateDelayedEventServlet(hs).register(http_server)
162+
CancelDelayedEventServlet(hs).register(http_server)
163+
RestartDelayedEventServlet(hs).register(http_server)
164+
SendDelayedEventServlet(hs).register(http_server)
111165
DelayedEventsServlet(hs).register(http_server)

0 commit comments

Comments
 (0)