Registry testing - all tests passing
This commit is contained in:
47
crates/common/src/cache/directory.rs
vendored
47
crates/common/src/cache/directory.rs
vendored
@@ -4,9 +4,7 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{Server, auth::DomainCache};
|
||||
use crate::{Server, auth::DomainCache, ipc::BroadcastEvent};
|
||||
use registry::{
|
||||
schema::{
|
||||
prelude::{Object, ObjectType},
|
||||
@@ -17,21 +15,23 @@ use registry::{
|
||||
},
|
||||
types::{datetime::UTCDateTime, id::ObjectId, list::List},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use store::registry::write::{RegistryWrite, RegistryWriteResult};
|
||||
use trc::AddContext;
|
||||
use types::id::Id;
|
||||
|
||||
pub(crate) struct AccountWithId {
|
||||
pub struct AccountWithId {
|
||||
pub id: u32,
|
||||
pub account: Account,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub(crate) async fn synchronize_account(
|
||||
pub async fn synchronize_account(
|
||||
&self,
|
||||
account: directory::Account,
|
||||
) -> trc::Result<AccountWithId> {
|
||||
let (local, domain) = self.validate_address(&account.email).await?;
|
||||
|
||||
match self
|
||||
.account_id_from_parts(local, domain.id)
|
||||
.await
|
||||
@@ -159,6 +159,8 @@ impl Server {
|
||||
enabled: true,
|
||||
description: None,
|
||||
});
|
||||
|
||||
self.invalidate_local_negative_account_cache(local, alias_domain.id);
|
||||
}
|
||||
}
|
||||
let mut member_group_ids = Vec::with_capacity(account.groups.len());
|
||||
@@ -182,10 +184,13 @@ impl Server {
|
||||
member_group_ids: member_group_ids.into(),
|
||||
member_tenant_id: domain.id_tenant.map(Id::from),
|
||||
roles: UserRoles::User,
|
||||
credentials: List::from_iter([Credential::Password(PasswordCredential {
|
||||
secret: account.secret.unwrap_or_default(),
|
||||
..Default::default()
|
||||
})]),
|
||||
credentials: List::from_iter(account.secret.map(|secret| {
|
||||
Credential::Password(PasswordCredential {
|
||||
credential_id: 0u64.into(),
|
||||
secret,
|
||||
..Default::default()
|
||||
})
|
||||
})),
|
||||
..Default::default()
|
||||
}));
|
||||
|
||||
@@ -206,10 +211,16 @@ impl Server {
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
{
|
||||
RegistryWriteResult::Success(id) => Ok(AccountWithId {
|
||||
id: id.document_id(),
|
||||
account: account.into(),
|
||||
}),
|
||||
RegistryWriteResult::Success(id) => {
|
||||
self.invalidate_local_negative_account_cache(local, domain.id);
|
||||
self.cluster_broadcast(BroadcastEvent::CacheInvalidateNegative)
|
||||
.await;
|
||||
|
||||
Ok(AccountWithId {
|
||||
id: id.document_id(),
|
||||
account: account.into(),
|
||||
})
|
||||
}
|
||||
failure => Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.caused_by(trc::location!())
|
||||
@@ -220,7 +231,7 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn synchronize_group(&self, group: directory::Group) -> trc::Result<u32> {
|
||||
pub async fn synchronize_group(&self, group: directory::Group) -> trc::Result<u32> {
|
||||
let (local, domain) = self.validate_address(&group.email).await?;
|
||||
|
||||
match self
|
||||
@@ -313,6 +324,8 @@ impl Server {
|
||||
enabled: true,
|
||||
description: None,
|
||||
});
|
||||
|
||||
self.invalidate_local_negative_account_cache(local, alias_domain.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +357,11 @@ impl Server {
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
{
|
||||
RegistryWriteResult::Success(id) => Ok(id.document_id()),
|
||||
RegistryWriteResult::Success(id) => {
|
||||
self.invalidate_local_negative_account_cache(local, domain.id);
|
||||
|
||||
Ok(id.document_id())
|
||||
}
|
||||
failure => Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.caused_by(trc::location!())
|
||||
|
||||
9
crates/common/src/cache/invalidate.rs
vendored
9
crates/common/src/cache/invalidate.rs
vendored
@@ -6,7 +6,7 @@
|
||||
|
||||
use crate::{
|
||||
Server,
|
||||
auth::EmailCache,
|
||||
auth::{EmailAddressRef, EmailCache},
|
||||
ipc::{BroadcastEvent, CacheInvalidation},
|
||||
};
|
||||
use ahash::AHashSet;
|
||||
@@ -283,6 +283,13 @@ impl Server {
|
||||
self.inner.cache.emails_negative.clear();
|
||||
}
|
||||
|
||||
pub fn invalidate_local_negative_account_cache(&self, local_part: &str, domain_id: u32) {
|
||||
self.inner
|
||||
.cache
|
||||
.emails_negative
|
||||
.remove(&EmailAddressRef::new(local_part, domain_id));
|
||||
}
|
||||
|
||||
pub async fn invalidate_local_caches(&self, changes: &[CacheInvalidation]) {
|
||||
let cache = &self.inner.cache;
|
||||
|
||||
|
||||
@@ -103,13 +103,36 @@ impl Server {
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
// Obtain external directory, if configured
|
||||
let directory = self
|
||||
.get_directory_for_cached_domain(&domain)
|
||||
.filter(|directory| directory.can_lookup_recipients());
|
||||
if let Some(directory) = directory {
|
||||
let address = if local_part.as_ref() == local_part_orig {
|
||||
Cow::Borrowed(rcpt)
|
||||
} else {
|
||||
Cow::Owned(format!("{local_part}@{domain_part}"))
|
||||
};
|
||||
match directory.recipient(address.as_ref()).await? {
|
||||
Recipient::Account(account) => {
|
||||
self.synchronize_account(account).await?;
|
||||
return Ok(RcptResolution::Accept);
|
||||
}
|
||||
Recipient::Group(group) => {
|
||||
self.synchronize_group(group).await?;
|
||||
return Ok(RcptResolution::Accept);
|
||||
}
|
||||
Recipient::Invalid => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Try resolving address from registry
|
||||
if let Some(address_type) = self
|
||||
.rcpt_id_from_parts(local_part.as_ref(), domain.id)
|
||||
.await?
|
||||
{
|
||||
match address_type {
|
||||
EmailCache::Account(id) => {
|
||||
EmailCache::Account(id) if directory.is_none() => {
|
||||
if self.try_account(id).await?.is_some() {
|
||||
return if local_part.as_ref() == local_part_orig {
|
||||
Ok(RcptResolution::Accept)
|
||||
@@ -135,29 +158,7 @@ impl Server {
|
||||
.remove(&EmailAddressRef::new(local_part.as_ref(), domain.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain external directory, if configured
|
||||
if let Some(directory) = self
|
||||
.get_directory_for_cached_domain(&domain)
|
||||
.filter(|directory| directory.can_lookup_recipients())
|
||||
{
|
||||
let address = if local_part.as_ref() == local_part_orig {
|
||||
Cow::Borrowed(rcpt)
|
||||
} else {
|
||||
Cow::Owned(format!("{local_part}@{domain_part}"))
|
||||
};
|
||||
match directory.recipient(address.as_ref()).await? {
|
||||
Recipient::Account(account) => {
|
||||
self.synchronize_account(account).await?;
|
||||
return Ok(RcptResolution::Accept);
|
||||
}
|
||||
Recipient::Group(group) => {
|
||||
self.synchronize_group(group).await?;
|
||||
return Ok(RcptResolution::Accept);
|
||||
}
|
||||
Recipient::Invalid => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user