Skip to main content

arminius_lib_events/
event_id.rs

1// SPDX-FileCopyrightText: 2025 BWI GmbH
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Event ID derivation from federation PDUs.
6
7#[cfg(test)]
8mod tests;
9
10use ruma::{
11	CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId,
12	room_version_rules::EventIdFormatVersion,
13};
14
15use crate::{KnownRoomVersionId, errors::EventIdGenerationError};
16
17/// Resolves the event ID for a federation PDU.
18///
19/// Room versions 1 and 2 carry the event ID in the PDU. Later room versions
20/// derive it from the event's reference hash.
21///
22/// See Matrix Specification v1.19, Server-Server API:
23/// <https://spec.matrix.org/v1.19/server-server-api/#calculating-the-reference-hash-for-an-event>.
24///
25/// ## Errors
26///
27/// Returns [`EventIdGenerationError`] if the embedded event ID is missing or
28/// invalid, the PDU is not canonical JSON, or reference hash generation fails.
29pub fn event_id_from_pdu(
30	pdu: &serde_json::value::RawValue,
31	room_version: KnownRoomVersionId,
32) -> Result<OwnedEventId, EventIdGenerationError> {
33	let rules = room_version.rules();
34	let canonical_pdu = serde_json::from_str::<CanonicalJsonObject>(pdu.get())
35		.map_err(|error| EventIdGenerationError::InvalidEvent(error.to_string()))?;
36	match rules.event_id_format {
37		EventIdFormatVersion::V1 => {
38			let Some(CanonicalJsonValue::String(event_id)) = canonical_pdu.get("event_id") else {
39				return Err(EventIdGenerationError::InvalidEvent(
40					"Missing or invalid event_id".to_owned(),
41				));
42			};
43			EventId::parse(event_id)
44				.map_err(|error| EventIdGenerationError::InvalidEvent(error.to_string()))
45		}
46		EventIdFormatVersion::V2 | EventIdFormatVersion::V3 => {
47			let reference_hash = ruma::signatures::reference_hash(&canonical_pdu, &rules)
48				.map_err(|error| EventIdGenerationError::InvalidEvent(error.to_string()))?;
49			EventId::new_v2_or_v3(&reference_hash)
50				.map_err(|error| EventIdGenerationError::InvalidEvent(error.to_string()))
51		}
52		_ => Err(EventIdGenerationError::InvalidEvent("Unsupported event ID format".to_owned())),
53	}
54}