Directory refactoring

This commit is contained in:
mdecimus
2023-12-14 12:35:25 +01:00
parent b7869901ee
commit f21bce722e
112 changed files with 2300 additions and 1823 deletions

View File

@@ -22,12 +22,12 @@
*/
use ahash::AHashMap;
use directory::{Principal, Type};
use directory::{backend::internal::manage::ManageDirectory, Principal, QueryBy, Type};
use mail_send::Credentials;
use smtp::core::Lookup;
use store::{LookupStore, Store};
use crate::directory::parse_config;
use crate::directory::{map_account_ids, parse_config};
use super::DirectoryStore;
@@ -57,6 +57,7 @@ async fn sql_directory() {
let store = DirectoryStore {
store: config.stores.lookup_stores.remove(directory_id).unwrap(),
};
let base_store = config.stores.stores.get(directory_id).unwrap();
// Create tables
store.create_test_directory().await;
@@ -132,32 +133,45 @@ async fn sql_directory() {
// Test authentication
assert_eq!(
handle
.authenticate(&Credentials::Plain {
username: "john".to_string(),
secret: "12345".to_string()
})
.query(
QueryBy::credentials(&Credentials::Plain {
username: "john".to_string(),
secret: "12345".to_string()
})
.with_store(base_store)
)
.await
.unwrap()
.unwrap(),
Principal {
id: base_store.get_account_id("john").await.unwrap().unwrap(),
name: "john".to_string(),
description: "John Doe".to_string().into(),
secrets: vec!["12345".to_string()],
typ: Type::Individual,
member_of: vec!["sales".to_string()],
member_of: map_account_ids(base_store, vec!["sales"]).await,
emails: vec![
"john@example.org".to_string(),
"jdoe@example.org".to_string(),
"john.doe@example.org".to_string()
],
..Default::default()
}
);
assert_eq!(
handle
.authenticate(&Credentials::Plain {
username: "bill".to_string(),
secret: "password".to_string()
})
.query(
QueryBy::credentials(&Credentials::Plain {
username: "bill".to_string(),
secret: "password".to_string()
})
.with_store(base_store)
)
.await
.unwrap()
.unwrap(),
Principal {
id: base_store.get_account_id("bill").await.unwrap().unwrap(),
name: "bill".to_string(),
description: "Bill Foobar".to_string().into(),
secrets: vec![
@@ -165,35 +179,50 @@ async fn sql_directory() {
],
typ: Type::Individual,
quota: 500000,
emails: vec!["bill@example.org".to_string(),],
..Default::default()
}
);
assert!(handle
.authenticate(&Credentials::Plain {
username: "bill".to_string(),
secret: "invalid".to_string()
})
.query(
QueryBy::credentials(&Credentials::Plain {
username: "bill".to_string(),
secret: "invalid".to_string()
})
.with_store(base_store)
)
.await
.unwrap()
.is_none());
// Get user by name
assert_eq!(
handle.principal("jane").await.unwrap().unwrap(),
handle
.query(QueryBy::name("jane").with_store(base_store))
.await
.unwrap()
.unwrap(),
Principal {
id: base_store.get_account_id("jane").await.unwrap().unwrap(),
name: "jane".to_string(),
description: "Jane Doe".to_string().into(),
typ: Type::Individual,
secrets: vec!["abcde".to_string()],
member_of: vec!["sales".to_string(), "support".to_string()],
member_of: map_account_ids(base_store, vec!["sales", "support"]).await,
emails: vec!["jane@example.org".to_string(),],
..Default::default()
}
);
// Get group by name
assert_eq!(
handle.principal("sales").await.unwrap().unwrap(),
handle
.query(QueryBy::name("sales").with_store(base_store))
.await
.unwrap()
.unwrap(),
Principal {
id: base_store.get_account_id("sales").await.unwrap().unwrap(),
name: "sales".to_string(),
description: "Sales Team".to_string().into(),
typ: Type::Group,
@@ -201,53 +230,48 @@ async fn sql_directory() {
}
);
// Emails by id
assert_eq!(
handle.emails_by_name("john").await.unwrap(),
vec![
"john@example.org".to_string(),
"jdoe@example.org".to_string(),
"john.doe@example.org".to_string(),
]
);
assert_eq!(
handle.emails_by_name("bill").await.unwrap(),
vec!["bill@example.org".to_string(),]
);
// Ids by email
assert_eq!(
handle.names_by_email("jane@example.org").await.unwrap(),
vec!["jane".to_string()]
);
assert_eq!(
handle.names_by_email("info@example.org").await.unwrap(),
vec!["bill".to_string(), "jane".to_string(), "john".to_string()]
handle
.email_to_ids("jane@example.org", base_store)
.await
.unwrap(),
map_account_ids(base_store, vec!["jane"]).await
);
assert_eq!(
handle
.names_by_email("jane+alias@example.org")
.email_to_ids("info@example.org", base_store)
.await
.unwrap(),
vec!["jane".to_string()]
map_account_ids(base_store, vec!["bill", "jane", "john"]).await
);
assert_eq!(
handle
.names_by_email("info+alias@example.org")
.email_to_ids("jane+alias@example.org", base_store)
.await
.unwrap(),
vec!["bill".to_string(), "jane".to_string(), "john".to_string()]
);
assert_eq!(
handle.names_by_email("unknown@example.org").await.unwrap(),
Vec::<String>::new()
map_account_ids(base_store, vec!["jane"]).await
);
assert_eq!(
handle
.names_by_email("anything@catchall.org")
.email_to_ids("info+alias@example.org", base_store)
.await
.unwrap(),
vec!["robert".to_string()]
map_account_ids(base_store, vec!["bill", "jane", "john"]).await
);
assert_eq!(
handle
.email_to_ids("unknown@example.org", base_store)
.await
.unwrap(),
Vec::<u32>::new()
);
assert_eq!(
handle
.email_to_ids("anything@catchall.org", base_store)
.await
.unwrap(),
map_account_ids(base_store, vec!["robert"]).await
);
// Domain validation
@@ -317,7 +341,7 @@ impl DirectoryStore {
"CREATE TABLE emails (name TEXT NOT NULL, address TEXT NOT",
" NULL, type TEXT, PRIMARY KEY (name, address))"
),
"INSERT INTO accounts (name, secret, type) VALUES ('admin', 'secret', 'individual')",
"INSERT INTO accounts (name, secret, type) VALUES ('admin', 'secret', 'admin')",
] {
let query = if matches!(self.store, LookupStore::Store(Store::MySQL(_))) {
query.replace("TEXT", "VARCHAR(255)")
@@ -333,25 +357,35 @@ impl DirectoryStore {
}
pub async fn create_test_user(&self, login: &str, secret: &str, name: &str) {
let account_type = if login == "admin" {
"admin"
} else {
"individual"
};
self.store
.query::<usize>(
if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) {
concat!(
"INSERT INTO accounts (name, secret, description, ",
"type, active) VALUES ($1, $2, $3, 'individual', true) ON CONFLICT (name) DO NOTHING"
"type, active) VALUES ($1, $2, $3, $4, true) ON CONFLICT (name) DO NOTHING"
)
} else if matches!(self.store, LookupStore::Store(Store::MySQL(_))) {
concat!(
"INSERT IGNORE INTO accounts (name, secret, description, ",
"type, active) VALUES (?, ?, ?, 'individual', true)"
"type, active) VALUES (?, ?, ?, ?, true)"
)
} else {
concat!(
"INSERT OR IGNORE INTO accounts (name, secret, description, ",
"type, active) VALUES (?, ?, ?, 'individual', true)"
"type, active) VALUES (?, ?, ?, ?, true)"
)
},
vec![login.into(), secret.into(), name.into()],
vec![
login.into(),
secret.into(),
name.into(),
account_type.into(),
],
)
.await
.unwrap();