diff --git a/crates/features/src/security/tenant_protocol_policy.rs b/crates/features/src/security/tenant_protocol_policy.rs index 4bdd93d..81e72d9 100644 --- a/crates/features/src/security/tenant_protocol_policy.rs +++ b/crates/features/src/security/tenant_protocol_policy.rs @@ -93,6 +93,17 @@ pub async fn set(data: &Store, tenant_id: u32, policy: &TenantProtocolPolicy) -> .map(|_| ()) } +/// Forgets a tenant's switch, when the tenant is deleted. Otherwise a tenant +/// that came to have the same id would start with the old one's switch. +pub async fn remove(data: &Store, tenant_id: u32) -> trc::Result<()> { + let mut batch = BatchBuilder::new(); + batch.clear(key(tenant_id)); + data.write(batch.build_all()) + .await + .caused_by(trc::location!()) + .map(|_| ()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/jmap/src/registry/set.rs b/crates/jmap/src/registry/set.rs index a7f59ab..d7a1634 100644 --- a/crates/jmap/src/registry/set.rs +++ b/crates/jmap/src/registry/set.rs @@ -851,6 +851,14 @@ impl RegistrySet for Server { if let ObjectInner::MaskedEmail(mask) = &object.inner { crate::inbuxa::masked_email::destroyed(self, id, mask).await?; } + // inbuxa: legacy-protocols, a tenant's switch goes with it + if matches!(object.inner, ObjectInner::Tenant(_)) { + inbuxa_features::security::tenant_protocol_policy::remove( + &self.core.storage.data, + id.document_id(), + ) + .await?; + } cache_invalidator.process_delete(id, &object); set.response.destroyed.push(id); } diff --git a/tests/e2e/legacy_protocols.py b/tests/e2e/legacy_protocols.py index 27fd509..a27706f 100755 --- a/tests/e2e/legacy_protocols.py +++ b/tests/e2e/legacy_protocols.py @@ -380,6 +380,24 @@ def tenant_checks(admin, admin_pw, account): "and its user signs in over IMAP again") check(session_flag(tu, user_pw) == "enabled", "and its session says enabled again (test 13)") + # A deleted tenant's switch goes with it, so a tenant that later gets the + # same id doesn't start with legacy protocols off. + sget = lambda ids: one(admin, admin_pw, "inbuxa:TenantProtocolPolicy/get", + {"accountId": account, "ids": ids}) + one(admin, admin_pw, "inbuxa:TenantProtocolPolicy/set", + {"accountId": account, "update": {t2: {"legacyProtocols": "disabled"}}}) + check(sget([t2])[1]["list"][0]["legacyProtocols"] == "disabled", + "a server admin turns another tenant's switch off") + res = one(admin, admin_pw, "x:Tenant/set", {"destroy": [t2]}) + check(t2 in (res[1].get("destroyed") or []), "that tenant can be deleted") + t3 = created(one(admin, admin_pw, "x:Tenant/set", {"create": {"t": {"name": "legacy-t3"}}}), + "t", "third tenant") + if t3 == t2: + check(sget([t3])[1]["list"][0]["legacyProtocols"] == "enabled", + "a new tenant with the deleted one's id starts with legacy protocols on") + else: + print(f" (the registry gave the new tenant a fresh id, {t3} not {t2}: reuse not observable)") + def session_flag(user, password): """legacyProtocols from the account's urn:inbuxa:jmap capability."""