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

Do not allow MSC3440 threads to fork threads #11161

Merged
merged 13 commits into from
Nov 18, 2021
Merged
4 changes: 2 additions & 2 deletions synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,7 @@ async def _validate_event_relation(self, event: EventBase) -> None:
else:
# There must be some reason that the client knows the event exists,
# see if there are existing relations. If so, assume everything is fine.
if not await self.store.event_related_to(relates_to):
if not await self.store.event_has_relation(relates_to):
# Otherwise, the client can't know about the parent event!
raise SynapseError(400, "Can't send relation to unknown event")

Expand All @@ -1057,7 +1057,7 @@ async def _validate_event_relation(self, event: EventBase) -> None:

# Don't attempt to start a thread if the parent event is a relation.
elif relation_type == RelationTypes.THREAD:
if await self.store.event_has_relations(relates_to):
if await self.store.event_includes_relation(relates_to):
raise SynapseError(
400, "Cannot start threads from an event with a relation"
)
Expand Down
45 changes: 35 additions & 10 deletions synapse/storage/databases/main/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,41 +132,66 @@ def _get_recent_references_for_event_txn(
"get_recent_references_for_event", _get_recent_references_for_event_txn
)

async def event_has_relations(self, event_id: str) -> bool:
"""Check if a given event has relations.
async def event_includes_relation(self, event_id: str) -> bool:
"""Check if the given event includes a valid relation.

An event has a relation if it has a valid m.relates_to with a rel_type
and event_id in the content:

{
"content": {
"m.relates_to": {
"rel_type": "m.replace",
"event_id": "$other_event_id"
}
}
}
clokep marked this conversation as resolved.
Show resolved Hide resolved

Args:
event_id: The event to check.

Returns:
True if the event has any relations.
True if the event includes a valid relation.
"""

result = await self.db_pool.simple_select_one_onecol(
table="event_relations",
keyvalues={"event_id": event_id},
retcol="event_id",
allow_none=True,
desc="event_has_relations",
desc="event_includes_relation",
)
return result is not None

async def event_related_to(self, parent_id: str) -> bool:
"""Check if a given event has other event relating to it.
async def event_has_relation(self, parent_id: str) -> bool:
clokep marked this conversation as resolved.
Show resolved Hide resolved
"""Check if the given event is referred to via another event's relation.

An event is the target of a relation if another event has a valid
m.relates_to with a rel_type and event_id pointing to parent_id in the
content:

{
"content": {
"m.relates_to": {
"rel_type": "m.replace",
"event_id": "$parent_id"
}
}
}
clokep marked this conversation as resolved.
Show resolved Hide resolved

Args:
parent_id: The event to check.

Returns:
True if the event is the target of any relations.
True if the event is the target of another event's relation.
"""

result = await self.db_pool.simple_select_one_onecol(
table="event_relations",
keyvalues={"relates_to_id": parent_id},
retcol="event_id",
allow_none=True,
desc="event_has_relations",
desc="event_has_relation",
)
return result is not None

Expand Down Expand Up @@ -400,7 +425,7 @@ async def events_have_relations(
%s;
"""

def _get_if_event_has_relations(txn) -> List[str]:
def _get_if_events_have_relations(txn) -> List[str]:
clauses: List[str] = []
clause, args = make_in_list_sql_clause(
txn.database_engine, "relates_to_id", parent_ids
Expand All @@ -425,7 +450,7 @@ def _get_if_event_has_relations(txn) -> List[str]:
return [row[0] for row in txn]

return await self.db_pool.runInteraction(
"get_if_event_has_relations", _get_if_event_has_relations
"get_if_events_have_relations", _get_if_events_have_relations
)

async def has_user_annotated_event(
Expand Down