aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshukuru <shukuru@boitalett.re>2024-02-18 22:11:16 +0100
committershukuru <shukuru@boitalett.re>2024-02-18 22:11:16 +0100
commit3bffae34eb3196fbe9a2cbc33c5c52e59461a5f4 (patch)
tree4296d412cfb7befb54c5abfb89b4e35484e61300
parent374acb9972034e0c53683c3ac44473e36c0fe406 (diff)
Update XML parsing feature
- Implements DMARC raw deserialization - Add test - Add a fixture
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml2
-rw-r--r--fixtures/dmarc_report_fixture.xml (renamed from examples/dmarc_report_example.xml)0
-rw-r--r--src/data_structures.rs125
-rw-r--r--src/main.rs3
-rw-r--r--src/parser/deserializer.rs86
-rw-r--r--src/parser/mod.rs1
7 files changed, 198 insertions, 20 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f1524d1..4afd2e7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6,6 +6,7 @@ version = 3
name = "cramd"
version = "0.1.0"
dependencies = [
+ "serde",
"serde-xml-rs",
]
diff --git a/Cargo.toml b/Cargo.toml
index 5639855..54749e1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,10 +9,10 @@ homepage="https://mail.boitalett.re"
description="DMARC reports reader daemon"
authors=["shukuru <shukuru@boitalett.re>"]
readme="README.md"
-license="BSD-3-Clause"
license-file="LICENSE"
keywords=["dmarc", "mail", "network", "daemon"]
[dependencies]
+serde = { version = "1.0.196", features = ["serde_derive"] }
serde-xml-rs = "0.6.0"
diff --git a/examples/dmarc_report_example.xml b/fixtures/dmarc_report_fixture.xml
index d560d85..d560d85 100644
--- a/examples/dmarc_report_example.xml
+++ b/fixtures/dmarc_report_fixture.xml
diff --git a/src/data_structures.rs b/src/data_structures.rs
index a90b7b0..ef1bcc2 100644
--- a/src/data_structures.rs
+++ b/src/data_structures.rs
@@ -1,35 +1,122 @@
-enum DMARCPolicy {
+use serde::Deserialize;
+
+// Raw DS to deserialize XML report
+
+#[derive(Debug, Deserialize)]
+pub struct Feedback {
+ pub version: String,
+ pub report_metadata: ReportMetadata,
+ pub policy_published: PolicyPublished,
+ pub record: Record,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct ReportMetadata {
+ pub org_name: String,
+ pub email: String,
+ pub report_id: String,
+ pub date_range: DateRange,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct DateRange {
+ pub begin: String,
+ pub end: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct PolicyPublished {
+ pub domain: String,
+ pub adkim: String,
+ pub aspf: String,
+ pub p: String,
+ pub sp: String,
+ pub pct: String,
+ pub fo: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Record {
+ pub row: Row,
+ pub identifiers: Identifiers,
+ pub auth_results: AuthResults,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Row {
+ pub source_ip: String,
+ pub count: String,
+ pub policy_evaluated: PolicyEvaluated,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct PolicyEvaluated {
+ pub disposition: String,
+ pub dkim: String,
+ pub spf: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Identifiers {
+ pub envelope_to: String,
+ pub envelope_from: String,
+ pub header_from: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct AuthResults {
+ pub dkim: DKIM,
+ pub spf: SPF,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct DKIM {
+ pub domain: String,
+ pub selector: String,
+ pub result: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct SPF {
+ pub domain: String,
+ pub scope: String,
+ pub result: String,
+}
+
+// Rust interface DS for HTML generation
+
+pub enum DMARCPolicy {
None,
Quarantine,
- Reject
+ Reject,
}
-enum DMARCAlignment {
+pub enum DMARCAlignment {
Relaxed,
- Strict
+ Strict,
}
-enum DMARCFailureOption {
+pub enum DMARCFailureOption {
AlignedPassFailure,
OtherAlignedPassFailure,
SignatureAlignmentFailure,
- SPFFailure
+ SPFFailure,
}
-struct DMARCRecord {
- domain: String,
- adkim: DMARCAlignment,
- aspf: DMARCAlignment,
- policy: DMARCPolicy,
- subdomain_policy: DMARCPolicy,
- percentage: u64,
- failure_opt: DMARCFailureOption
+pub struct DMARCRecord {
+ pub domain: String,
+ pub adkim: DMARCAlignment,
+ pub aspf: DMARCAlignment,
+ pub policy: DMARCPolicy,
+ pub subdomain_policy: DMARCPolicy,
+ pub percentage: u64,
+ pub failure_opt: DMARCFailureOption,
}
pub struct DMARCReport {
- id: String,
- org: String,
- record: DMARCRecord,
- dkim_pass: bool,
- spf_pass: bool
+ pub id: String,
+ pub org: String,
+ pub record: DMARCRecord,
+ pub dkim_pass: bool,
+ pub spf_pass: bool,
}
diff --git a/src/main.rs b/src/main.rs
index e7a11a9..2125cf4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,6 @@
+pub mod data_structures;
+pub mod parser;
+
fn main() {
println!("Hello, world!");
}
diff --git a/src/parser/deserializer.rs b/src/parser/deserializer.rs
new file mode 100644
index 0000000..75d3c6e
--- /dev/null
+++ b/src/parser/deserializer.rs
@@ -0,0 +1,86 @@
+use std::io::Read;
+
+use crate::data_structures;
+
+fn deserialize_dmarc_report<R: Read>(reader: R) ->
+Result<data_structures::Feedback, serde_xml_rs::Error> {
+ serde_xml_rs::from_reader(reader)
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ use std::fs::File;
+ use std::io::BufReader;
+
+ #[test]
+ fn test_deserialize_dmarc_report() {
+ let dmarc_report_file = File::open("fixtures/dmarc_report_fixture.xml").unwrap();
+
+ let reader = BufReader::new(dmarc_report_file);
+
+ let should_be = data_structures::Feedback {
+ version: String::from("1.0"),
+ report_metadata: data_structures::ReportMetadata {
+ org_name: String::from("Enterprise Outlook"),
+ email: String::from("dmarcreport@microsoft.com"),
+ report_id: String::from("3374fb5148ba40c1a5cf8e3d36f34a34"),
+ date_range: data_structures::DateRange {
+ begin: String::from("1707436800"),
+ end: String::from("1707523200"),
+ },
+ },
+ policy_published: data_structures::PolicyPublished {
+ domain: String::from("boitalett.re"),
+ adkim: String::from("s"),
+ aspf: String::from("s"),
+ p: String::from("reject"),
+ sp: String::from("reject"),
+ pct: String::from("100"),
+ fo: String::from("0"),
+ },
+ record: data_structures::Record {
+ row: data_structures::Row {
+ source_ip: String::from("195.154.102.43"),
+ count: String::from("1"),
+ policy_evaluated: data_structures::PolicyEvaluated {
+ disposition: String::from("none"),
+ dkim: String::from("pass"),
+ spf: String::from("pass"),
+ },
+ },
+ identifiers: data_structures::Identifiers {
+ envelope_to: String::from("babilou.com"),
+ envelope_from: String::from("boitalett.re"),
+ header_from: String::from("boitalett.re"),
+ },
+ auth_results: data_structures::AuthResults {
+ dkim: data_structures::DKIM {
+ domain: String::from("boitalett.re"),
+ selector: String::from("2023101501"),
+ result: String::from("pass"),
+ },
+ spf: data_structures::SPF {
+ domain: String::from("boitalett.re"),
+ scope: String::from("mfrom"),
+ result: String::from("pass"),
+ },
+ },
+ },
+ };
+
+ match deserialize_dmarc_report(reader) {
+ Ok(report) => {
+ assert_eq!(
+ report.report_metadata.report_id,
+ should_be.report_metadata.report_id
+ );
+ println!("{:?}", report);
+ },
+ Err(err) => {
+ panic!("{:?}", err);
+ }
+ }
+ }
+}
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
new file mode 100644
index 0000000..218d426
--- /dev/null
+++ b/src/parser/mod.rs
@@ -0,0 +1 @@
+pub mod deserializer;