Implement redaction for v1 to v11 events

This commit is contained in:
2025-10-26 22:38:22 -04:00
parent 17d5a6458e
commit da82f492e8
4 changed files with 63 additions and 16 deletions

View File

@@ -174,7 +174,7 @@ async def make_join(room, user):
return jsonify({ return jsonify({
"event": globals.hash_and_sign_event(join), "event": globals.hash_and_sign_event(join, int(room_ver)),
"room_version": room_ver "room_version": room_ver
}) })

View File

@@ -223,12 +223,12 @@ def v3(request, room) -> dict:
del event["signatures"] del event["signatures"]
# m.room.create doesn't have prev_events or auth_events # 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) 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"]["auth_events"] = [hash_map["m.room.create"]]
events["m.room.member"]["prev_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) hash_map["m.room.member"] = globals.make_ref_hash(events["m.room.member"], ver)
events["m.room.power_levels"]["auth_events"] = [ 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"]] events["m.room.power_levels"]["prev_events"] = [hash_map["m.room.member"]]
if ver == 10: if ver == 10:
events["m.room.power_levels"]["content"]["users"][f"@vona:{config.server_name}"] = 100 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) hash_map["m.room.power_levels"] = globals.make_ref_hash(events["m.room.power_levels"], ver)
events["m.room.join_rules"]["auth_events"] = [ events["m.room.join_rules"]["auth_events"] = [
@@ -247,7 +247,7 @@ def v3(request, room) -> dict:
hash_map["m.room.power_levels"], hash_map["m.room.power_levels"],
] ]
events["m.room.join_rules"]["prev_events"] = [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) hash_map["m.room.join_rules"] = globals.make_ref_hash(events["m.room.join_rules"], ver)
events["m.room.guest_access"]["auth_events"] = [ events["m.room.guest_access"]["auth_events"] = [
@@ -256,7 +256,7 @@ def v3(request, room) -> dict:
hash_map["m.room.power_levels"], hash_map["m.room.power_levels"],
] ]
events["m.room.guest_access"]["prev_events"] = [hash_map["m.room.join_rules"]] 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) hash_map["m.room.guest_access"] = globals.make_ref_hash(events["m.room.guest_access"], ver)
events["m.room.history_visibility"]["auth_events"] = [ events["m.room.history_visibility"]["auth_events"] = [
@@ -265,7 +265,7 @@ def v3(request, room) -> dict:
hash_map["m.room.power_levels"], hash_map["m.room.power_levels"],
] ]
events["m.room.history_visibility"]["prev_events"] = [hash_map["m.room.guest_access"]] 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 = [] new_state = []

View File

@@ -8,6 +8,7 @@ import base64
import random import random
import httpx import httpx
import json import json
import copy
import re import re
version = "1.5.0" version = "1.5.0"
@@ -171,9 +172,10 @@ def make_auth_header(
def redact_event( def redact_event(
event: dict, event: dict,
for_event_id: bool = False, for_event_id: bool = False,
room_ver: int = 1,
): ):
# Returns a redacted event as per # Returns a redacted event as per
# the algorithm for v1/v2 rooms. # the algorithm for v1 to v11 rooms.
allowed_keys = [ allowed_keys = [
"event_id", "event_id",
@@ -185,16 +187,18 @@ def redact_event(
"hashes", "hashes",
"depth", "depth",
"prev_events", "prev_events",
"prev_state",
"auth_events", "auth_events",
"origin",
"origin_server_ts", "origin_server_ts",
"membership",
] ]
if not for_event_id: if not for_event_id:
allowed_keys.append("signatures") 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} 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: if "type" in redacted_event and "content" in redacted_event:
@@ -218,23 +222,59 @@ def redact_event(
"m.room.history_visibility": ["history_visibility"], "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: if event_type in content_key_rules:
allowed_content_keys = content_key_rules[event_type] 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"] = { redacted_event["content"] = {
k: v k: v
for k, v in redacted_event["content"].items() for k, v in redacted_event["content"].items()
if k in allowed_content_keys if k in allowed_content_keys
} }
if third_party_invite_signature:
redacted_event["content"]["third_party_invite"] = {
"signed": third_party_invite_signature
}
else:
if room_ver >= 11 and event_type == "m.room.create":
pass
else: else:
redacted_event["content"] = {} redacted_event["content"] = {}
return redacted_event 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) content_hash = event_hash(event_object)
event_object["hashes"] = {"sha256": content_hash} 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) signed_object = sign_json(stripped_object)
event_object["signatures"] = signed_object["signatures"] event_object["signatures"] = signed_object["signatures"]
return event_object return event_object
@@ -244,7 +284,11 @@ def make_ref_hash(
event: dict, event: dict,
room_ver: int = 3, 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_bytes = canonical_json(stripped)
evt_hash = base64.b64encode( evt_hash = base64.b64encode(

View File

@@ -98,7 +98,10 @@ try:
except ValueError: except ValueError:
join_event["origin_server_ts"] = int(f"{time.time() * 1000}".split(".")[0]) 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: try:
send_join_response = http_client.put( send_join_response = http_client.put(