Skip to main content

tuwunel_matrix/event/
id.rs

1use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId};
2use serde_json::value::RawValue as RawJsonValue;
3use tuwunel_core::{Result, debug_error, err};
4
5use crate::room_version;
6
7/// Generates a correct eventId for the incoming pdu.
8///
9/// Returns a tuple of the new `EventId` and the PDU as a `BTreeMap<String,
10/// CanonicalJsonValue>`.
11#[tracing::instrument(
12	name = "gen_event_id",
13	level = "debug",
14	skip_all,
15	fields(
16		len = pdu.get().len(),
17	)
18)]
19pub fn gen_event_id_canonical_json(
20	pdu: &RawJsonValue,
21	room_version_id: &RoomVersionId,
22) -> Result<(OwnedEventId, CanonicalJsonObject)> {
23	let value: CanonicalJsonObject = serde_json::from_str(pdu.get())
24		.map_err(|e| err!(BadServerResponse(warn!("Error parsing canonical event: {e}"))))
25		.inspect_err(|e| debug_error!("{pdu:#?} {e:?}"))?;
26
27	let event_id = gen_event_id(&value, room_version_id)?;
28
29	Ok((event_id, value))
30}
31
32/// Generates a correct eventId for the PDU. For v1/v2 incoming PDU's the
33/// value's event_id is passed through. For all outgoing PDU's and for v3+
34/// incoming PDU's it is generated.
35#[tracing::instrument(
36	level = "debug",
37	skip_all,
38	fields(
39		members = value.len(),
40		room_version = ?room_version_id,
41	)
42)]
43pub fn gen_event_id(
44	value: &CanonicalJsonObject,
45	room_version_id: &RoomVersionId,
46) -> Result<OwnedEventId> {
47	let room_version_rules = room_version::rules(room_version_id)?;
48	let require_event_id = room_version_rules.event_format.require_event_id;
49
50	// We don't actually generate any event_id for incoming events in v1/v2 rooms,
51	// just pass them through.
52	if let Some(event_id) = require_event_id
53		.then(|| value.get("event_id"))
54		.flatten()
55		.and_then(CanonicalJsonValue::as_str)
56		.map(OwnedEventId::try_from)
57		.transpose()?
58	{
59		return Ok(event_id);
60	}
61
62	// For outgoing v1/v2 add the server part. This has to be our origin but we
63	// can't assert that here.
64	let server_name = require_event_id
65		.then(|| value.get("origin"))
66		.flatten()
67		.and_then(CanonicalJsonValue::as_str);
68
69	let reference_hash = ruma::signatures::reference_hash(value, &room_version_rules)?;
70
71	OwnedEventId::from_parts('$', &reference_hash, server_name).map_err(Into::into)
72}