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