Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 9fd057b

Browse files
Ensure (room_id, next_batch_id) is unique to avoid cross-talk/conflicts between batches (MSC2716) (#10877)
Part of [MSC2716](matrix-org/matrix-spec-proposals#2716) Part of #10737
1 parent 0f007fe commit 9fd057b

File tree

4 files changed

+43
-4
lines changed

4 files changed

+43
-4
lines changed

changelog.d/10877.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure `(room_id, next_batch_id)` is unique across [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) insertion events in rooms to avoid cross-talk/conflicts between batches.

synapse/handlers/message.py

+34
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# limitations under the License.
1717
import logging
1818
import random
19+
from http import HTTPStatus
1920
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple
2021

2122
from canonicaljson import encode_canonical_json
@@ -1461,6 +1462,39 @@ async def persist_and_notify_client_event(
14611462
if prev_state_ids:
14621463
raise AuthError(403, "Changing the room create event is forbidden")
14631464

1465+
if event.type == EventTypes.MSC2716_INSERTION:
1466+
room_version = await self.store.get_room_version_id(event.room_id)
1467+
room_version_obj = KNOWN_ROOM_VERSIONS[room_version]
1468+
1469+
create_event = await self.store.get_create_event_for_room(event.room_id)
1470+
room_creator = create_event.content.get(EventContentFields.ROOM_CREATOR)
1471+
1472+
# Only check an insertion event if the room version
1473+
# supports it or the event is from the room creator.
1474+
if room_version_obj.msc2716_historical or (
1475+
self.config.experimental.msc2716_enabled
1476+
and event.sender == room_creator
1477+
):
1478+
next_batch_id = event.content.get(
1479+
EventContentFields.MSC2716_NEXT_BATCH_ID
1480+
)
1481+
conflicting_insertion_event_id = (
1482+
await self.store.get_insertion_event_by_batch_id(
1483+
event.room_id, next_batch_id
1484+
)
1485+
)
1486+
if conflicting_insertion_event_id is not None:
1487+
# The current insertion event that we're processing is invalid
1488+
# because an insertion event already exists in the room with the
1489+
# same next_batch_id. We can't allow multiple because the batch
1490+
# pointing will get weird, e.g. we can't determine which insertion
1491+
# event the batch event is pointing to.
1492+
raise SynapseError(
1493+
HTTPStatus.BAD_REQUEST,
1494+
"Another insertion event already exists with the same next_batch_id",
1495+
errcode=Codes.INVALID_PARAM,
1496+
)
1497+
14641498
# Mark any `m.historical` messages as backfilled so they don't appear
14651499
# in `/sync` and have the proper decrementing `stream_ordering` as we import
14661500
backfilled = False

synapse/rest/client/room_batch.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,13 @@ async def on_POST(
306306
# Verify the batch_id_from_query corresponds to an actual insertion event
307307
# and have the batch connected.
308308
corresponding_insertion_event_id = (
309-
await self.store.get_insertion_event_by_batch_id(batch_id_from_query)
309+
await self.store.get_insertion_event_by_batch_id(
310+
room_id, batch_id_from_query
311+
)
310312
)
311313
if corresponding_insertion_event_id is None:
312314
raise SynapseError(
313-
400,
315+
HTTPStatus.BAD_REQUEST,
314316
"No insertion event corresponds to the given ?batch_id",
315317
errcode=Codes.INVALID_PARAM,
316318
)

synapse/storage/databases/main/room_batch.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919

2020
class RoomBatchStore(SQLBaseStore):
21-
async def get_insertion_event_by_batch_id(self, batch_id: str) -> Optional[str]:
21+
async def get_insertion_event_by_batch_id(
22+
self, room_id: str, batch_id: str
23+
) -> Optional[str]:
2224
"""Retrieve a insertion event ID.
2325
2426
Args:
@@ -30,7 +32,7 @@ async def get_insertion_event_by_batch_id(self, batch_id: str) -> Optional[str]:
3032
"""
3133
return await self.db_pool.simple_select_one_onecol(
3234
table="insertion_events",
33-
keyvalues={"next_batch_id": batch_id},
35+
keyvalues={"room_id": room_id, "next_batch_id": batch_id},
3436
retcol="event_id",
3537
allow_none=True,
3638
)

0 commit comments

Comments
 (0)