Fix Sieve: add Received headers to auto-generated messages and detect loops
This commit is contained in:
@@ -32,6 +32,7 @@ pub struct Scripting {
|
|||||||
pub untrusted_runtime: Runtime,
|
pub untrusted_runtime: Runtime,
|
||||||
pub trusted_runtime: Runtime,
|
pub trusted_runtime: Runtime,
|
||||||
pub trusted_compiler: Compiler,
|
pub trusted_compiler: Compiler,
|
||||||
|
pub max_received_headers: usize,
|
||||||
pub from_addr: IfBlock,
|
pub from_addr: IfBlock,
|
||||||
pub from_name: IfBlock,
|
pub from_name: IfBlock,
|
||||||
pub return_path: IfBlock,
|
pub return_path: IfBlock,
|
||||||
@@ -65,7 +66,7 @@ impl Scripting {
|
|||||||
.with_cpu_limit(untrusted.max_cpu_cycles as usize)
|
.with_cpu_limit(untrusted.max_cpu_cycles as usize)
|
||||||
.with_max_variable_size(untrusted.max_var_size as usize)
|
.with_max_variable_size(untrusted.max_var_size as usize)
|
||||||
.with_max_redirects(untrusted.max_redirects as usize)
|
.with_max_redirects(untrusted.max_redirects as usize)
|
||||||
.with_max_received_headers(untrusted.max_received_headers as usize)
|
.with_max_received_headers(usize::MAX) // This is set to usize::MAX here, but the actual limit is enforced during ingestion.
|
||||||
.with_max_header_size(untrusted.max_header_size as usize)
|
.with_max_header_size(untrusted.max_header_size as usize)
|
||||||
.with_max_out_messages(untrusted.max_out_messages as usize)
|
.with_max_out_messages(untrusted.max_out_messages as usize)
|
||||||
.with_default_vacation_expiry(untrusted.default_expiry_vacation.into_inner().as_secs())
|
.with_default_vacation_expiry(untrusted.default_expiry_vacation.into_inner().as_secs())
|
||||||
@@ -180,6 +181,7 @@ impl Scripting {
|
|||||||
trusted_compiler,
|
trusted_compiler,
|
||||||
untrusted_scripts,
|
untrusted_scripts,
|
||||||
trusted_scripts,
|
trusted_scripts,
|
||||||
|
max_received_headers: untrusted.max_received_headers as usize,
|
||||||
from_addr: bp.compile_expr(
|
from_addr: bp.compile_expr(
|
||||||
ObjectType::SieveSystemScript.singleton(),
|
ObjectType::SieveSystemScript.singleton(),
|
||||||
&trusted.ctx_default_from_address(),
|
&trusted.ctx_default_from_address(),
|
||||||
@@ -209,6 +211,7 @@ impl Clone for Scripting {
|
|||||||
from_addr: self.from_addr.clone(),
|
from_addr: self.from_addr.clone(),
|
||||||
from_name: self.from_name.clone(),
|
from_name: self.from_name.clone(),
|
||||||
return_path: self.return_path.clone(),
|
return_path: self.return_path.clone(),
|
||||||
|
max_received_headers: self.max_received_headers,
|
||||||
sign: self.sign.clone(),
|
sign: self.sign.clone(),
|
||||||
trusted_scripts: self.trusted_scripts.clone(),
|
trusted_scripts: self.trusted_scripts.clone(),
|
||||||
untrusted_scripts: self.untrusted_scripts.clone(),
|
untrusted_scripts: self.untrusted_scripts.clone(),
|
||||||
|
|||||||
@@ -146,7 +146,11 @@ impl LdapDirectory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.account.groups = if groups.is_empty() { None } else { Some(groups) };
|
result.account.groups = if groups.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(groups)
|
||||||
|
};
|
||||||
} else if let Some(filter) = &self.mappings.filter_member_of {
|
} else if let Some(filter) = &self.mappings.filter_member_of {
|
||||||
let filter = filter.build(&result.dn);
|
let filter = filter.build(&result.dn);
|
||||||
let rs = conn
|
let rs = conn
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ use crate::{
|
|||||||
ingest::{EmailIngest, IngestEmail, IngestSource, IngestedEmail},
|
ingest::{EmailIngest, IngestEmail, IngestSource, IngestedEmail},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{Server, auth::AccessToken, scripts::plugins::PluginContext};
|
||||||
Server, auth::AccessToken, expr::functions::EmptyResolver, scripts::plugins::PluginContext,
|
|
||||||
};
|
|
||||||
use mail_builder::headers::date::Date;
|
use mail_builder::headers::date::Date;
|
||||||
use mail_parser::{HeaderName, MessageParser};
|
use mail_parser::{HeaderName, MessageParser};
|
||||||
use sieve::{Envelope, Event, Input, Mailbox, Recipient, Sieve, SpamStatus};
|
use sieve::{Envelope, Event, Input, Mailbox, Recipient, Sieve, SpamStatus};
|
||||||
@@ -114,14 +112,6 @@ impl SieveScriptIngest for Server {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|header| matches!(header.name, HeaderName::Received))
|
.filter(|header| matches!(header.name, HeaderName::Received))
|
||||||
.count();
|
.count();
|
||||||
let max_received_headers = self
|
|
||||||
.eval_if(
|
|
||||||
&self.core.smtp.session.data.max_received_headers,
|
|
||||||
&EmptyResolver,
|
|
||||||
session_id,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap_or(50);
|
|
||||||
|
|
||||||
// Obtain mailboxIds
|
// Obtain mailboxIds
|
||||||
let account_id = access_token.account_id();
|
let account_id = access_token.account_id();
|
||||||
@@ -404,12 +394,12 @@ impl SieveScriptIngest for Server {
|
|||||||
} => {
|
} => {
|
||||||
input = true.into();
|
input = true.into();
|
||||||
if let Some(message) = messages.get(message_id) {
|
if let Some(message) = messages.get(message_id) {
|
||||||
if received_headers >= max_received_headers {
|
if received_headers >= self.core.sieve.max_received_headers {
|
||||||
trc::event!(
|
trc::event!(
|
||||||
Smtp(SmtpEvent::LoopDetected),
|
Smtp(SmtpEvent::LoopDetected),
|
||||||
From = mail_from.clone(),
|
From = mail_from.clone(),
|
||||||
Total = received_headers,
|
Total = received_headers,
|
||||||
Limit = max_received_headers,
|
Limit = self.core.sieve.max_received_headers,
|
||||||
SpanId = session_id,
|
SpanId = session_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -36267,7 +36267,7 @@ impl Default for SieveUserInterpreter {
|
|||||||
max_nested_includes: 3u64,
|
max_nested_includes: 3u64,
|
||||||
max_nested_tests: 15u64,
|
max_nested_tests: 15u64,
|
||||||
max_out_messages: 3u64,
|
max_out_messages: 3u64,
|
||||||
max_received_headers: 10u64,
|
max_received_headers: 50u64,
|
||||||
max_redirects: 1u64,
|
max_redirects: 1u64,
|
||||||
max_script_size: 102400,
|
max_script_size: 102400,
|
||||||
max_string_length: 4096u64,
|
max_string_length: 4096u64,
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
lV3eX4039eN4Y1KtcoXv5vnm6_-nGt_bHuLB6jlkFZQ
|
sEuYGmxMEGuoMkdYNGUNw9kpFzscVRfeSRk44yRmcU8
|
||||||
@@ -45,7 +45,10 @@ pub async fn test() {
|
|||||||
email: "jane.smith@example.org".into(),
|
email: "jane.smith@example.org".into(),
|
||||||
email_aliases: vec![],
|
email_aliases: vec![],
|
||||||
secret: Some("$app$4096614298472586996$".into()),
|
secret: Some("$app$4096614298472586996$".into()),
|
||||||
groups: Some(vec!["sales@example.org".into(), "corporate@example.org".into()]),
|
groups: Some(vec![
|
||||||
|
"sales@example.org".into(),
|
||||||
|
"corporate@example.org".into()
|
||||||
|
]),
|
||||||
description: Some("Jane Smith".into()),
|
description: Some("Jane Smith".into()),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -107,7 +110,10 @@ pub async fn test() {
|
|||||||
email: "jane.smith@example.org".into(),
|
email: "jane.smith@example.org".into(),
|
||||||
email_aliases: vec![],
|
email_aliases: vec![],
|
||||||
secret: Some("this is Jane's LDAP password".into()),
|
secret: Some("this is Jane's LDAP password".into()),
|
||||||
groups: Some(vec!["sales@example.org".into(), "corporate@example.org".into()]),
|
groups: Some(vec![
|
||||||
|
"sales@example.org".into(),
|
||||||
|
"corporate@example.org".into()
|
||||||
|
]),
|
||||||
description: Some("Jane Smith".into())
|
description: Some("Jane Smith".into())
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user