mirror of
https://mau.dev/maunium/synapse.git
synced 2024-11-16 06:51:46 +01:00
Ensure (room_id, next_batch_id)
is unique to avoid cross-talk/conflicts between batches (MSC2716) (#10877)
Part of [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) Part of https://github.com/matrix-org/synapse/issues/10737
This commit is contained in:
parent
0f007fe009
commit
9fd057b8c5
4 changed files with 43 additions and 4 deletions
1
changelog.d/10877.feature
Normal file
1
changelog.d/10877.feature
Normal file
|
@ -0,0 +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.
|
|
@ -16,6 +16,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
from http import HTTPStatus
|
||||||
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple
|
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple
|
||||||
|
|
||||||
from canonicaljson import encode_canonical_json
|
from canonicaljson import encode_canonical_json
|
||||||
|
@ -1461,6 +1462,39 @@ class EventCreationHandler:
|
||||||
if prev_state_ids:
|
if prev_state_ids:
|
||||||
raise AuthError(403, "Changing the room create event is forbidden")
|
raise AuthError(403, "Changing the room create event is forbidden")
|
||||||
|
|
||||||
|
if event.type == EventTypes.MSC2716_INSERTION:
|
||||||
|
room_version = await self.store.get_room_version_id(event.room_id)
|
||||||
|
room_version_obj = KNOWN_ROOM_VERSIONS[room_version]
|
||||||
|
|
||||||
|
create_event = await self.store.get_create_event_for_room(event.room_id)
|
||||||
|
room_creator = create_event.content.get(EventContentFields.ROOM_CREATOR)
|
||||||
|
|
||||||
|
# Only check an insertion event if the room version
|
||||||
|
# supports it or the event is from the room creator.
|
||||||
|
if room_version_obj.msc2716_historical or (
|
||||||
|
self.config.experimental.msc2716_enabled
|
||||||
|
and event.sender == room_creator
|
||||||
|
):
|
||||||
|
next_batch_id = event.content.get(
|
||||||
|
EventContentFields.MSC2716_NEXT_BATCH_ID
|
||||||
|
)
|
||||||
|
conflicting_insertion_event_id = (
|
||||||
|
await self.store.get_insertion_event_by_batch_id(
|
||||||
|
event.room_id, next_batch_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if conflicting_insertion_event_id is not None:
|
||||||
|
# The current insertion event that we're processing is invalid
|
||||||
|
# because an insertion event already exists in the room with the
|
||||||
|
# same next_batch_id. We can't allow multiple because the batch
|
||||||
|
# pointing will get weird, e.g. we can't determine which insertion
|
||||||
|
# event the batch event is pointing to.
|
||||||
|
raise SynapseError(
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
"Another insertion event already exists with the same next_batch_id",
|
||||||
|
errcode=Codes.INVALID_PARAM,
|
||||||
|
)
|
||||||
|
|
||||||
# Mark any `m.historical` messages as backfilled so they don't appear
|
# Mark any `m.historical` messages as backfilled so they don't appear
|
||||||
# in `/sync` and have the proper decrementing `stream_ordering` as we import
|
# in `/sync` and have the proper decrementing `stream_ordering` as we import
|
||||||
backfilled = False
|
backfilled = False
|
||||||
|
|
|
@ -306,11 +306,13 @@ class RoomBatchSendEventRestServlet(RestServlet):
|
||||||
# Verify the batch_id_from_query corresponds to an actual insertion event
|
# Verify the batch_id_from_query corresponds to an actual insertion event
|
||||||
# and have the batch connected.
|
# and have the batch connected.
|
||||||
corresponding_insertion_event_id = (
|
corresponding_insertion_event_id = (
|
||||||
await self.store.get_insertion_event_by_batch_id(batch_id_from_query)
|
await self.store.get_insertion_event_by_batch_id(
|
||||||
|
room_id, batch_id_from_query
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if corresponding_insertion_event_id is None:
|
if corresponding_insertion_event_id is None:
|
||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
400,
|
HTTPStatus.BAD_REQUEST,
|
||||||
"No insertion event corresponds to the given ?batch_id",
|
"No insertion event corresponds to the given ?batch_id",
|
||||||
errcode=Codes.INVALID_PARAM,
|
errcode=Codes.INVALID_PARAM,
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,7 +18,9 @@ from synapse.storage._base import SQLBaseStore
|
||||||
|
|
||||||
|
|
||||||
class RoomBatchStore(SQLBaseStore):
|
class RoomBatchStore(SQLBaseStore):
|
||||||
async def get_insertion_event_by_batch_id(self, batch_id: str) -> Optional[str]:
|
async def get_insertion_event_by_batch_id(
|
||||||
|
self, room_id: str, batch_id: str
|
||||||
|
) -> Optional[str]:
|
||||||
"""Retrieve a insertion event ID.
|
"""Retrieve a insertion event ID.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -30,7 +32,7 @@ class RoomBatchStore(SQLBaseStore):
|
||||||
"""
|
"""
|
||||||
return await self.db_pool.simple_select_one_onecol(
|
return await self.db_pool.simple_select_one_onecol(
|
||||||
table="insertion_events",
|
table="insertion_events",
|
||||||
keyvalues={"next_batch_id": batch_id},
|
keyvalues={"room_id": room_id, "next_batch_id": batch_id},
|
||||||
retcol="event_id",
|
retcol="event_id",
|
||||||
allow_none=True,
|
allow_none=True,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue