Show the authentication results in the message info

This commit is contained in:
Hocuri
2022-10-15 13:31:25 +02:00
parent e45747ea99
commit ba323609fa
3 changed files with 58 additions and 26 deletions

View File

@@ -3,6 +3,7 @@
use std::borrow::Cow;
use std::collections::HashSet;
use std::fmt;
use anyhow::Result;
use mailparse::MailHeaderMap;
@@ -27,14 +28,14 @@ pub(crate) async fn handle_authres(
context: &Context,
mail: &ParsedMail<'_>,
from: &str,
) -> Result<bool> {
) -> Result<DkimResults> {
let from_domain = match EmailAddress::new(from) {
Ok(email) => email.domain,
Err(e) => {
warn!(context, "invalid email {:#}", e);
// This email is invalid, but don't return an error, we still want to
// add a stub to the database so that it's not downloaded again
return Ok(false);
return Ok(DkimResults::default());
}
};
@@ -44,6 +45,27 @@ pub(crate) async fn handle_authres(
Ok(allow_keychange)
}
#[derive(Default, Debug)]
pub(crate) struct DkimResults {
pub dkim_passed: bool,
pub dkim_works: bool,
pub allow_keychange: bool,
}
impl fmt::Display for DkimResults {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"DKIM Results: Passed={}, Works={}, Allow_Keychange={}",
self.dkim_passed, self.dkim_works, self.allow_keychange
)?;
if !self.allow_keychange {
write!(fmt, " KEYCHANGES NOT ALLOWED!!!!")?;
}
Ok(())
}
}
type AuthservId = String;
#[derive(Debug, PartialEq)]
@@ -59,12 +81,12 @@ enum DkimResult {
Nothing,
}
type AuthenticationResults = Vec<(AuthservId, DkimResult)>;
type ParsedAuthresHeaders = Vec<(AuthservId, DkimResult)>;
fn parse_authres_headers(
headers: &mailparse::headers::Headers<'_>,
from_domain: &str,
) -> AuthenticationResults {
) -> ParsedAuthresHeaders {
let mut res = Vec::new();
for header_value in headers.get_all_values(HeaderDef::AuthenticationResults.into()) {
let header_value = remove_comments(&header_value);
@@ -163,7 +185,7 @@ fn parse_one_authres_header(header_value: &str, from_domain: &str) -> DkimResult
/// See [`handle_authres`].
async fn update_authservid_candidates(
context: &Context,
authres: &AuthenticationResults,
authres: &ParsedAuthresHeaders,
) -> Result<()> {
let mut new_ids: HashSet<&str> = authres
.iter()
@@ -205,9 +227,9 @@ async fn update_authservid_candidates(
/// we don't accept Autocrypt key changes if they come with negative Authentication-Results.
async fn should_allow_keychange(
context: &Context,
mut authres: AuthenticationResults,
mut authres: ParsedAuthresHeaders,
from_domain: &str,
) -> Result<bool> {
) -> Result<DkimResults> {
let mut dkim_passed = false;
let ids_config = context.get_config(Config::AuthservidCandidates).await?;
@@ -239,12 +261,17 @@ async fn should_allow_keychange(
}
}
let dkim_works = dkim_works(context, from_domain).await?;
let mut dkim_works = dkim_works(context, from_domain).await?;
if !dkim_works && dkim_passed {
set_dkim_works(context, from_domain).await?;
dkim_works = true;
}
Ok(dkim_passed || !dkim_works)
Ok(DkimResults {
dkim_passed,
dkim_works,
allow_keychange: dkim_passed || !dkim_works,
})
}
async fn dkim_works(context: &Context, from_domain: &str) -> Result<bool> {
@@ -492,8 +519,8 @@ Authentication-Results: box.hispanilandia.net; spf=pass smtp.mailfrom=adbenitez@
let mail = mailparse::parse_mail(&bytes)?;
let from = &mimeparser::get_from(&mail.headers)[0].addr;
let allow_keychange = handle_authres(&t, &mail, from).await?;
assert!(allow_keychange);
let res = handle_authres(&t, &mail, from).await?;
assert!(res.allow_keychange);
}
for entry in &dir {
@@ -504,8 +531,8 @@ Authentication-Results: box.hispanilandia.net; spf=pass smtp.mailfrom=adbenitez@
let mail = mailparse::parse_mail(&bytes)?;
let from = &mimeparser::get_from(&mail.headers)[0].addr;
let allow_keychange = handle_authres(&t, &mail, from).await?;
if !allow_keychange {
let res = handle_authres(&t, &mail, from).await?;
if !res.allow_keychange {
println!(
"!!!!!! FAILURE Receiving {:?}, keychange is not allowed !!!!!!",
entry.path()
@@ -514,7 +541,8 @@ Authentication-Results: box.hispanilandia.net; spf=pass smtp.mailfrom=adbenitez@
}
let from_domain = EmailAddress::new(from).unwrap().domain;
let dkim_result = dkim_works(&t, &from_domain).await.unwrap();
assert_eq!(res.dkim_works, dkim_works(&t, &from_domain).await.unwrap());
assert_eq!(res.dkim_passed, res.dkim_works);
// delta.blinzeln.de and gmx.de have invalid DKIM, so the DKIM check should fail
let expected_result = (from_domain != "delta.blinzeln.de") && (from_domain != "gmx.de")
@@ -524,7 +552,7 @@ Authentication-Results: box.hispanilandia.net; spf=pass smtp.mailfrom=adbenitez@
// Other forged emails
&& !from.starts_with("forged");
if dkim_result != expected_result {
if res.dkim_passed != expected_result {
if authres_parsing_works {
println!(
"!!!!!! FAILURE Receiving {:?}, order {:#?} wrong result: !!!!!!",
@@ -533,7 +561,7 @@ Authentication-Results: box.hispanilandia.net; spf=pass smtp.mailfrom=adbenitez@
);
test_failed = true;
}
println!("From {}: {}", from_domain, dkim_result);
println!("From {}: {}", from_domain, res.dkim_passed);
}
}
}