Use safe defaults when settings are missing

This commit is contained in:
mdecimus
2024-03-30 18:12:40 +01:00
parent cb4d2f15ae
commit 35562bb9fd
120 changed files with 11732 additions and 2069 deletions

View File

@@ -2,66 +2,28 @@
BASE_DIR="/Users/me/Downloads/stalwart-test"
DOMAIN="example.org"
# Stores
#STORE="foundationdb"
#FTS_STORE="foundationdb"
#BLOB_STORE="foundationdb"
#STORE="rocksdb"
#FTS_STORE="rocksdb"
#BLOB_STORE="rocksdb"
STORE="sqlite"
FTS_STORE="sqlite"
BLOB_STORE="sqlite"
#FEATURES="foundationdb postgres mysql rocks elastic s3 redis"
FEATURES="sqlite"
# Directories
DIRECTORY="internal"
SQL_STORE="sqlite"
FEATURES="sqlite foundationdb postgres mysql rocks elastic s3 redis"
# Delete previous tests
rm -rf $BASE_DIR
# Create directories
mkdir -p $BASE_DIR $BASE_DIR/data $BASE_DIR/data/blobs $BASE_DIR/logs
mkdir -p $BASE_DIR $BASE_DIR/data $BASE_DIR/etc
# Copy config files
cp -r resources/config $BASE_DIR/etc
# Copy self-signed certs
cp -r tests/resources/tls_cert.pem $BASE_DIR/etc
cp -r tests/resources/tls_privatekey.pem $BASE_DIR/etc
# Replace stores and directories
sed -i '' -e "s|__SQL_STORE__|$SQL_STORE|g" "$BASE_DIR/etc/directory/sql.toml"
sed -i '' -e 's/disable = true//g' "$BASE_DIR/etc/directory/$DIRECTORY.toml"
sed -i '' -e 's/disable = true//g' "$BASE_DIR/etc/store/$STORE.toml"
sed -i '' -e 's/disable = true//g' "$BASE_DIR/etc/store/$FTS_STORE.toml"
sed -i '' -e 's/disable = true//g' "$BASE_DIR/etc/store/$BLOB_STORE.toml"
sed -i '' -e "s/__FTS_STORE__/$FTS_STORE/g" \
-e "s/__BLOB_STORE__/$BLOB_STORE/g" "$BASE_DIR/etc/common/store.toml"
# Copy resources
cp -r resources/config/config.toml $BASE_DIR/etc
# Replace settings
sed -i '' -e "s/__STORE__/$STORE/g" \
-e "s/__DIRECTORY__/$DIRECTORY/g" \
-e "s/__DOMAIN__/$DOMAIN/g" \
-e "s/__HOST__/mail.$DOMAIN/g" \
-e "s|__BASE_PATH__|$BASE_DIR|g" "$BASE_DIR/etc/config.toml"
sed -i '' -e "s|__CERT_PATH__|$BASE_DIR/etc/tls_cert.pem|g" \
-e "s|__PK_PATH__|$BASE_DIR/etc/tls_privatekey.pem|g" "$BASE_DIR/etc/common/tls.toml"
sed -i '' -e 's/method = "log"/method = "stdout"/g' \
-e 's/level = "info"/level = "trace"/g' "$BASE_DIR/etc/common/tracing.toml"
sed -i '' -e 's/%{HOST}%/127.0.0.1/g' "$BASE_DIR/etc/jmap/listener.toml"
sed -i '' -e 's/allow-plain-text = false/allow-plain-text = true/g' \
-e 's/2000\/1m/9999999\/100m/g' \
-e 's/concurrent = 4/concurrent = 90000/g' "$BASE_DIR/etc/imap/settings.toml"
sed -i '' -e 's/user = "stalwart-mail"//g' \
-e 's/group = "stalwart-mail"//g' "$BASE_DIR/etc/common/server.toml"
# Generate DKIM key
mkdir -p $BASE_DIR/etc/dkim
openssl genpkey -algorithm RSA -out $BASE_DIR/etc/dkim/$DOMAIN.key
sed -i '' -e "s|%{env:STALWART_PATH}%|$BASE_DIR|g" \
-e "s|%{env:DOMAIN}%|$DOMAIN|g" \
-e "s|%{env:HOSTNAME}%|mail.$DOMAIN|g" \
-e "s|%{env:OAUTH_KEY}%|12345|g" \
-e 's/level = "info"/level = "trace"/g' "$BASE_DIR/etc/config.toml"
#sed -i '' -e 's/allow-plain-text = false/allow-plain-text = true/g' \
# -e 's/2000\/1m/9999999\/100m/g' \
# -e 's/concurrent = 4/concurrent = 90000/g' "$BASE_DIR/etc/imap/settings.toml"
# Create admin user
SET_ADMIN_USER="admin" SET_ADMIN_PASS="secret" cargo run -p mail-server --no-default-features --features "$FEATURES" -- --config=$BASE_DIR/etc/config.toml

