tuwunel_service/fetcher/
validate.rs1use ruma::{CanonicalJsonObject, RoomVersionId};
6use serde::de::IgnoredAny;
7use tuwunel_core::{Err, Result, err, implement, matrix::event::gen_event_id};
8
9use super::{Op, Opts};
10
11#[implement(super::Service)]
16#[tracing::instrument(name = "validate", level = "trace", skip_all)]
17pub(super) async fn validate(&self, opts: &Opts, bytes: &[u8]) -> Result {
18 if opts.check_conforms {
19 serde_json::from_slice::<IgnoredAny>(bytes)
20 .map_err(|e| err!(BadServerResponse("malformed federation response: {e}")))?;
21 }
22
23 let deep = opts.check_event_id || opts.check_hashes || opts.check_signature;
24 if matches!(opts.op, Op::Event | Op::AuthEvent) && deep {
25 self.verify_pdu(opts, bytes).await?;
26 }
27
28 Ok(())
29}
30
31#[implement(super::Service)]
32#[tracing::instrument(level = "trace", skip_all)]
33async fn verify_pdu(&self, opts: &Opts, bytes: &[u8]) -> Result {
34 let value: CanonicalJsonObject = serde_json::from_slice(bytes)
35 .map_err(|e| err!(BadServerResponse("PDU is not a canonical JSON object: {e}")))?;
36
37 let v11 = RoomVersionId::V11;
38 let room_version = opts.room_version.as_ref().unwrap_or(&v11);
39
40 if opts.check_event_id
41 && let Some(expected) = opts.event_id.as_ref()
42 {
43 let calculated = gen_event_id(&value, room_version)?;
44 if calculated != *expected {
45 return Err!(BadServerResponse("server returned the wrong event id"));
46 }
47 }
48
49 if opts.check_signature || opts.check_hashes {
50 self.services
51 .server_keys
52 .verify_event(&value, Some(room_version))
53 .await?;
54 }
55
56 Ok(())
57}