feat!: DKIM verifier (#35)

* feat!: DKIM verifier

This implements a DKIM verification as well as a strict
DKIM signature alignment check with domain in `From`
header address.

Caches the retrieved RDATA using in-memory LRU.

BREAKING CHANGE: incoming messages now require DKIM signatures
  aligned to domain of the `From` header address.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>

* chore(license): License binaries under GPLv3

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>

---------

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
This commit is contained in:
Jagoda Estera Ślązak
2026-02-16 09:50:55 +01:00
committed by GitHub
parent 3bf8395ef6
commit a096d0550f
12 changed files with 2072 additions and 40 deletions
+21
View File
@@ -26,6 +26,17 @@ pub fn extract_address(input: &str) -> Option<String> {
})
}
pub fn get_domain_from_address(address: &str) -> Option<String> {
let parts: Vec<&str> = address.split('@').collect();
if parts.len() == 2
&& let Some(domain) = parts.get(1)
{
Some(domain.to_string())
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -44,4 +55,14 @@ mod tests {
let result = extract_address(input);
assert_eq!(result, expected)
}
#[rstest]
#[case("t1@example.org", Some("example.org".to_string()))]
#[case("SRS1=HHH=example.com==HHH=TT=example.org=alice@example.net", Some("example.net".to_string()))]
#[case("invalid", None)]
#[case("invalid@address@com", None)]
fn test_get_domain_from_address(#[case] input: &str, #[case] expected: Option<String>) {
let result = get_domain_from_address(input);
assert_eq!(result, expected);
}
}