Settings hot reloading - Part 4

This commit is contained in:
mdecimus
2024-03-26 18:40:41 +01:00
parent d8af9b4576
commit 170ff38d1f
120 changed files with 2286 additions and 2594 deletions

View File

@@ -24,30 +24,33 @@
use std::time::{Duration, Instant};
use common::{
config::smtp::{session::Mechanism, *},
expr::{if_block::IfBlock, Expression},
config::smtp::*,
expr::{tokenizer::TokenMap, Expression},
Core,
};
use directory::core::config::ConfigDirectory;
use mail_auth::MX;
use smtp_proto::{AUTH_LOGIN, AUTH_PLAIN};
use store::Store;
use store::Stores;
use utils::config::Config;
use crate::{
directory::DirectoryStore,
smtp::{
build_smtp,
session::{TestSession, VerifyResponse},
ParseTestConfig, TestConfig,
TempDir,
},
store::TempDir,
};
use smtp::{
core::{Session, SMTP},
core::{Inner, Session},
queue::RecipientDomain,
};
const CONFIG: &str = r#"
[storage]
data = "sql"
blob = "sql"
fts = "sql"
lookup = "sql"
[store."sql"]
@@ -74,7 +77,39 @@ description = "description"
secret = "secret"
email = "address"
quota = "quota"
type = "type"
class = "type"
[session.auth]
directory = "'sql'"
mechanisms = "[plain, login]"
errors.wait = "5ms"
[session.rcpt]
directory = "'sql'"
relay = false
errors.wait = "5ms"
[session.extensions]
requiretls = [{if = "key_exists('sql/is_ip_allowed', remote_ip)", then = true},
{else = false}]
expn = true
vrfy = true
[test."sql"]
expr = "sql_query('sql', 'SELECT description FROM domains WHERE name = ?', 'foobar.org')"
expect = "Main domain"
[test."dns"]
expr = "dns_query(rcpt_domain, 'mx')[0]"
expect = "mx.foobar.org"
[test."key_get"]
expr = "key_get('sql', 'hello') + '-' + key_exists('sql', 'hello') + '-' + key_set('sql', 'hello', 'world') + '-' + key_get('sql', 'hello') + '-' + key_exists('sql', 'hello')"
expect = "0-0-1-world-1"
[test."counter_get"]
expr = "counter_get('sql', 'county') + '-' + counter_incr('sql', 'county', 1) + '-' + counter_incr('sql', 'county', 1) + '-' + counter_get('sql', 'county')"
expect = "0-1-2-2"
"#;
@@ -91,18 +126,13 @@ async fn lookup_sql() {
// Parse settings
let temp_dir = TempDir::new("smtp_lookup_tests", true);
let config_file = CONFIG.replace("{TMP}", &temp_dir.path.to_string_lossy());
let mut core = SMTP::test();
let mut ctx = ConfigContext::new();
let config = Config::new(&config_file).unwrap();
ctx.stores = config.parse_stores().await.unwrap();
core.core.storage.lookups = ctx.stores.lookups.clone();
core.core.storage.directories = config
.parse_directory(&ctx.stores, Store::default())
.await
.unwrap()
.directories;
core.core.smtp.resolvers.dns.mx_add(
let mut config = Config::new(temp_dir.update_config(CONFIG)).unwrap();
let stores = Stores::parse(&mut config).await;
let inner = Inner::default();
let core = Core::parse(&mut config, stores).await;
core.smtp.resolvers.dns.mx_add(
"test.org",
vec![MX {
exchanges: vec!["mx.foobar.org".to_string()],
@@ -113,7 +143,7 @@ async fn lookup_sql() {
// Obtain directory handle
let handle = DirectoryStore {
store: ctx.stores.lookups.get("sql").unwrap().clone(),
store: core.storage.lookups.get("sql").unwrap().clone(),
};
// Create tables
@@ -160,76 +190,33 @@ async fn lookup_sql() {
}
// Test expression functions
for (expr, expected) in [
(
"sql_query('sql', 'SELECT description FROM domains WHERE name = ?', 'foobar.org')",
"Main domain",
),
("dns_query(rcpt_domain, 'mx')[0]", "mx.foobar.org"),
(
concat!(
"key_get('sql', 'hello') + '-' + key_exists('sql', 'hello') + '-' + ",
"key_set('sql', 'hello', 'world') + '-' + key_get('sql', 'hello') + ",
"'-' + key_exists('sql', 'hello')"
),
"0-0-1-world-1",
),
(
concat!(
"counter_get('sql', 'county') + '-' + counter_incr('sql', 'county', 1) + '-' ",
"+ counter_incr('sql', 'county', 1) + '-' + counter_get('sql', 'county')"
),
"0-1-2-2",
),
] {
let e = Expression::parse("test", expr, |name| {
map_expr_token::<Duration>(
name,
&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,
V_SENDER_DOMAIN,
V_MX,
V_HELO_DOMAIN,
V_AUTHENTICATED_AS,
V_LISTENER,
V_REMOTE_IP,
V_LOCAL_IP,
V_PRIORITY,
],
)
})
.unwrap();
let token_map = TokenMap::default().with_smtp_variables(&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,
V_SENDER_DOMAIN,
V_MX,
V_HELO_DOMAIN,
V_AUTHENTICATED_AS,
V_LISTENER,
V_REMOTE_IP,
V_LOCAL_IP,
V_PRIORITY,
]);
for test_name in ["sql", "dns", "key_get", "counter_get"] {
let e =
Expression::try_parse(&mut config, ("test", test_name, "expr"), &token_map).unwrap();
assert_eq!(
core.core
.eval_expr::<String, _>(&e, &RecipientDomain::new("test.org"), "text")
core.eval_expr::<String, _>(&e, &RecipientDomain::new("test.org"), "text")
.await
.unwrap(),
expected,
config.value(("test", test_name, "expect")).unwrap(),
"failed for '{}'",
expr
test_name
);
}
// Enable AUTH
let config = &mut core.core.smtp.session.auth;
config.directory = "\"'sql'\"".parse_if();
config.mechanisms = IfBlock::new(Mechanism::from(AUTH_PLAIN | AUTH_LOGIN));
config.errors_wait = IfBlock::new(Duration::from_millis(5));
// Enable VRFY/EXPN/RCPT
let config = &mut core.core.smtp.session.rcpt;
config.directory = "\"'sql'\"".parse_if();
config.relay = IfBlock::new(false);
config.errors_wait = IfBlock::new(Duration::from_millis(5));
// Enable REQUIRETLS based on SQL lookup
core.core.smtp.session.extensions.requiretls =
r#"[{if = "key_exists('sql/is_ip_allowed', remote_ip)", then = true},
{else = false}]"#
.parse_if();
let mut session = Session::test(core);
let mut session = Session::test(build_smtp(core, inner));
session.data.remote_ip_str = "10.0.0.50".parse().unwrap();
session.eval_session_params().await;
session.stream.tls = true;