Fix ACL: Orphaned ACL entries for deleted accounts cause JMAP session errors

This commit is contained in:
Maurus Decimus
2026-05-19 20:06:09 +02:00
parent 897d3c282c
commit 83a1543483
3 changed files with 47 additions and 23 deletions

View File

@@ -23,7 +23,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If
- DNS updater:
- Skip `v=spf1 a -all` records for apex domains.
- RFC2136 TSIG: regression related to multiplexer.
- Rout53: Chunk `TXT` records when they exceed 255 characters.
- Route53: Chunk `TXT` records when they exceed 255 characters.
- ACME:
- Update `defaultCertificateId` when renewing a certificate that is currently set as default.
- Perform `DNS-01` authorizations sequentially to avoid race conditions in some DNS providers.
@@ -31,6 +31,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If
- Websocket: Perform case insensitive matching during upgrade.
- LDAP: Synchronize accounts when expanding mailing list recipients.
- Sieve: `replace` action adds an extra `From` header.
- ACL: Orphaned ACL entries for deleted accounts cause JMAP session errors.
## [0.16.5] - 2026-05-11

View File

@@ -60,7 +60,18 @@ impl SessionHandler for Server {
// Add secondary accounts
for &account_id in access_token.secondary_ids() {
let is_owner = access_token.is_member(account_id);
let account = self.account(account_id).await.caused_by(trc::location!())?;
let Some(account) = self
.try_account(account_id)
.await
.caused_by(trc::location!())?
else {
trc::event!(
Auth(trc::AuthEvent::Warning),
AccountId = account_id,
Reason = "Skipping orphan secondary account id in session",
);
continue;
};
let account_id = Id::from(account_id);
let mut account = Account {

View File

@@ -357,27 +357,39 @@ impl Store {
.caused_by(trc::location!())?;
}
for (from_class, to_class) in [
(ValueClass::Acl(account_id), ValueClass::Acl(account_id + 1)),
(ValueClass::Property(0), ValueClass::Property(0)),
] {
self.delete_range(
ValueKey {
account_id,
collection: 0,
document_id: 0,
class: from_class,
},
ValueKey {
account_id: account_id + 1,
collection: 0,
document_id: 0,
class: to_class,
},
)
.await
.caused_by(trc::location!())?;
}
self.delete_range(
ValueKey {
account_id: 0,
collection: 0,
document_id: 0,
class: ValueClass::Acl(account_id),
},
ValueKey {
account_id: 0,
collection: 0,
document_id: 0,
class: ValueClass::Acl(account_id + 1),
},
)
.await
.caused_by(trc::location!())?;
self.delete_range(
ValueKey {
account_id,
collection: 0,
document_id: 0,
class: ValueClass::Property(0),
},
ValueKey {
account_id: account_id + 1,
collection: 0,
document_id: 0,
class: ValueClass::Property(0),
},
)
.await
.caused_by(trc::location!())?;
Ok(())
}