From 7a0b8c986fa9ec5a3bbf9c80b9270ce618672e0b Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Tue, 21 May 2024 14:04:53 -0700 Subject: [PATCH] implement global account_data filtering in /sync TODO docs on raw_event_allowed, and figure out how we want to organize it with CompiledRoomEventFilter::raw_event_allowed --- src/api/client_server/sync.rs | 3 +++ src/utils/filter.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 1f5acdde..3aea0a2b 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -346,6 +346,9 @@ pub(crate) async fn sync_events_route( }) .ok() }) + .filter(|event| { + compiled_filter.account_data.raw_event_allowed(event) + }) .collect(), }, device_lists: DeviceLists { diff --git a/src/utils/filter.rs b/src/utils/filter.rs index aeb460d7..1947df98 100644 --- a/src/utils/filter.rs +++ b/src/utils/filter.rs @@ -160,6 +160,7 @@ impl WildcardAllowDenyList { /// `types`/`not_types`, this is a [`WildcardAllowDenyList`], because the type /// filter fields support `'*'` wildcards. pub(crate) struct CompiledFilterDefinition<'a> { + pub(crate) account_data: CompiledFilter<'a>, pub(crate) room: CompiledRoomFilter<'a>, } @@ -188,6 +189,7 @@ impl<'a> TryFrom<&'a FilterDefinition> for CompiledFilterDefinition<'a> { source: &'a FilterDefinition, ) -> Result, Error> { Ok(CompiledFilterDefinition { + account_data: (&source.account_data).try_into()?, room: (&source.room).try_into()?, }) } @@ -238,6 +240,38 @@ impl<'a> TryFrom<&'a RoomEventFilter> for CompiledRoomEventFilter<'a> { } } +impl CompiledFilter<'_> { + // TODO: docs + pub(crate) fn raw_event_allowed(&self, event: &Raw) -> bool { + // We need to deserialize some of the fields from the raw json, but + // don't need all of them. Fully deserializing to a ruma event type + // would involve a lot extra copying and validation. + #[derive(Deserialize)] + struct LimitedEvent<'a> { + sender: Option, + #[serde(rename = "type")] + kind: Cow<'a, str>, + } + + let event = match event.deserialize_as::>() { + Ok(event) => event, + Err(e) => { + // TODO: maybe rephrase this error, or propagate it to the + // caller + error!("invalid event in database: {e}"); + return false; + } + }; + + let sender_allowed = match &event.sender { + Some(sender) => self.senders.allowed(sender), + // sender allowlist means we reject events without a sender + None => matches!(self.senders, AllowDenyList::Deny(_)), + }; + sender_allowed && self.types.allowed(&event.kind) + } +} + impl CompiledRoomFilter<'_> { /// Returns the top-level [`AllowDenyList`] for rooms (`rooms`/`not_rooms` /// in `filter.room`).