From d2fab358688c8ee1321cbc5657bf08dfc15d22b1 Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Tue, 4 Jun 2024 19:54:21 -0700 Subject: [PATCH] implement more robust (not_)rooms filter for search The previous code only handled the rooms field, and ignored not_rooms. --- src/api/client_server/search.rs | 44 ++++++++++++++++++++------------- src/utils/filter.rs | 2 +- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/api/client_server/search.rs b/src/api/client_server/search.rs index 761f89b7..575e31db 100644 --- a/src/api/client_server/search.rs +++ b/src/api/client_server/search.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::{borrow::Cow, collections::BTreeMap}; use ruma::{ api::client::{ @@ -14,7 +14,11 @@ use ruma::{ uint, UInt, }; -use crate::{services, Ar, Error, Ra, Result}; +use crate::{ + services, + utils::filter::{AllowDenyList, CompiledRoomEventFilter}, + Ar, Error, Ra, Result, +}; /// # `POST /_matrix/client/r0/search` /// @@ -30,15 +34,28 @@ pub(crate) async fn search_events_route( let search_criteria = body.search_categories.room_events.as_ref().unwrap(); let filter = &search_criteria.filter; + let Ok(compiled_filter) = CompiledRoomEventFilter::try_from(filter) else { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "invalid 'filter' parameter", + )); + }; - let room_ids = filter.rooms.clone().unwrap_or_else(|| { - services() - .rooms - .state_cache - .rooms_joined(sender_user) - .filter_map(Result::ok) - .collect() - }); + let mut room_ids = vec![]; + if let AllowDenyList::Allow(allow_set) = &compiled_filter.rooms { + for &room_id in allow_set { + if services().rooms.state_cache.is_joined(sender_user, room_id)? { + room_ids.push(Cow::Borrowed(room_id)); + } + } + } else { + for result in services().rooms.state_cache.rooms_joined(sender_user) { + let room_id = result?; + if compiled_filter.rooms.allowed(&room_id) { + room_ids.push(Cow::Owned(room_id)); + } + } + } // Use limit or else 10, with maximum 100 let limit = filter @@ -51,13 +68,6 @@ pub(crate) async fn search_events_route( let mut searches = Vec::new(); for room_id in room_ids { - if !services().rooms.state_cache.is_joined(sender_user, &room_id)? { - return Err(Error::BadRequest( - ErrorKind::forbidden(), - "You don't have permission to view this room.", - )); - } - if let Some(search) = services() .rooms .search diff --git a/src/utils/filter.rs b/src/utils/filter.rs index 3f113d93..77c51368 100644 --- a/src/utils/filter.rs +++ b/src/utils/filter.rs @@ -182,7 +182,7 @@ pub(crate) struct CompiledRoomEventFilter<'a> { // AllowDenyList when none of the type patterns // include a wildcard. types: WildcardAllowDenyList, - rooms: AllowDenyList<'a, RoomId>, + pub(crate) rooms: AllowDenyList<'a, RoomId>, senders: AllowDenyList<'a, UserId>, url_filter: Option, }