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

Commit 2503126

Browse files
authored
Implement MSC2174: move redacts to a content property. (#15395)
This moves `redacts` from being a top-level property to a `content` property in a new room version. MSC2176 (which was previously implemented) states to not `redact` this property.
1 parent c9723a1 commit 2503126

File tree

8 files changed

+87
-17
lines changed

8 files changed

+87
-17
lines changed

changelog.d/15395.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement [MSC2174](https://github.com/matrix-org/matrix-spec-proposals/pull/2174) to move the `redacts` key to a `content` property.

synapse/api/room_versions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class RoomVersion:
8080
limit_notifications_power_levels: bool
8181
# MSC2175: No longer include the creator in m.room.create events.
8282
msc2175_implicit_room_creator: bool
83-
# MSC2174/MSC2176: Apply updated redaction rules algorithm.
83+
# MSC2174/MSC2176: Apply updated redaction rules algorithm, move redacts to
84+
# content property.
8485
msc2176_redaction_rules: bool
8586
# MSC3083: Support the 'restricted' join_rule.
8687
msc3083_join_rules: bool

synapse/event_auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ def check_redaction(
793793
"""Check whether the event sender is allowed to redact the target event.
794794
795795
Returns:
796-
True if the the sender is allowed to redact the target event if the
796+
True if the sender is allowed to redact the target event if the
797797
target event was created by them.
798798
False if the sender is allowed to redact the target event with no
799799
further checks.

synapse/events/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,6 @@ def __init__(
326326
hashes: DictProperty[Dict[str, str]] = DictProperty("hashes")
327327
origin: DictProperty[str] = DictProperty("origin")
328328
origin_server_ts: DictProperty[int] = DictProperty("origin_server_ts")
329-
redacts: DefaultDictProperty[Optional[str]] = DefaultDictProperty("redacts", None)
330329
room_id: DictProperty[str] = DictProperty("room_id")
331330
sender: DictProperty[str] = DictProperty("sender")
332331
# TODO state_key should be Optional[str]. This is generally asserted in Synapse
@@ -346,6 +345,13 @@ def event_id(self) -> str:
346345
def membership(self) -> str:
347346
return self.content["membership"]
348347

348+
@property
349+
def redacts(self) -> Optional[str]:
350+
"""MSC2176 moved the redacts field into the content."""
351+
if self.room_version.msc2176_redaction_rules:
352+
return self.content.get("redacts")
353+
return self.get("redacts")
354+
349355
def is_state(self) -> bool:
350356
return self.get_state_key() is not None
351357

synapse/events/builder.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ async def build(
173173
if self.is_state():
174174
event_dict["state_key"] = self._state_key
175175

176-
if self._redacts is not None:
176+
# MSC2174 moves the redacts property to the content, it is invalid to
177+
# provide it as a top-level property.
178+
if self._redacts is not None and not self.room_version.msc2176_redaction_rules:
177179
event_dict["redacts"] = self._redacts
178180

179181
if self._origin_server_ts is not None:

synapse/rest/client/room.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ def __init__(self, hs: "HomeServer"):
10961096
super().__init__(hs)
10971097
self.event_creation_handler = hs.get_event_creation_handler()
10981098
self.auth = hs.get_auth()
1099+
self._store = hs.get_datastores().main
10991100
self._relation_handler = hs.get_relations_handler()
11001101
self._msc3912_enabled = hs.config.experimental.msc3912_enabled
11011102

@@ -1113,6 +1114,19 @@ async def _do(
11131114
) -> Tuple[int, JsonDict]:
11141115
content = parse_json_object_from_request(request)
11151116

1117+
# Ensure the redacts property in the content matches the one provided in
1118+
# the URL.
1119+
room_version = await self._store.get_room_version(room_id)
1120+
if room_version.msc2176_redaction_rules:
1121+
if "redacts" in content and content["redacts"] != event_id:
1122+
raise SynapseError(
1123+
400,
1124+
"Cannot provide a redacts value incoherent with the event_id of the URL parameter",
1125+
Codes.INVALID_PARAM,
1126+
)
1127+
else:
1128+
content["redacts"] = event_id
1129+
11161130
try:
11171131
with_relations = None
11181132
if self._msc3912_enabled and "org.matrix.msc3912.with_relations" in content:
@@ -1128,20 +1142,23 @@ async def _do(
11281142
requester, txn_id, room_id
11291143
)
11301144

1145+
# Event is not yet redacted, create a new event to redact it.
11311146
if event is None:
1147+
event_dict = {
1148+
"type": EventTypes.Redaction,
1149+
"content": content,
1150+
"room_id": room_id,
1151+
"sender": requester.user.to_string(),
1152+
}
1153+
# Earlier room versions had a top-level redacts property.
1154+
if not room_version.msc2176_redaction_rules:
1155+
event_dict["redacts"] = event_id
1156+
11321157
(
11331158
event,
11341159
_,
11351160
) = await self.event_creation_handler.create_and_send_nonmember_event(
1136-
requester,
1137-
{
1138-
"type": EventTypes.Redaction,
1139-
"content": content,
1140-
"room_id": room_id,
1141-
"sender": requester.user.to_string(),
1142-
"redacts": event_id,
1143-
},
1144-
txn_id=txn_id,
1161+
requester, event_dict, txn_id=txn_id
11451162
)
11461163

11471164
if with_relations:

tests/events/test_utils.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,11 @@ def test_redacts(self) -> None:
318318
"""Redaction events have no special behaviour until MSC2174/MSC2176."""
319319

320320
self.run_test(
321-
{"type": "m.room.redaction", "content": {"redacts": "$test2:domain"}},
321+
{
322+
"type": "m.room.redaction",
323+
"content": {"redacts": "$test2:domain"},
324+
"redacts": "$test2:domain",
325+
},
322326
{
323327
"type": "m.room.redaction",
324328
"content": {},
@@ -330,7 +334,11 @@ def test_redacts(self) -> None:
330334

331335
# After MSC2174, redaction events keep the redacts content key.
332336
self.run_test(
333-
{"type": "m.room.redaction", "content": {"redacts": "$test2:domain"}},
337+
{
338+
"type": "m.room.redaction",
339+
"content": {"redacts": "$test2:domain"},
340+
"redacts": "$test2:domain",
341+
},
334342
{
335343
"type": "m.room.redaction",
336344
"content": {"redacts": "$test2:domain"},

tests/rest/client/test_redactions.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from twisted.test.proto_helpers import MemoryReactor
1717

1818
from synapse.api.constants import EventTypes, RelationTypes
19+
from synapse.api.room_versions import RoomVersions
1920
from synapse.rest import admin
2021
from synapse.rest.client import login, room, sync
2122
from synapse.server import HomeServer
@@ -74,14 +75,15 @@ def _redact_event(
7475
event_id: str,
7576
expect_code: int = 200,
7677
with_relations: Optional[List[str]] = None,
78+
content: Optional[JsonDict] = None,
7779
) -> JsonDict:
7880
"""Helper function to send a redaction event.
7981
8082
Returns the json body.
8183
"""
8284
path = "/_matrix/client/r0/rooms/%s/redact/%s" % (room_id, event_id)
8385

84-
request_content = {}
86+
request_content = content or {}
8587
if with_relations:
8688
request_content["org.matrix.msc3912.with_relations"] = with_relations
8789

@@ -92,7 +94,7 @@ def _redact_event(
9294
return channel.json_body
9395

9496
def _sync_room_timeline(self, access_token: str, room_id: str) -> List[JsonDict]:
95-
channel = self.make_request("GET", "sync", access_token=self.mod_access_token)
97+
channel = self.make_request("GET", "sync", access_token=access_token)
9698
self.assertEqual(channel.code, 200)
9799
room_sync = channel.json_body["rooms"]["join"][room_id]
98100
return room_sync["timeline"]["events"]
@@ -466,3 +468,36 @@ def test_redact_relations_txn_id_reuse(self) -> None:
466468
)
467469
self.assertIn("body", event_dict["content"], event_dict)
468470
self.assertEqual("I'm in a thread!", event_dict["content"]["body"])
471+
472+
def test_content_redaction(self) -> None:
473+
"""MSC2174 moved the redacts property to the content."""
474+
# Create a room with the newer room version.
475+
room_id = self.helper.create_room_as(
476+
self.mod_user_id,
477+
tok=self.mod_access_token,
478+
room_version=RoomVersions.MSC2176.identifier,
479+
)
480+
481+
# Create an event.
482+
b = self.helper.send(room_id=room_id, tok=self.mod_access_token)
483+
event_id = b["event_id"]
484+
485+
# Attempt to redact it with a bogus event ID.
486+
self._redact_event(
487+
self.mod_access_token,
488+
room_id,
489+
event_id,
490+
expect_code=400,
491+
content={"redacts": "foo"},
492+
)
493+
494+
# Redact it for real.
495+
self._redact_event(self.mod_access_token, room_id, event_id)
496+
497+
# Sync the room, to get the id of the create event
498+
timeline = self._sync_room_timeline(self.mod_access_token, room_id)
499+
redact_event = timeline[-1]
500+
self.assertEqual(redact_event["type"], EventTypes.Redaction)
501+
# The redacts key should be in the content.
502+
self.assertNotIn("redacts", redact_event)
503+
self.assertEquals(redact_event["content"]["redacts"], event_id)

0 commit comments

Comments
 (0)