Fix JMAP: Thread/get did not filter by per-mailbox ACLs on shared accounts
This commit is contained in:
@@ -12,6 +12,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If
|
||||
|
||||
## Fixed
|
||||
- DAV: `acl-principal-prop-set` REPORT enforced the wrong privilege.
|
||||
- JMAP: `Thread/get` did not filter by per-mailbox ACLs on shared accounts.
|
||||
|
||||
|
||||
## [0.16.5] - 2026-05-11
|
||||
|
||||
@@ -47,11 +47,11 @@ impl DnsUpdater {
|
||||
core,
|
||||
updater: dns_update::DnsUpdater::new_rfc2136_tsig(
|
||||
match server.protocol {
|
||||
enums::IpProtocol::Udp => DnsAddress::Tcp(SocketAddr::new(
|
||||
enums::IpProtocol::Tcp => DnsAddress::Tcp(SocketAddr::new(
|
||||
server.host.into_inner(),
|
||||
server.port as u16,
|
||||
)),
|
||||
enums::IpProtocol::Tcp => DnsAddress::Udp(SocketAddr::new(
|
||||
enums::IpProtocol::Udp => DnsAddress::Udp(SocketAddr::new(
|
||||
server.host.into_inner(),
|
||||
server.port as u16,
|
||||
)),
|
||||
|
||||
@@ -247,7 +247,7 @@ impl RequestHandler for Server {
|
||||
set_account_id_if_missing(&mut req.account_id, access_token);
|
||||
access_token.assert_has_access(req.account_id, Collection::Email)?;
|
||||
|
||||
self.thread_get(*req).await?.into()
|
||||
self.thread_get(*req, access_token).await?.into()
|
||||
}
|
||||
GetRequestMethod::Identity(mut req) => {
|
||||
set_account_id_if_missing(&mut req.account_id, access_token);
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
use crate::changes::state::StateManager;
|
||||
use common::Server;
|
||||
use email::cache::MessageCacheFetch;
|
||||
use common::{Server, auth::AccessToken};
|
||||
use email::cache::{MessageCacheFetch, email::MessageCacheAccess};
|
||||
use jmap_proto::{
|
||||
method::get::{GetRequest, GetResponse},
|
||||
object::thread::{Thread, ThreadProperty, ThreadValue},
|
||||
@@ -21,12 +21,13 @@ use store::{
|
||||
write::SearchIndex,
|
||||
};
|
||||
use trc::AddContext;
|
||||
use types::{collection::SyncCollection, id::Id};
|
||||
use types::{acl::Acl, collection::SyncCollection, id::Id};
|
||||
|
||||
pub trait ThreadGet: Sync + Send {
|
||||
fn thread_get(
|
||||
&self,
|
||||
request: GetRequest<Thread>,
|
||||
access_token: &AccessToken,
|
||||
) -> impl Future<Output = trc::Result<GetResponse<Thread>>> + Send;
|
||||
}
|
||||
|
||||
@@ -34,17 +35,27 @@ impl ThreadGet for Server {
|
||||
async fn thread_get(
|
||||
&self,
|
||||
mut request: GetRequest<Thread>,
|
||||
access_token: &AccessToken,
|
||||
) -> trc::Result<GetResponse<Thread>> {
|
||||
let account_id = request.account_id.document_id();
|
||||
let mut thread_map: AHashMap<u32, RoaringBitmap> = AHashMap::with_capacity(32);
|
||||
let mut all_ids = RoaringBitmap::new();
|
||||
for item in &self
|
||||
let cache = self
|
||||
.get_cached_messages(account_id)
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
.emails
|
||||
.items
|
||||
{
|
||||
.caused_by(trc::location!())?;
|
||||
let shared_ids = if access_token.is_shared(account_id) {
|
||||
Some(cache.shared_messages(access_token, Acl::ReadItems))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut thread_map: AHashMap<u32, RoaringBitmap> = AHashMap::with_capacity(32);
|
||||
let mut all_ids = RoaringBitmap::new();
|
||||
for item in &cache.emails.items {
|
||||
if shared_ids
|
||||
.as_ref()
|
||||
.is_some_and(|ids| !ids.contains(item.document_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
thread_map
|
||||
.entry(item.thread_id)
|
||||
.or_default()
|
||||
|
||||
Reference in New Issue
Block a user