Skip to main content

tuwunel_core/matrix/event/
id.rs

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