Skip to main content

tuwunel_api/server/
event_auth.rs

1use std::{borrow::Borrow, iter::once};
2
3use axum::extract::State;
4use futures::StreamExt;
5use ruma::{
6	RoomId,
7	api::{error::ErrorKind, federation::authorization::get_event_authorization},
8};
9use tuwunel_core::{
10	Error, Result,
11	utils::stream::{BroadbandExt, ReadyExt},
12};
13
14use super::AccessCheck;
15use crate::Ruma;
16
17/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
18///
19/// Retrieves the auth chain for a given event.
20///
21/// - This does not include the event itself
22pub(crate) async fn get_event_authorization_route(
23	State(services): State<crate::State>,
24	body: Ruma<get_event_authorization::v1::Request>,
25) -> Result<get_event_authorization::v1::Response> {
26	AccessCheck {
27		services: &services,
28		origin: body.origin(),
29		room_id: &body.room_id,
30		event_id: None,
31	}
32	.check()
33	.await?;
34
35	let event = services
36		.timeline
37		.get_pdu_json(&body.event_id)
38		.await
39		.map_err(|_| Error::BadRequest(ErrorKind::NotFound, "Event not found."))?;
40
41	let room_id_str = event
42		.get("room_id")
43		.and_then(|val| val.as_str())
44		.ok_or_else(|| Error::bad_database("Invalid event in database."))?;
45
46	let room_id = <&RoomId>::try_from(room_id_str)
47		.map_err(|_| Error::bad_database("Invalid room_id in event in database."))?;
48
49	let room_version = services.state.get_room_version(room_id).await?;
50
51	let auth_chain = services
52		.auth_chain
53		.event_ids_iter(room_id, &room_version, once(body.event_id.borrow()))
54		.ready_filter_map(Result::ok)
55		.broad_filter_map(async |id| {
56			let pdu = services.timeline.get_pdu_json(&id).await.ok()?;
57
58			let pdu = services
59				.federation
60				.format_pdu_into(pdu, Some(&room_version))
61				.await;
62
63			Some(pdu)
64		})
65		.collect()
66		.await;
67
68	Ok(get_event_authorization::v1::Response { auth_chain })
69}