mirror of
https://mau.dev/maunium/synapse.git
synced 2024-10-01 01:36:05 -04:00
Add forward-compatibility for the redacts property (MSC2174). (#16013)
The location of the redacts field changes in room version 11. Ensure it is copied to the *new* location for *old* room versions for forwards-compatibility with clients. Note that copying it to the *old* location for the *new* room version was previously handled.
This commit is contained in:
parent
01a45869f0
commit
4f5bccbbba
1
changelog.d/16013.misc
Normal file
1
changelog.d/16013.misc
Normal file
@ -0,0 +1 @@
|
|||||||
|
Properly overwrite the `redacts` content-property for forwards-compatibility with room versions 1 through 10.
|
@ -475,14 +475,16 @@ def serialize_event(
|
|||||||
if config.as_client_event:
|
if config.as_client_event:
|
||||||
d = config.event_format(d)
|
d = config.event_format(d)
|
||||||
|
|
||||||
# If the event is a redaction, copy the redacts field from the content to
|
# If the event is a redaction, the field with the redacted event ID appears
|
||||||
# top-level for backwards compatibility.
|
# in a different location depending on the room version. e.redacts handles
|
||||||
if (
|
# fetching from the proper location; copy it to the other location for forwards-
|
||||||
e.type == EventTypes.Redaction
|
# and backwards-compatibility with clients.
|
||||||
and e.room_version.updated_redaction_rules
|
if e.type == EventTypes.Redaction and e.redacts is not None:
|
||||||
and e.redacts is not None
|
if e.room_version.updated_redaction_rules:
|
||||||
):
|
d["redacts"] = e.redacts
|
||||||
d["redacts"] = e.redacts
|
else:
|
||||||
|
d["content"] = dict(d["content"])
|
||||||
|
d["content"]["redacts"] = e.redacts
|
||||||
|
|
||||||
only_event_fields = config.only_event_fields
|
only_event_fields = config.only_event_fields
|
||||||
if only_event_fields:
|
if only_event_fields:
|
||||||
|
@ -13,10 +13,12 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from parameterized import parameterized
|
||||||
|
|
||||||
from twisted.test.proto_helpers import MemoryReactor
|
from twisted.test.proto_helpers import MemoryReactor
|
||||||
|
|
||||||
from synapse.api.constants import EventTypes, RelationTypes
|
from synapse.api.constants import EventTypes, RelationTypes
|
||||||
from synapse.api.room_versions import RoomVersions
|
from synapse.api.room_versions import RoomVersion, RoomVersions
|
||||||
from synapse.rest import admin
|
from synapse.rest import admin
|
||||||
from synapse.rest.client import login, room, sync
|
from synapse.rest.client import login, room, sync
|
||||||
from synapse.server import HomeServer
|
from synapse.server import HomeServer
|
||||||
@ -569,50 +571,81 @@ class RedactionsTestCase(HomeserverTestCase):
|
|||||||
self.assertIn("body", event_dict["content"], event_dict)
|
self.assertIn("body", event_dict["content"], event_dict)
|
||||||
self.assertEqual("I'm in a thread!", event_dict["content"]["body"])
|
self.assertEqual("I'm in a thread!", event_dict["content"]["body"])
|
||||||
|
|
||||||
def test_content_redaction(self) -> None:
|
@parameterized.expand(
|
||||||
"""MSC2174 moved the redacts property to the content."""
|
[
|
||||||
|
# Tuples of:
|
||||||
|
# Room version
|
||||||
|
# Boolean: True if the redaction event content should include the event ID.
|
||||||
|
# Boolean: true if the resulting redaction event is expected to include the
|
||||||
|
# event ID in the content.
|
||||||
|
(RoomVersions.V10, False, False),
|
||||||
|
(RoomVersions.V11, True, True),
|
||||||
|
(RoomVersions.V11, False, True),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_redaction_content(
|
||||||
|
self, room_version: RoomVersion, include_content: bool, expect_content: bool
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Room version 11 moved the redacts property to the content.
|
||||||
|
|
||||||
|
Ensure that the event gets created properly and that the Client-Server
|
||||||
|
API servers the proper backwards-compatible version.
|
||||||
|
"""
|
||||||
# Create a room with the newer room version.
|
# Create a room with the newer room version.
|
||||||
room_id = self.helper.create_room_as(
|
room_id = self.helper.create_room_as(
|
||||||
self.mod_user_id,
|
self.mod_user_id,
|
||||||
tok=self.mod_access_token,
|
tok=self.mod_access_token,
|
||||||
room_version=RoomVersions.V11.identifier,
|
room_version=room_version.identifier,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create an event.
|
# Create an event.
|
||||||
b = self.helper.send(room_id=room_id, tok=self.mod_access_token)
|
b = self.helper.send(room_id=room_id, tok=self.mod_access_token)
|
||||||
event_id = b["event_id"]
|
event_id = b["event_id"]
|
||||||
|
|
||||||
# Attempt to redact it with a bogus event ID.
|
# Ensure the event ID in the URL and the content must match.
|
||||||
self._redact_event(
|
if include_content:
|
||||||
|
self._redact_event(
|
||||||
|
self.mod_access_token,
|
||||||
|
room_id,
|
||||||
|
event_id,
|
||||||
|
expect_code=400,
|
||||||
|
content={"redacts": "foo"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Redact it for real.
|
||||||
|
result = self._redact_event(
|
||||||
self.mod_access_token,
|
self.mod_access_token,
|
||||||
room_id,
|
room_id,
|
||||||
event_id,
|
event_id,
|
||||||
expect_code=400,
|
content={"redacts": event_id} if include_content else {},
|
||||||
content={"redacts": "foo"},
|
|
||||||
)
|
)
|
||||||
|
redaction_event_id = result["event_id"]
|
||||||
# Redact it for real.
|
|
||||||
self._redact_event(self.mod_access_token, room_id, event_id)
|
|
||||||
|
|
||||||
# Sync the room, to get the id of the create event
|
# Sync the room, to get the id of the create event
|
||||||
timeline = self._sync_room_timeline(self.mod_access_token, room_id)
|
timeline = self._sync_room_timeline(self.mod_access_token, room_id)
|
||||||
redact_event = timeline[-1]
|
redact_event = timeline[-1]
|
||||||
self.assertEqual(redact_event["type"], EventTypes.Redaction)
|
self.assertEqual(redact_event["type"], EventTypes.Redaction)
|
||||||
# The redacts key should be in the content.
|
# The redacts key should be in the content and the redacts keys.
|
||||||
self.assertEquals(redact_event["content"]["redacts"], event_id)
|
self.assertEquals(redact_event["content"]["redacts"], event_id)
|
||||||
|
|
||||||
# It should also be copied as the top-level redacts field for backwards
|
|
||||||
# compatibility.
|
|
||||||
self.assertEquals(redact_event["redacts"], event_id)
|
self.assertEquals(redact_event["redacts"], event_id)
|
||||||
|
|
||||||
# But it isn't actually part of the event.
|
# But it isn't actually part of the event.
|
||||||
def get_event(txn: LoggingTransaction) -> JsonDict:
|
def get_event(txn: LoggingTransaction) -> JsonDict:
|
||||||
return db_to_json(
|
return db_to_json(
|
||||||
main_datastore._fetch_event_rows(txn, [event_id])[event_id].json
|
main_datastore._fetch_event_rows(txn, [redaction_event_id])[
|
||||||
|
redaction_event_id
|
||||||
|
].json
|
||||||
)
|
)
|
||||||
|
|
||||||
main_datastore = self.hs.get_datastores().main
|
main_datastore = self.hs.get_datastores().main
|
||||||
event_json = self.get_success(
|
event_json = self.get_success(
|
||||||
main_datastore.db_pool.runInteraction("get_event", get_event)
|
main_datastore.db_pool.runInteraction("get_event", get_event)
|
||||||
)
|
)
|
||||||
self.assertNotIn("redacts", event_json)
|
self.assertEquals(event_json["type"], EventTypes.Redaction)
|
||||||
|
if expect_content:
|
||||||
|
self.assertNotIn("redacts", event_json)
|
||||||
|
self.assertEquals(event_json["content"]["redacts"], event_id)
|
||||||
|
else:
|
||||||
|
self.assertEquals(event_json["redacts"], event_id)
|
||||||
|
self.assertNotIn("redacts", event_json["content"])
|
||||||
|
Loading…
Reference in New Issue
Block a user