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

Untested approach for MSC2174 #12634

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions synapse/api/room_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class RoomVersion:
limit_notifications_power_levels: bool
# MSC2174/MSC2176: Apply updated redaction rules algorithm.
msc2176_redaction_rules: bool
# MSC2174: Move `redacts` into `content`
msc2174_redacts_key_content: bool
# MSC3083: Support the 'restricted' join_rule.
msc3083_join_rules: bool
# MSC3375: Support for the proper redaction rules for MSC3083. This mustn't
Expand All @@ -94,6 +96,7 @@ class RoomVersions:
strict_canonicaljson=False,
limit_notifications_power_levels=False,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -110,6 +113,7 @@ class RoomVersions:
strict_canonicaljson=False,
limit_notifications_power_levels=False,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -126,6 +130,7 @@ class RoomVersions:
strict_canonicaljson=False,
limit_notifications_power_levels=False,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -142,6 +147,7 @@ class RoomVersions:
strict_canonicaljson=False,
limit_notifications_power_levels=False,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -158,6 +164,7 @@ class RoomVersions:
strict_canonicaljson=False,
limit_notifications_power_levels=False,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -174,6 +181,7 @@ class RoomVersions:
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -190,6 +198,25 @@ class RoomVersions:
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=True,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
)
MSC2174 = RoomVersion(
# v6 + MSC2174
"org.matrix.msc2174",
RoomDisposition.UNSTABLE,
EventFormatVersions.V3,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=True,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=False,
Expand All @@ -206,6 +233,7 @@ class RoomVersions:
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=True,
Expand All @@ -222,6 +250,7 @@ class RoomVersions:
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=True,
msc3375_redaction_rules=False,
msc2403_knocking=True,
Expand All @@ -238,6 +267,7 @@ class RoomVersions:
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=True,
msc3375_redaction_rules=True,
msc2403_knocking=True,
Expand All @@ -254,6 +284,7 @@ class RoomVersions:
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc2174_redacts_key_content=False,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=True,
Expand All @@ -272,6 +303,7 @@ class RoomVersions:
RoomVersions.V5,
RoomVersions.V6,
RoomVersions.MSC2176,
RoomVersions.MSC2174,
RoomVersions.V7,
RoomVersions.V8,
RoomVersions.V9,
Expand Down
2 changes: 2 additions & 0 deletions synapse/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,8 @@ def check_redaction(

if room_version_obj.event_format == EventFormatVersions.V1:
redacter_domain = get_domain_from_id(event.event_id)
# Note: Room versions with v1-formatted events *cannot* have the
# `redacts` key in `content` from MSC2174/MSC2176.
if not isinstance(event.redacts, str):
return False
redactee_domain = get_domain_from_id(event.redacts)
Expand Down
9 changes: 9 additions & 0 deletions synapse/events/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,15 @@ def serialize_event(
raise TypeError("only_event_fields must be a list of strings")
d = only_fields(d, only_event_fields)

if d["content"] is not None and e.type == EventTypes.Redaction:
# If the redacts key is in the `content`, copy it to the top level for
# older clients. Similarly, if the redacts key is already at the top
# level then copy it to `content` for newer clients.
if e.room_version.msc2174_redacts_key_content:
d["redacts"] = d["content"]["redacts"]
else:
d["content"]["redacts"] = d["redacts"]

return d


Expand Down
17 changes: 12 additions & 5 deletions synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -1403,10 +1403,14 @@ async def persist_and_notify_client_event(
# user is actually admin or not).
is_admin_redaction = False
if event.type == EventTypes.Redaction:
assert event.redacts is not None
redacts = event.redacts
if event.room_version.msc2174_redacts_key_content:
redacts = event.content["redacts"]

assert redacts is not None

original_event = await self.store.get_event(
event.redacts,
redacts,
redact_behaviour=EventRedactBehaviour.as_is,
get_prev_content=False,
allow_rejected=False,
Expand Down Expand Up @@ -1500,10 +1504,13 @@ async def persist_and_notify_client_event(
)

if event.type == EventTypes.Redaction:
assert event.redacts is not None
redacts = event.redacts
if event.room_version.msc2174_redacts_key_content:
redacts = event.content["redacts"]
assert redacts is not None

original_event = await self.store.get_event(
event.redacts,
redacts,
redact_behaviour=EventRedactBehaviour.as_is,
get_prev_content=False,
allow_rejected=False,
Expand Down Expand Up @@ -1560,7 +1567,7 @@ async def persist_and_notify_client_event(
# checks on the original event. Let's start by checking the original
# event exists.
if not original_event:
raise NotFoundError("Could not find event %s" % (event.redacts,))
raise NotFoundError("Could not find event %s" % (redacts,))

if event.user_id != original_event.user_id:
raise AuthError(403, "You don't have permission to redact events")
Expand Down
2 changes: 2 additions & 0 deletions synapse/storage/databases/main/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def process_replication_rows(
row.room_id,
row.type,
row.state_key,
# TODO: Support `redacts` being in `content` rather than at the top level.
row.redacts,
row.relates_to,
backfilled=True,
Expand Down Expand Up @@ -159,6 +160,7 @@ def _process_event_stream_row(self, token: int, row: EventsStreamRow) -> None:
data.room_id,
data.type,
data.state_key,
# TODO: Support `redacts` being in `content` rather than at the top level.
data.redacts,
data.relates_to,
backfilled=False,
Expand Down
32 changes: 22 additions & 10 deletions synapse/storage/databases/main/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1538,15 +1538,18 @@ def _update_metadata_tables_txn(
return

for event, _ in events_and_contexts:
if event.type == EventTypes.Redaction and event.redacts is not None:
redacts = event.redacts
if event.room_version.msc2174_redacts_key_content:
redacts = event.content["redacts"]
if event.type == EventTypes.Redaction and redacts is not None:
# Remove the entries in the event_push_actions table for the
# redacted event.
self._remove_push_actions_for_event_id_txn(
txn, event.room_id, event.redacts
txn, event.room_id, redacts
)

# Remove from relations table.
self._handle_redact_relations(txn, event.redacts)
self._handle_redact_relations(txn, redacts)

# Update the event_forward_extremities, event_backward_extremities and
# event_edges tables.
Expand All @@ -1564,9 +1567,13 @@ def _update_metadata_tables_txn(
elif event.type == EventTypes.Message:
# Insert into the event_search table.
self._store_room_message_txn(txn, event)
elif event.type == EventTypes.Redaction and event.redacts is not None:
# Insert into the redactions table.
self._store_redaction(txn, event)
elif event.type == EventTypes.Redaction:
redacts = event.redacts
if event.room_version.msc2174_redacts_key_content:
redacts = event.content["redacts"]
if redacts is not None:
# Insert into the redactions table.
self._store_redaction(txn, event)
elif event.type == EventTypes.Retention:
# Update the room_retention table.
self._store_retention_policy_for_room_txn(txn, event)
Expand Down Expand Up @@ -1617,6 +1624,7 @@ def _add_to_cache(self, txn, events_and_contexts):
if not ev_map:
return

# TODO: Support `redacts` being in `content` rather than at the top level.
sql = (
"SELECT "
" e.event_id as event_id, "
Expand Down Expand Up @@ -1648,18 +1656,22 @@ def prefill():
txn.call_after(prefill)

def _store_redaction(self, txn: LoggingTransaction, event: EventBase) -> None:
redacts = event.redacts
if event.room_version.msc2174_redacts_key_content:
redacts = event.content["redacts"]

# Invalidate the caches for the redacted event, note that these caches
# are also cleared as part of event replication in _invalidate_caches_for_event.
txn.call_after(self.store._invalidate_get_event_cache, event.redacts)
txn.call_after(self.store.get_relations_for_event.invalidate, (event.redacts,))
txn.call_after(self.store.get_applicable_edit.invalidate, (event.redacts,))
txn.call_after(self.store._invalidate_get_event_cache, redacts)
txn.call_after(self.store.get_relations_for_event.invalidate, (redacts,))
txn.call_after(self.store.get_applicable_edit.invalidate, (redacts,))

self.db_pool.simple_upsert_txn(
txn,
table="redactions",
keyvalues={"event_id": event.event_id},
values={
"redacts": event.redacts,
"redacts": redacts,
"received_ts": self._clock.time_msec(),
},
)
Expand Down
1 change: 1 addition & 0 deletions synapse/storage/databases/main/events_bg_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ async def _event_fix_redactions_bytes(

def _event_fix_redactions_bytes_txn(txn: LoggingTransaction) -> None:
# This update is quite fast due to new index.
# TODO: Support `redacts` being in `content` rather than at the top level.
txn.execute(
"""
UPDATE event_json
Expand Down
6 changes: 4 additions & 2 deletions synapse/storage/databases/main/events_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,10 @@ async def get_events_as_list(
# we have to recheck auth now.

if not allow_rejected and entry.event.type == EventTypes.Redaction:
if entry.event.redacts is None:
redacted_event_id = entry.event.redacts
if entry.event.room_version.msc2174_redacts_key_content:
redacted_event_id = entry.event.content["redacts"]
if redacted_event_id is None:
# A redacted redaction doesn't have a `redacts` key, in
# which case lets just withhold the event.
#
Expand All @@ -511,7 +514,6 @@ async def get_events_as_list(
)
continue

redacted_event_id = entry.event.redacts
event_map = await self._get_events_from_cache_or_db([redacted_event_id])
original_event_entry = event_map.get(redacted_event_id)
if not original_event_entry:
Expand Down