Implement MSC3389 to protect relations from redaction. (#15565)
MSC3389 proposes protecting the relation type & parent event ID from redaction. This keeps the relation information intact after redaction which helps with some UX flaws (e.g. deleting an event causes it to no longer be in a thread, which is confusing).
This commit is contained in:
parent
8583346335
commit
ba6b21c81e
|
@ -0,0 +1 @@
|
|||
Implement updated redaction rules from [MSC3389](https://github.com/matrix-org/matrix-spec-proposals/pull/3389).
|
|
@ -96,6 +96,8 @@ class RoomVersion:
|
|||
msc2716_historical: bool
|
||||
# MSC2716: Adds support for redacting "insertion", "chunk", and "marker" events
|
||||
msc2716_redactions: bool
|
||||
# MSC3389: Protect relation information from redaction.
|
||||
msc3389_relation_redactions: bool
|
||||
# MSC3787: Adds support for a `knock_restricted` join rule, mixing concepts of
|
||||
# knocks and restricted join rules into the same join condition.
|
||||
msc3787_knock_restricted_join_rule: bool
|
||||
|
@ -128,6 +130,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -149,6 +152,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -170,6 +174,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -191,6 +196,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -212,6 +218,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -233,6 +240,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -254,6 +262,7 @@ class RoomVersions:
|
|||
msc2403_knocking=False,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -275,6 +284,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -296,6 +306,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -317,6 +328,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -338,6 +350,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=True,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -359,6 +372,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=True,
|
||||
msc3667_int_only_power_levels=True,
|
||||
msc3931_push_features=(),
|
||||
|
@ -380,6 +394,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=True,
|
||||
msc2716_redactions=True,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=False,
|
||||
msc3667_int_only_power_levels=False,
|
||||
msc3931_push_features=(),
|
||||
|
@ -402,6 +417,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=True,
|
||||
msc3667_int_only_power_levels=True,
|
||||
msc3931_push_features=(PushRuleRoomFlag.EXTENSIBLE_EVENTS,),
|
||||
|
@ -423,6 +439,7 @@ class RoomVersions:
|
|||
msc2403_knocking=True,
|
||||
msc2716_historical=False,
|
||||
msc2716_redactions=False,
|
||||
msc3389_relation_redactions=False,
|
||||
msc3787_knock_restricted_join_rule=True,
|
||||
msc3667_int_only_power_levels=True,
|
||||
msc3931_push_features=(),
|
||||
|
|
|
@ -171,6 +171,18 @@ def prune_event_dict(room_version: RoomVersion, event_dict: JsonDict) -> JsonDic
|
|||
elif room_version.msc2716_redactions and event_type == EventTypes.MSC2716_MARKER:
|
||||
add_fields(EventContentFields.MSC2716_INSERTION_EVENT_REFERENCE)
|
||||
|
||||
# Protect the rel_type and event_id fields under the m.relates_to field.
|
||||
if room_version.msc3389_relation_redactions:
|
||||
relates_to = event_dict["content"].get("m.relates_to")
|
||||
if isinstance(relates_to, collections.abc.Mapping):
|
||||
new_relates_to = {}
|
||||
for field in ("rel_type", "event_id"):
|
||||
if field in relates_to:
|
||||
new_relates_to[field] = relates_to[field]
|
||||
# Only include a non-empty relates_to field.
|
||||
if new_relates_to:
|
||||
new_content["m.relates_to"] = new_relates_to
|
||||
|
||||
allowed_fields = {k: v for k, v in event_dict.items() if k in allowed_keys}
|
||||
|
||||
allowed_fields["content"] = new_content
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
import unittest as stdlib_unittest
|
||||
from typing import Any, List, Mapping, Optional
|
||||
|
||||
import attr
|
||||
|
||||
from synapse.api.constants import EventContentFields
|
||||
from synapse.api.room_versions import RoomVersions
|
||||
from synapse.events import EventBase, make_event_from_dict
|
||||
|
@ -435,6 +437,94 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
|
|||
room_version=RoomVersions.V9,
|
||||
)
|
||||
|
||||
def test_relations(self) -> None:
|
||||
"""Event relations get redacted until MSC3389."""
|
||||
# Normally the m._relates_to field is redacted.
|
||||
self.run_test(
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "foo",
|
||||
"m.relates_to": {
|
||||
"rel_type": "rel_type",
|
||||
"event_id": "$parent:domain",
|
||||
"other": "stripped",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {},
|
||||
"signatures": {},
|
||||
"unsigned": {},
|
||||
},
|
||||
room_version=RoomVersions.V10,
|
||||
)
|
||||
|
||||
# Create a new room version.
|
||||
msc3389_room_ver = attr.evolve(
|
||||
RoomVersions.V10, msc3389_relation_redactions=True
|
||||
)
|
||||
|
||||
self.run_test(
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "foo",
|
||||
"m.relates_to": {
|
||||
"rel_type": "rel_type",
|
||||
"event_id": "$parent:domain",
|
||||
"other": "stripped",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"rel_type": "rel_type",
|
||||
"event_id": "$parent:domain",
|
||||
},
|
||||
},
|
||||
"signatures": {},
|
||||
"unsigned": {},
|
||||
},
|
||||
room_version=msc3389_room_ver,
|
||||
)
|
||||
|
||||
# If the field is not an object, redact it.
|
||||
self.run_test(
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "foo",
|
||||
"m.relates_to": "stripped",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {},
|
||||
"signatures": {},
|
||||
"unsigned": {},
|
||||
},
|
||||
room_version=msc3389_room_ver,
|
||||
)
|
||||
|
||||
# If the m.relates_to property would be empty, redact it.
|
||||
self.run_test(
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {"body": "foo", "m.relates_to": {"foo": "stripped"}},
|
||||
},
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"content": {},
|
||||
"signatures": {},
|
||||
"unsigned": {},
|
||||
},
|
||||
room_version=msc3389_room_ver,
|
||||
)
|
||||
|
||||
|
||||
class SerializeEventTestCase(stdlib_unittest.TestCase):
|
||||
def serialize(self, ev: EventBase, fields: Optional[List[str]]) -> JsonDict:
|
||||
|
|
Loading…
Reference in New Issue