diff --git a/changelog.d/15563.misc b/changelog.d/15563.misc
new file mode 100644
index 0000000000..8bfecf2b95
--- /dev/null
+++ b/changelog.d/15563.misc
@@ -0,0 +1 @@
+Implement [MSC3821](https://github.com/matrix-org/matrix-spec-proposals/pull/3821) to update the redaction rules.
diff --git a/synapse/api/room_versions.py b/synapse/api/room_versions.py
index e65b9a0287..7030b133d3 100644
--- a/synapse/api/room_versions.py
+++ b/synapse/api/room_versions.py
@@ -103,6 +103,8 @@ class RoomVersion:
msc3787_knock_restricted_join_rule: bool
# MSC3667: Enforce integer power levels
msc3667_int_only_power_levels: bool
+ # MSC3821: Do not redact the third_party_invite content field for membership events.
+ msc3821_redaction_rules: bool
# MSC3931: Adds a push rule condition for "room version feature flags", making
# some push rules room version dependent. Note that adding a flag to this list
# is not enough to mark it "supported": the push rule evaluator also needs to
@@ -133,6 +135,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -155,6 +158,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -177,6 +181,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -199,6 +204,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -221,6 +227,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -243,6 +250,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -265,6 +273,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -287,6 +296,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -309,6 +319,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -331,6 +342,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -353,6 +365,30 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
+ msc3931_push_features=(),
+ msc3989_redaction_rules=False,
+ )
+ MSC3821 = RoomVersion(
+ "org.matrix.msc3821.opt1",
+ RoomDisposition.UNSTABLE,
+ EventFormatVersions.ROOM_V4_PLUS,
+ StateResolutionVersions.V2,
+ enforce_key_validity=True,
+ special_case_aliases_auth=False,
+ strict_canonicaljson=True,
+ limit_notifications_power_levels=True,
+ msc2175_implicit_room_creator=False,
+ msc2176_redaction_rules=False,
+ msc3083_join_rules=True,
+ msc3375_redaction_rules=True,
+ 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,
+ msc3821_redaction_rules=True,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -375,6 +411,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=True,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -397,6 +434,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=False,
)
@@ -420,6 +458,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=True,
+ msc3821_redaction_rules=False,
msc3931_push_features=(PushRuleRoomFlag.EXTENSIBLE_EVENTS,),
msc3989_redaction_rules=False,
)
@@ -442,6 +481,7 @@ class RoomVersions:
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=True,
+ msc3821_redaction_rules=False,
msc3931_push_features=(),
msc3989_redaction_rules=True,
)
diff --git a/synapse/events/utils.py b/synapse/events/utils.py
index e540f1582a..e6d040176b 100644
--- a/synapse/events/utils.py
+++ b/synapse/events/utils.py
@@ -130,6 +130,16 @@ def prune_event_dict(room_version: RoomVersion, event_dict: JsonDict) -> JsonDic
add_fields("membership")
if room_version.msc3375_redaction_rules:
add_fields(EventContentFields.AUTHORISING_USER)
+ if room_version.msc3821_redaction_rules:
+ # Preserve the signed field under third_party_invite.
+ third_party_invite = event_dict["content"].get("third_party_invite")
+ if isinstance(third_party_invite, collections.abc.Mapping):
+ new_content["third_party_invite"] = {}
+ if "signed" in third_party_invite:
+ new_content["third_party_invite"]["signed"] = third_party_invite[
+ "signed"
+ ]
+
elif event_type == EventTypes.Create:
# MSC2176 rules state that create events cannot be redacted.
if room_version.msc2176_redaction_rules:
diff --git a/tests/events/test_utils.py b/tests/events/test_utils.py
index 02f0800a31..e40eac2eb0 100644
--- a/tests/events/test_utils.py
+++ b/tests/events/test_utils.py
@@ -394,7 +394,7 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
)
def test_member(self) -> None:
- """Member events have changed behavior starting with MSC3375."""
+ """Member events have changed behavior in MSC3375 and MSC3821."""
self.run_test(
{
"type": "m.room.member",
@@ -437,6 +437,79 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
room_version=RoomVersions.V9,
)
+ # After MSC3821, the signed key under third_party_invite is protected
+ # from redaction.
+ THIRD_PARTY_INVITE = {
+ "display_name": "alice",
+ "signed": {
+ "mxid": "@alice:example.org",
+ "signatures": {
+ "magic.forest": {
+ "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
+ }
+ },
+ "token": "abc123",
+ },
+ }
+
+ self.run_test(
+ {
+ "type": "m.room.member",
+ "content": {
+ "membership": "invite",
+ "third_party_invite": THIRD_PARTY_INVITE,
+ "other_key": "stripped",
+ },
+ },
+ {
+ "type": "m.room.member",
+ "content": {
+ "membership": "invite",
+ "third_party_invite": {"signed": THIRD_PARTY_INVITE["signed"]},
+ },
+ "signatures": {},
+ "unsigned": {},
+ },
+ room_version=RoomVersions.MSC3821,
+ )
+
+ # Ensure this doesn't break if an invalid field is sent.
+ self.run_test(
+ {
+ "type": "m.room.member",
+ "content": {
+ "membership": "invite",
+ "third_party_invite": {},
+ "other_key": "stripped",
+ },
+ },
+ {
+ "type": "m.room.member",
+ "content": {"membership": "invite", "third_party_invite": {}},
+ "signatures": {},
+ "unsigned": {},
+ },
+ room_version=RoomVersions.MSC3821,
+ )
+
+ self.run_test(
+ {
+ "type": "m.room.member",
+ "content": {
+ "membership": "invite",
+ "third_party_invite": "stripped",
+ "other_key": "stripped",
+ },
+ },
+ {
+ "type": "m.room.member",
+ "content": {"membership": "invite"},
+ "signatures": {},
+ "unsigned": {},
+ },
+ room_version=RoomVersions.MSC3821,
+ )
+
def test_relations(self) -> None:
"""Event relations get redacted until MSC3389."""
# Normally the m._relates_to field is redacted.
|