View File

@@ -70,8 +70,8 @@ impl AssertConfig for utils::config::Config {
}
fn assert_no_warnings(self) -> Self {
if !self.missing.is_empty() {
panic!("Warnings: {:#?}", self.missing);
if !self.warnings.is_empty() {
panic!("Warnings: {:#?}", self.warnings);
}
self
}

View File

@@ -63,7 +63,7 @@ fn parse_if_blocks() {
// Create context and add some conditions
let token_map = TokenMap::default().with_smtp_variables(&[
let token_map = TokenMap::default().with_variables(&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,
@@ -83,7 +83,7 @@ fn parse_if_blocks() {
IfThen {
expr: Expression {
items: vec![
ExpressionItem::Variable(2),
ExpressionItem::Variable(V_SENDER),
ExpressionItem::Constant(Constant::String("jdoe".to_string())),
ExpressionItem::BinaryOperator(BinaryOperator::Eq)
]
@@ -95,12 +95,12 @@ fn parse_if_blocks() {
IfThen {
expr: Expression {
items: vec![
ExpressionItem::Variable(10),
ExpressionItem::Variable(V_PRIORITY),
ExpressionItem::Constant(Constant::Integer(1)),
ExpressionItem::UnaryOperator(UnaryOperator::Minus),
ExpressionItem::BinaryOperator(BinaryOperator::Eq),
ExpressionItem::JmpIf { val: true, pos: 4 },
ExpressionItem::Variable(0),
ExpressionItem::Variable(V_RECIPIENT),
ExpressionItem::Constant(Constant::String("jane".to_string())),
ExpressionItem::Function {
id: 29,
@@ -128,7 +128,7 @@ fn parse_if_blocks() {
IfThen {
expr: Expression {
items: vec![
ExpressionItem::Variable(2),
ExpressionItem::Variable(V_SENDER),
ExpressionItem::Constant(Constant::String("jdoe".to_string())),
ExpressionItem::BinaryOperator(BinaryOperator::Eq)
]
@@ -145,12 +145,12 @@ fn parse_if_blocks() {
IfThen {
expr: Expression {
items: vec![
ExpressionItem::Variable(10),
ExpressionItem::Variable(V_PRIORITY),
ExpressionItem::Constant(Constant::Integer(1)),
ExpressionItem::UnaryOperator(UnaryOperator::Minus),
ExpressionItem::BinaryOperator(BinaryOperator::Eq),
ExpressionItem::JmpIf { val: true, pos: 4 },
ExpressionItem::Variable(0),
ExpressionItem::Variable(V_RECIPIENT),
ExpressionItem::Constant(Constant::String("jane".to_string())),
ExpressionItem::Function {
id: 29,
@@ -180,7 +180,7 @@ fn parse_if_blocks() {
IfThen {
expr: Expression {
items: vec![
ExpressionItem::Variable(2),
ExpressionItem::Variable(V_SENDER),
ExpressionItem::Constant(Constant::String("jdoe".to_string())),
ExpressionItem::BinaryOperator(BinaryOperator::Eq)
]
@@ -197,12 +197,12 @@ fn parse_if_blocks() {
IfThen {
expr: Expression {
items: vec![
ExpressionItem::Variable(10),
ExpressionItem::Variable(V_PRIORITY),
ExpressionItem::Constant(Constant::Integer(1)),
ExpressionItem::UnaryOperator(UnaryOperator::Minus),
ExpressionItem::BinaryOperator(BinaryOperator::Eq),
ExpressionItem::JmpIf { val: true, pos: 4 },
ExpressionItem::Variable(0),
ExpressionItem::Variable(V_RECIPIENT),
ExpressionItem::Constant(Constant::String("jane".to_string())),
ExpressionItem::Function {
id: 29,
@@ -261,7 +261,7 @@ fn parse_throttles() {
let throttle = parse_throttle(
&mut config,
"throttle",
&TokenMap::default().with_smtp_variables(&[
&TokenMap::default().with_variables(&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,
@@ -415,7 +415,7 @@ async fn eval_if() {
let mut config = Config::new(fs::read_to_string(file).unwrap()).unwrap();
let envelope = TestEnvelope::from_config(&mut config);
let token_map = TokenMap::default().with_smtp_variables(&[
let token_map = TokenMap::default().with_variables(&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,
@@ -464,7 +464,7 @@ async fn eval_dynvalue() {
let mut config = Config::new(fs::read_to_string(file).unwrap()).unwrap();
let envelope = TestEnvelope::from_config(&mut config);
let token_map = TokenMap::default().with_smtp_variables(&[
let token_map = TokenMap::default().with_variables(&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,

View File

@@ -30,28 +30,20 @@ use crate::smtp::{build_smtp, session::TestSession, TempDir};
const CONFIG: &str = r#"
[spam.header]
add-spam = true
add-spam-result = true
is-spam = "X-Spam-Status: Yes"
[spam.autolearn]
enable = true
#balance = 0.9
balance = 0.0
[spam.autolearn.ham]
replies = true
threshold = -0.5
[spam.autolearn.spam]
threshold = 6.0
[spam.threshold]
spam = 5.0
discard = 0
reject = 0
[spam.data]
[lookup.spam-config]
add-spam = true
add-spam-result = true
learn-enable = true
#learn-balance = "0.9"
learn-balance = "0.0"
learn-ham-replies = true
learn-ham-threshold = "-0.5"
learn-spam-threshold = "6.0"
threshold-spam = "5.0"
threshold-discard = 0
threshold-reject = 0
directory = ""
lookup = ""
@@ -59,8 +51,8 @@ lookup = ""
relay = true
[sieve.trusted]
from-name = "Sieve Daemon"
from-addr = "sieve@foobar.org"
from-name = "'Sieve Daemon'"
from-addr = "'sieve@foobar.org'"
return-path = ""
hostname = "mx.foobar.org"
no-capability-check = true
@@ -110,13 +102,12 @@ public-suffix = "file://{LIST_PATH}/public-suffix.dat"
#[tokio::test(flavor = "multi_thread")]
async fn antispam() {
/*let disable = true;
tracing::subscriber::set_global_default(
/*tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(
tracing_subscriber::EnvFilter::builder()
.parse(
"smtp=debug,imap=debug,jmap=debug,store=debug,utils=debug,directory=debug,common=debug",
"smtp=debug,imap=debug,jmap=debug,store=debug,utils=debug,directory=debug,common=trace",
)
.unwrap(),
)
@@ -212,6 +203,7 @@ async fn antispam() {
config.resolve_macros().await;
let stores = Stores::parse_all(&mut config).await;
let core = Core::parse(&mut config, stores, Default::default()).await;
//config.assert_no_errors();
// Add mock DNS entries
for (domain, ip) in [

View File

@@ -66,7 +66,7 @@ member-of = ["sales", "support"]
[session.auth]
require = [{if = "remote_ip = '10.0.0.1'", then = true},
{else = false}]
mechanisms = [{if = "remote_ip = '10.0.0.1'", then = "[plain, login]"},
mechanisms = [{if = "remote_ip = '10.0.0.1' && is_tls", then = "[plain, login]"},
{else = 0}]
directory = [{if = "remote_ip = '10.0.0.1'", then = "'local'"},
{else = false}]

View File

@@ -25,11 +25,14 @@ use common::Core;
use store::Stores;
use utils::config::Config;
use crate::smtp::{
build_smtp,
inbound::TestMessage,
session::{load_test_message, TestSession, VerifyResponse},
TempDir, TestSMTP,
use crate::{
smtp::{
build_smtp,
inbound::TestMessage,
session::{load_test_message, TestSession, VerifyResponse},
TempDir, TestSMTP,
},
AssertConfig,
};
use smtp::core::{Inner, Session};
@@ -39,6 +42,7 @@ data = "sqlite"
lookup = "sqlite"
blob = "sqlite"
fts = "sqlite"
directory = "local"
[store."sqlite"]
type = "sqlite"
@@ -74,11 +78,6 @@ email = "mike@test.com"
[session.rcpt]
directory = "'local'"
[[queue.quota]]
match = "sender = 'john@doe.org'"
key = ['sender']
messages = 1
[session.data.limits]
messages = [{if = "remote_ip = '10.0.0.1'", then = 1},
{else = 100}]
@@ -98,6 +97,11 @@ date = [{if = "remote_ip = '10.0.0.3'", then = true},
return-path = [{if = "remote_ip = '10.0.0.3'", then = true},
{else = false}]
[[queue.quota]]
match = "sender = 'john@doe.org'"
key = ['sender']
messages = 1
[[queue.quota]]
match = "rcpt_domain = 'foobar.org'"
key = ['rcpt_domain']
@@ -115,9 +119,10 @@ enable = true
#[tokio::test]
async fn data() {
// Enable logging
/*tracing::subscriber::set_global_default(
/*let disable = 1;
tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.with_max_level(tracing::Level::TRACE)
.finish(),
)
.unwrap();*/
@@ -128,6 +133,7 @@ async fn data() {
let mut config = Config::new(tmp_dir.update_config(CONFIG)).unwrap();
let stores = Stores::parse_all(&mut config).await;
let core = Core::parse(&mut config, stores, Default::default()).await;
config.assert_no_errors();
let mut qr = inner.init_test_queue(&core);
// Test queue message builder

View File

@@ -231,6 +231,7 @@ fn milter_address_modifications() {
let mut data = SessionData::new(
"127.0.0.1".parse().unwrap(),
0,
"127.0.0.1".parse().unwrap(),
0,
);
@@ -335,6 +336,7 @@ fn milter_message_modifications() {
let parsed_test_message = AuthenticatedMessage::parse(test_message.as_bytes()).unwrap();
let mut session_data = SessionData::new(
"127.0.0.1".parse().unwrap(),
0,
"127.0.0.1".parse().unwrap(),
0,
);
@@ -403,7 +405,7 @@ async fn milter_client_test() {
const PORT: u16 = 7357;
let mut client = MilterClient::connect(
&Milter {
enable: IfBlock::default(),
enable: IfBlock::empty(""),
addrs: vec![SocketAddr::from(([127, 0, 0, 1], PORT))],
hostname: "localhost".to_string(),
port: PORT,

View File

@@ -63,11 +63,11 @@ arguments = "['{CFG_PATH}/pipe_me.sh', 'hello', 'world']"
timeout = "10s"
[sieve.trusted]
from-name = "Sieve Daemon"
from-addr = "sieve@foobar.org"
return-path = ""
from-name = "'Sieve Daemon'"
from-addr = "'sieve@foobar.org'"
return-path = "''"
hostname = "mx.foobar.org"
sign = ["rsa"]
sign = "['rsa']"
[sieve.trusted.limits]
redirects = 3
@@ -94,11 +94,20 @@ relay = true
[session.data]
script = "'stage_data'"
[session.data.add-headers]
received = true
received-spf = true
auth-results = true
message-id = true
date = true
return-path = false
"#;
#[tokio::test]
async fn sieve_scripts() {
/*tracing::subscriber::set_global_default(
/*let disable = 1;
tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::TRACE)
.finish(),
@@ -170,7 +179,9 @@ async fn sieve_scripts() {
let script = script.clone();
let params = session
.build_script_parameters("data")
.set_variable("from", "john.doe@example.org");
.set_variable("from", "john.doe@example.org")
.with_envelope(&core.core, &session)
.await;
let handle = Handle::current();
let span = span.clone();
let core_ = core.clone();

View File

@@ -24,8 +24,7 @@
use std::time::{Duration, Instant};
use common::{
config::smtp::*,
expr::{tokenizer::TokenMap, Expression},
expr::{tokenizer::TokenMap, *},
Core,
};
@@ -52,6 +51,7 @@ data = "sql"
blob = "sql"
fts = "sql"
lookup = "sql"
directory = "sql"
[store."sql"]
type = "sqlite"
@@ -105,7 +105,7 @@ 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"
expect = "-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')"
@@ -190,7 +190,7 @@ async fn lookup_sql() {
}
// Test expression functions
let token_map = TokenMap::default().with_smtp_variables(&[
let token_map = TokenMap::default().with_variables(&[
V_RECIPIENT,
V_RECIPIENT_DOMAIN,
V_SENDER,

View File

@@ -75,6 +75,8 @@ send = "weekly"
[queue.outbound.tls]
dane = "require"
starttls = "require"
"#;
const REMOTE: &str = "
@@ -83,12 +85,22 @@ reject-non-fqdn = false
[session.rcpt]
relay = true
[session.data.add-headers]
received = true
received-spf = true
auth-results = true
message-id = true
date = true
return-path = false
";
#[tokio::test]
#[serial_test::serial]
async fn dane_verify() {
/*tracing::subscriber::set_global_default(
/*let disable = 1;
tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::TRACE)
.finish(),

View File

@@ -54,6 +54,14 @@ size = 1500
[session.extensions]
dsn = true
requiretls = true
[session.data.add-headers]
received = true
received-spf = true
auth-results = true
message-id = true
date = true
return-path = false
"#;
#[tokio::test]

View File

@@ -51,9 +51,9 @@ pub mod throttle;
pub mod tls;
const CONFIG: &str = r#"
[server]
hostname = 'mx.example.org'
greeting = 'Test SMTP instance'
[session.connect]
hostname = "'mx.example.org'"
greeting = "'Test SMTP instance'"
[server.listener.smtp-debug]
bind = ['127.0.0.1:9925']

View File

@@ -62,6 +62,15 @@ reject-non-fqdn = false
[session.rcpt]
relay = true
[session.data.add-headers]
received = true
received-spf = true
auth-results = true
message-id = true
date = true
return-path = false
"#;
#[tokio::test]

View File

@@ -59,7 +59,8 @@ chunking = false
#[tokio::test]
#[serial_test::serial]
async fn starttls_optional() {
/*tracing::subscriber::set_global_default(
/*let disable = 1;
tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::TRACE)
.finish(),

View File

@@ -125,6 +125,7 @@ impl TestSession for Session<DummyIo> {
},
data: SessionData::new(
"127.0.0.1".parse().unwrap(),
0,
"127.0.0.1".parse().unwrap(),
0,
),