BREAKING CHANGE(smartmta): Rebrand package to @push.rocks/smartmta, add consolidated email security verification and IPC handler
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use mail_auth::common::crypto::{RsaKey, Sha256};
|
||||
use mail_auth::common::headers::HeaderWriter;
|
||||
use mail_auth::dkim::{Canonicalization, DkimSigner};
|
||||
use mail_auth::{AuthenticatedMessage, DkimResult, MessageAuthenticator};
|
||||
use mail_auth::{AuthenticatedMessage, DkimOutput, DkimResult, MessageAuthenticator};
|
||||
use rustls_pki_types::{PrivateKeyDer, PrivatePkcs1KeyDer, pem::PemObject};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -22,6 +22,48 @@ pub struct DkimVerificationResult {
|
||||
pub details: Option<String>,
|
||||
}
|
||||
|
||||
/// Convert raw `mail-auth` DKIM outputs to our serializable results.
|
||||
///
|
||||
/// This is used internally by `verify_dkim` and by the compound `verify_email_security`.
|
||||
pub fn dkim_outputs_to_results(dkim_outputs: &[DkimOutput<'_>]) -> Vec<DkimVerificationResult> {
|
||||
if dkim_outputs.is_empty() {
|
||||
return vec![DkimVerificationResult {
|
||||
is_valid: false,
|
||||
domain: None,
|
||||
selector: None,
|
||||
status: "none".to_string(),
|
||||
details: Some("No DKIM signatures found".to_string()),
|
||||
}];
|
||||
}
|
||||
|
||||
dkim_outputs
|
||||
.iter()
|
||||
.map(|output| {
|
||||
let (is_valid, status, details) = match output.result() {
|
||||
DkimResult::Pass => (true, "pass", None),
|
||||
DkimResult::Neutral(err) => (false, "neutral", Some(err.to_string())),
|
||||
DkimResult::Fail(err) => (false, "fail", Some(err.to_string())),
|
||||
DkimResult::PermError(err) => (false, "permerror", Some(err.to_string())),
|
||||
DkimResult::TempError(err) => (false, "temperror", Some(err.to_string())),
|
||||
DkimResult::None => (false, "none", None),
|
||||
};
|
||||
|
||||
let (domain, selector) = output
|
||||
.signature()
|
||||
.map(|sig| (Some(sig.d.clone()), Some(sig.s.clone())))
|
||||
.unwrap_or((None, None));
|
||||
|
||||
DkimVerificationResult {
|
||||
is_valid,
|
||||
domain,
|
||||
selector,
|
||||
status: status.to_string(),
|
||||
details,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Verify DKIM signatures on a raw email message.
|
||||
///
|
||||
/// Uses the `mail-auth` crate which performs full RFC 6376 verification
|
||||
@@ -34,45 +76,7 @@ pub async fn verify_dkim(
|
||||
.ok_or_else(|| SecurityError::Parse("Failed to parse email for DKIM verification".into()))?;
|
||||
|
||||
let dkim_outputs = authenticator.verify_dkim(&message).await;
|
||||
|
||||
let mut results = Vec::new();
|
||||
|
||||
if dkim_outputs.is_empty() {
|
||||
results.push(DkimVerificationResult {
|
||||
is_valid: false,
|
||||
domain: None,
|
||||
selector: None,
|
||||
status: "none".to_string(),
|
||||
details: Some("No DKIM signatures found".to_string()),
|
||||
});
|
||||
return Ok(results);
|
||||
}
|
||||
|
||||
for output in &dkim_outputs {
|
||||
let (is_valid, status, details) = match output.result() {
|
||||
DkimResult::Pass => (true, "pass", None),
|
||||
DkimResult::Neutral(err) => (false, "neutral", Some(err.to_string())),
|
||||
DkimResult::Fail(err) => (false, "fail", Some(err.to_string())),
|
||||
DkimResult::PermError(err) => (false, "permerror", Some(err.to_string())),
|
||||
DkimResult::TempError(err) => (false, "temperror", Some(err.to_string())),
|
||||
DkimResult::None => (false, "none", None),
|
||||
};
|
||||
|
||||
let (domain, selector) = output
|
||||
.signature()
|
||||
.map(|sig| (Some(sig.d.clone()), Some(sig.s.clone())))
|
||||
.unwrap_or((None, None));
|
||||
|
||||
results.push(DkimVerificationResult {
|
||||
is_valid,
|
||||
domain,
|
||||
selector,
|
||||
status: status.to_string(),
|
||||
details,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
Ok(dkim_outputs_to_results(&dkim_outputs))
|
||||
}
|
||||
|
||||
/// Sign a raw email message with DKIM (RSA-SHA256).
|
||||
|
||||
Reference in New Issue
Block a user