Skip to main content

tuwunel_core/matrix/pdu/
format.rs

1pub(super) mod check;
2
3use ruma::{
4	CanonicalJsonObject, CanonicalJsonValue, EventId, RoomId, RoomVersionId,
5	room_version_rules::{EventsReferenceFormatVersion, RoomVersionRules},
6};
7
8use crate::{extract_variant, is_equal_to, matrix::room_version};
9
10#[must_use]
11pub fn into_outgoing_federation(
12	mut pdu_json: CanonicalJsonObject,
13	room_version: &RoomVersionId,
14) -> CanonicalJsonObject {
15	if let Some(unsigned) = pdu_json
16		.get_mut("unsigned")
17		.and_then(|val| val.as_object_mut())
18	{
19		unsigned.remove("transaction_id");
20	}
21
22	let Ok(room_rules) = room_version::rules(room_version) else {
23		pdu_json.remove("event_id");
24		return pdu_json;
25	};
26
27	if !room_rules.event_format.require_event_id {
28		pdu_json.remove("event_id");
29	}
30
31	if !room_rules
32		.event_format
33		.require_room_create_room_id
34		&& pdu_json
35			.get("type")
36			.and_then(CanonicalJsonValue::as_str)
37			.is_some_and(is_equal_to!("m.room.create"))
38	{
39		pdu_json.remove("room_id");
40	}
41
42	if matches!(room_rules.events_reference_format, EventsReferenceFormatVersion::V1) {
43		if let Some(value) = pdu_json.get_mut("auth_events") {
44			mutate_outgoing_reference_format(value);
45		}
46		if let Some(value) = pdu_json.get_mut("prev_events") {
47			mutate_outgoing_reference_format(value);
48		}
49	}
50
51	pdu_json
52}
53
54fn mutate_outgoing_reference_format(value: &mut CanonicalJsonValue) {
55	value
56		.as_array_mut()
57		.into_iter()
58		.flatten()
59		.for_each(|value| {
60			if let Some(event_id) = value.as_str().map(ToOwned::to_owned) {
61				*value = CanonicalJsonValue::Array(vec![
62					CanonicalJsonValue::String(event_id),
63					CanonicalJsonValue::Object([(Default::default(), "".into())].into()),
64				]);
65			}
66		});
67}
68
69#[must_use]
70pub fn from_incoming_federation(
71	room_id: &RoomId,
72	event_id: &EventId,
73	mut pdu_json: CanonicalJsonObject,
74	room_rules: &RoomVersionRules,
75) -> CanonicalJsonObject {
76	if matches!(room_rules.events_reference_format, EventsReferenceFormatVersion::V1) {
77		if let Some(value) = pdu_json.get_mut("auth_events") {
78			mutate_incoming_reference_format(value);
79		}
80		if let Some(value) = pdu_json.get_mut("prev_events") {
81			mutate_incoming_reference_format(value);
82		}
83	}
84
85	if !room_rules
86		.event_format
87		.require_room_create_room_id
88		&& pdu_json["type"] == "m.room.create"
89	{
90		pdu_json.insert("room_id".into(), CanonicalJsonValue::String(room_id.as_str().into()));
91	}
92
93	if !room_rules.event_format.require_event_id {
94		pdu_json.insert("event_id".into(), CanonicalJsonValue::String(event_id.into()));
95	}
96
97	pdu_json
98}
99
100fn mutate_incoming_reference_format(value: &mut CanonicalJsonValue) {
101	value
102		.as_array_mut()
103		.into_iter()
104		.flat_map(|vec| vec.iter_mut())
105		.for_each(|value| {
106			let event_id = value
107				.as_array()
108				.into_iter()
109				.find_map(|vec| vec.first())
110				.and_then(|val| extract_variant!(val, CanonicalJsonValue::String))
111				.cloned()
112				.unwrap_or_default();
113
114			*value = CanonicalJsonValue::String(event_id);
115		});
116}