From da82f492e891e50255dcb0f47894cfdc5c73a17b Mon Sep 17 00:00:00 2001 From: Kierre Date: Sun, 26 Oct 2025 22:38:22 -0400 Subject: [PATCH] Implement redaction for v1 to v11 events --- vona/federation/__init__.py | 2 +- vona/federation/rooms.py | 12 ++++---- vona/globals/__init__.py | 60 ++++++++++++++++++++++++++++++++----- vona/utils/joinroom.py | 5 +++- 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/vona/federation/__init__.py b/vona/federation/__init__.py index e40cd6f..476851b 100644 --- a/vona/federation/__init__.py +++ b/vona/federation/__init__.py @@ -174,7 +174,7 @@ async def make_join(room, user): return jsonify({ - "event": globals.hash_and_sign_event(join), + "event": globals.hash_and_sign_event(join, int(room_ver)), "room_version": room_ver }) diff --git a/vona/federation/rooms.py b/vona/federation/rooms.py index efbf3d2..1ae4aa9 100644 --- a/vona/federation/rooms.py +++ b/vona/federation/rooms.py @@ -223,12 +223,12 @@ def v3(request, room) -> dict: del event["signatures"] # m.room.create doesn't have prev_events or auth_events - events["m.room.create"] = globals.hash_and_sign_event(events["m.room.create"]) + events["m.room.create"] = globals.hash_and_sign_event(events["m.room.create"], ver) hash_map["m.room.create"] = globals.make_ref_hash(events["m.room.create"], ver) events["m.room.member"]["auth_events"] = [hash_map["m.room.create"]] events["m.room.member"]["prev_events"] = [hash_map["m.room.create"]] - events["m.room.member"] = globals.hash_and_sign_event(events["m.room.member"]) + events["m.room.member"] = globals.hash_and_sign_event(events["m.room.member"], ver) hash_map["m.room.member"] = globals.make_ref_hash(events["m.room.member"], ver) events["m.room.power_levels"]["auth_events"] = [ @@ -238,7 +238,7 @@ def v3(request, room) -> dict: events["m.room.power_levels"]["prev_events"] = [hash_map["m.room.member"]] if ver == 10: events["m.room.power_levels"]["content"]["users"][f"@vona:{config.server_name}"] = 100 - events["m.room.power_levels"] = globals.hash_and_sign_event(events["m.room.power_levels"]) + events["m.room.power_levels"] = globals.hash_and_sign_event(events["m.room.power_levels"], ver) hash_map["m.room.power_levels"] = globals.make_ref_hash(events["m.room.power_levels"], ver) events["m.room.join_rules"]["auth_events"] = [ @@ -247,7 +247,7 @@ def v3(request, room) -> dict: hash_map["m.room.power_levels"], ] events["m.room.join_rules"]["prev_events"] = [hash_map["m.room.power_levels"]] - events["m.room.join_rules"] = globals.hash_and_sign_event(events["m.room.join_rules"]) + events["m.room.join_rules"] = globals.hash_and_sign_event(events["m.room.join_rules"], ver) hash_map["m.room.join_rules"] = globals.make_ref_hash(events["m.room.join_rules"], ver) events["m.room.guest_access"]["auth_events"] = [ @@ -256,7 +256,7 @@ def v3(request, room) -> dict: hash_map["m.room.power_levels"], ] events["m.room.guest_access"]["prev_events"] = [hash_map["m.room.join_rules"]] - events["m.room.guest_access"] = globals.hash_and_sign_event(events["m.room.guest_access"]) + events["m.room.guest_access"] = globals.hash_and_sign_event(events["m.room.guest_access"], ver) hash_map["m.room.guest_access"] = globals.make_ref_hash(events["m.room.guest_access"], ver) events["m.room.history_visibility"]["auth_events"] = [ @@ -265,7 +265,7 @@ def v3(request, room) -> dict: hash_map["m.room.power_levels"], ] events["m.room.history_visibility"]["prev_events"] = [hash_map["m.room.guest_access"]] - events["m.room.history_visibility"] = globals.hash_and_sign_event(events["m.room.history_visibility"]) + events["m.room.history_visibility"] = globals.hash_and_sign_event(events["m.room.history_visibility"], ver) new_state = [] diff --git a/vona/globals/__init__.py b/vona/globals/__init__.py index a1be0d1..35c1f06 100644 --- a/vona/globals/__init__.py +++ b/vona/globals/__init__.py @@ -8,6 +8,7 @@ import base64 import random import httpx import json +import copy import re version = "1.5.0" @@ -171,9 +172,10 @@ def make_auth_header( def redact_event( event: dict, for_event_id: bool = False, + room_ver: int = 1, ): # Returns a redacted event as per - # the algorithm for v1/v2 rooms. + # the algorithm for v1 to v11 rooms. allowed_keys = [ "event_id", @@ -185,16 +187,18 @@ def redact_event( "hashes", "depth", "prev_events", - "prev_state", "auth_events", - "origin", "origin_server_ts", - "membership", ] if not for_event_id: allowed_keys.append("signatures") + if room_ver < 11: + allowed_keys.append("origin") + allowed_keys.append("membership") + allowed_keys.append("prev_state") + redacted_event = {k: v for k, v in event.items() if k in allowed_keys} if "type" in redacted_event and "content" in redacted_event: @@ -218,23 +222,59 @@ def redact_event( "m.room.history_visibility": ["history_visibility"], } + if room_ver >= 6: + del content_key_rules["m.room.aliases"] + + if room_ver >= 8: + content_key_rules["m.room.join_rules"].append("allow") + + if room_ver >= 9: + content_key_rules["m.room.member"].append("join_authorised_via_users_server") + + if room_ver >= 11: + content_key_rules["m.room.redaction"] = ["redacts"] + del content_key_rules["m.room.create"] # All keys will be permitted + + if event_type in content_key_rules: allowed_content_keys = content_key_rules[event_type] + + if ( + room_ver >= 11 + and "third_party_invite" in redacted_event + and "signed" in redacted_event["third_party_invite"] + ): + third_party_invite_signature = copy.deepcopy(redacted_event["third_party_invite"]["signed"]) + else: + third_party_invite_signature = None + redacted_event["content"] = { k: v for k, v in redacted_event["content"].items() if k in allowed_content_keys } + + if third_party_invite_signature: + redacted_event["content"]["third_party_invite"] = { + "signed": third_party_invite_signature + } + else: - redacted_event["content"] = {} + if room_ver >= 11 and event_type == "m.room.create": + pass + else: + redacted_event["content"] = {} return redacted_event -def hash_and_sign_event(event_object): +def hash_and_sign_event( + event_object: dict, + room_ver: int = 1, +): content_hash = event_hash(event_object) event_object["hashes"] = {"sha256": content_hash} - stripped_object = redact_event(event_object) + stripped_object = redact_event(event_object, room_ver) signed_object = sign_json(stripped_object) event_object["signatures"] = signed_object["signatures"] return event_object @@ -244,7 +284,11 @@ def make_ref_hash( event: dict, room_ver: int = 3, ): - stripped = redact_event(event, True) + stripped = redact_event( + event=event, + for_event_id=True, + room_ver=room_ver, + ) evt_bytes = canonical_json(stripped) evt_hash = base64.b64encode( diff --git a/vona/utils/joinroom.py b/vona/utils/joinroom.py index 0f7dd00..7c43cb1 100644 --- a/vona/utils/joinroom.py +++ b/vona/utils/joinroom.py @@ -98,7 +98,10 @@ try: except ValueError: join_event["origin_server_ts"] = int(f"{time.time() * 1000}".split(".")[0]) -signed_join = globals.hash_and_sign_event(join_event) +signed_join = globals.hash_and_sign_event( + join_event, + int(make_join.get("room_version", "1")) +) try: send_join_response = http_client.put(