Commit
+173 -149 +/-13 browse
1 | diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml |
2 | index 387b9c4..7739fab 100644 |
3 | --- a/.github/workflows/rust.yml |
4 | +++ b/.github/workflows/rust.yml |
5 | @@ -30,4 +30,4 @@ jobs: |
6 | - name: Build |
7 | run: cargo build --verbose |
8 | - name: Run tests |
9 | - run: cargo test --verbose |
10 | + run: cargo test --features test --verbose |
11 | diff --git a/Cargo.toml b/Cargo.toml |
12 | index 18c3f76..0595c70 100644 |
13 | --- a/Cargo.toml |
14 | +++ b/Cargo.toml |
15 | @@ -34,3 +34,6 @@ flate2 = "1.0.25" |
16 | |
17 | [dev-dependencies] |
18 | tokio = { version = "1.16", features = ["net", "io-util", "time", "rt-multi-thread", "macros"] } |
19 | + |
20 | + [features] |
21 | + test = [] |
22 | diff --git a/README.md b/README.md |
23 | index 3e75e48..8e9ff73 100644 |
24 | --- a/README.md |
25 | +++ b/README.md |
26 | @@ -187,7 +187,7 @@ More examples available under the [examples](examples) directory. |
27 | To run the testsuite: |
28 | |
29 | ```bash |
30 | - $ cargo test --all-features |
31 | + $ cargo test --features test |
32 | ``` |
33 | |
34 | To fuzz the library with `cargo-fuzz`: |
35 | diff --git a/src/arc/seal.rs b/src/arc/seal.rs |
36 | index 101c620..9ab8d54 100644 |
37 | --- a/src/arc/seal.rs |
38 | +++ b/src/arc/seal.rs |
39 | @@ -177,6 +177,7 @@ impl Signature { |
40 | } |
41 | |
42 | #[cfg(test)] |
43 | + #[allow(unused)] |
44 | mod test { |
45 | use std::time::{Duration, Instant}; |
46 | |
47 | @@ -235,16 +236,19 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc= |
48 | |
49 | // Crate resolver |
50 | let resolver = Resolver::new_system_conf().unwrap(); |
51 | - resolver.txt_add( |
52 | - "rsa._domainkey.manchego.org.".to_string(), |
53 | - DomainKey::parse(RSA_PUBLIC_KEY.as_bytes()).unwrap(), |
54 | - Instant::now() + Duration::new(3600, 0), |
55 | - ); |
56 | - resolver.txt_add( |
57 | - "ed._domainkey.scamorza.org.".to_string(), |
58 | - DomainKey::parse(ED25519_PUBLIC_KEY.as_bytes()).unwrap(), |
59 | - Instant::now() + Duration::new(3600, 0), |
60 | - ); |
61 | + #[cfg(feature = "test")] |
62 | + { |
63 | + resolver.txt_add( |
64 | + "rsa._domainkey.manchego.org.".to_string(), |
65 | + DomainKey::parse(RSA_PUBLIC_KEY.as_bytes()).unwrap(), |
66 | + Instant::now() + Duration::new(3600, 0), |
67 | + ); |
68 | + resolver.txt_add( |
69 | + "ed._domainkey.scamorza.org.".to_string(), |
70 | + DomainKey::parse(ED25519_PUBLIC_KEY.as_bytes()).unwrap(), |
71 | + Instant::now() + Duration::new(3600, 0), |
72 | + ); |
73 | + } |
74 | |
75 | // Create private keys |
76 | let pk_ed_public = |
77 | diff --git a/src/arc/verify.rs b/src/arc/verify.rs |
78 | index 3322feb..ef44a3c 100644 |
79 | --- a/src/arc/verify.rs |
80 | +++ b/src/arc/verify.rs |
81 | @@ -175,6 +175,7 @@ impl Resolver { |
82 | } |
83 | |
84 | #[cfg(test)] |
85 | + #[allow(unused)] |
86 | mod test { |
87 | use std::{ |
88 | fs, |
89 | @@ -220,6 +221,7 @@ mod test { |
90 | .split('\n') |
91 | .filter_map(|r| r.split_once(' ').map(|(a, b)| (a, b.as_bytes()))) |
92 | { |
93 | + #[cfg(feature = "test")] |
94 | resolver.txt_add( |
95 | format!("{}.", key), |
96 | DomainKey::parse(value).unwrap(), |
97 | diff --git a/src/common/resolver.rs b/src/common/resolver.rs |
98 | index 28d355a..7cb4a61 100644 |
99 | --- a/src/common/resolver.rs |
100 | +++ b/src/common/resolver.rs |
101 | @@ -109,7 +109,7 @@ impl Resolver { |
102 | return T::unwrap_txt(value); |
103 | } |
104 | |
105 | - #[cfg(test)] |
106 | + #[cfg(feature = "test")] |
107 | if true { |
108 | return mock_resolve(key.as_ref()); |
109 | } |
110 | @@ -150,7 +150,7 @@ impl Resolver { |
111 | return Ok(value); |
112 | } |
113 | |
114 | - #[cfg(test)] |
115 | + #[cfg(feature = "test")] |
116 | if true { |
117 | return mock_resolve(key.as_ref()); |
118 | } |
119 | @@ -190,7 +190,7 @@ impl Resolver { |
120 | return Ok(value); |
121 | } |
122 | |
123 | - #[cfg(test)] |
124 | + #[cfg(feature = "test")] |
125 | if true { |
126 | return mock_resolve(key.as_ref()); |
127 | } |
128 | @@ -216,7 +216,7 @@ impl Resolver { |
129 | return Ok(value); |
130 | } |
131 | |
132 | - #[cfg(test)] |
133 | + #[cfg(feature = "test")] |
134 | if true { |
135 | return mock_resolve(key.as_ref()); |
136 | } |
137 | @@ -246,7 +246,7 @@ impl Resolver { |
138 | return Ok(value); |
139 | } |
140 | |
141 | - #[cfg(test)] |
142 | + #[cfg(feature = "test")] |
143 | if true { |
144 | return mock_resolve(&addr.to_string()); |
145 | } |
146 | @@ -270,8 +270,8 @@ impl Resolver { |
147 | .insert(addr, Arc::new(ptr), ptr_lookup.valid_until())) |
148 | } |
149 | |
150 | - pub(crate) async fn exists<'x>(&self, key: impl IntoFqdn<'x>) -> crate::Result<bool> { |
151 | - #[cfg(test)] |
152 | + pub async fn exists<'x>(&self, key: impl IntoFqdn<'x>) -> crate::Result<bool> { |
153 | + #[cfg(feature = "test")] |
154 | if true { |
155 | let key = key.into_fqdn().into_owned(); |
156 | return match self.ipv4_lookup(key.as_str()).await { |
157 | @@ -302,8 +302,8 @@ impl Resolver { |
158 | } |
159 | } |
160 | |
161 | - #[cfg(test)] |
162 | - pub(crate) fn txt_add<'x>( |
163 | + #[cfg(feature = "test")] |
164 | + pub fn txt_add<'x>( |
165 | &self, |
166 | name: impl IntoFqdn<'x>, |
167 | value: impl Into<Txt>, |
168 | @@ -313,8 +313,8 @@ impl Resolver { |
169 | .insert(name.into_fqdn().into_owned(), value.into(), valid_until); |
170 | } |
171 | |
172 | - #[cfg(test)] |
173 | - pub(crate) fn ipv4_add<'x>( |
174 | + #[cfg(feature = "test")] |
175 | + pub fn ipv4_add<'x>( |
176 | &self, |
177 | name: impl IntoFqdn<'x>, |
178 | value: Vec<Ipv4Addr>, |
179 | @@ -324,8 +324,8 @@ impl Resolver { |
180 | .insert(name.into_fqdn().into_owned(), Arc::new(value), valid_until); |
181 | } |
182 | |
183 | - #[cfg(test)] |
184 | - pub(crate) fn ipv6_add<'x>( |
185 | + #[cfg(feature = "test")] |
186 | + pub fn ipv6_add<'x>( |
187 | &self, |
188 | name: impl IntoFqdn<'x>, |
189 | value: Vec<Ipv6Addr>, |
190 | @@ -335,18 +335,13 @@ impl Resolver { |
191 | .insert(name.into_fqdn().into_owned(), Arc::new(value), valid_until); |
192 | } |
193 | |
194 | - #[cfg(test)] |
195 | - pub(crate) fn ptr_add( |
196 | - &self, |
197 | - name: IpAddr, |
198 | - value: Vec<String>, |
199 | - valid_until: std::time::Instant, |
200 | - ) { |
201 | + #[cfg(feature = "test")] |
202 | + pub fn ptr_add(&self, name: IpAddr, value: Vec<String>, valid_until: std::time::Instant) { |
203 | self.cache_ptr.insert(name, Arc::new(value), valid_until); |
204 | } |
205 | |
206 | - #[cfg(test)] |
207 | - pub(crate) fn mx_add<'x>( |
208 | + #[cfg(feature = "test")] |
209 | + pub fn mx_add<'x>( |
210 | &self, |
211 | name: impl IntoFqdn<'x>, |
212 | value: Vec<MX>, |
213 | @@ -543,8 +538,8 @@ impl<'x> IntoFqdn<'x> for &String { |
214 | } |
215 | } |
216 | |
217 | - #[cfg(test)] |
218 | - fn mock_resolve<T>(domain: &str) -> crate::Result<T> { |
219 | + #[cfg(feature = "test")] |
220 | + pub fn mock_resolve<T>(domain: &str) -> crate::Result<T> { |
221 | Err(if domain.contains("_parse_error.") { |
222 | Error::ParseError |
223 | } else if domain.contains("_invalid_record.") { |
224 | diff --git a/src/dkim/sign.rs b/src/dkim/sign.rs |
225 | index 1aa996e..819af62 100644 |
226 | --- a/src/dkim/sign.rs |
227 | +++ b/src/dkim/sign.rs |
228 | @@ -94,6 +94,7 @@ impl<T: SigningKey> DkimSigner<T, Done> { |
229 | } |
230 | |
231 | #[cfg(test)] |
232 | + #[allow(unused)] |
233 | mod test { |
234 | use std::time::{Duration, Instant}; |
235 | |
236 | @@ -206,21 +207,24 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc= |
237 | |
238 | // Create resolver |
239 | let resolver = Resolver::new_system_conf().unwrap(); |
240 | - resolver.txt_add( |
241 | - "default._domainkey.example.com.".to_string(), |
242 | - DomainKey::parse(RSA_PUBLIC_KEY.as_bytes()).unwrap(), |
243 | - Instant::now() + Duration::new(3600, 0), |
244 | - ); |
245 | - resolver.txt_add( |
246 | - "ed._domainkey.example.com.".to_string(), |
247 | - DomainKey::parse(ED25519_PUBLIC_KEY.as_bytes()).unwrap(), |
248 | - Instant::now() + Duration::new(3600, 0), |
249 | - ); |
250 | - resolver.txt_add( |
251 | - "_report._domainkey.example.com.".to_string(), |
252 | - DomainKeyReport::parse("ra=dkim-failures; rp=100; rr=x".as_bytes()).unwrap(), |
253 | - Instant::now() + Duration::new(3600, 0), |
254 | - ); |
255 | + #[cfg(feature = "test")] |
256 | + { |
257 | + resolver.txt_add( |
258 | + "default._domainkey.example.com.".to_string(), |
259 | + DomainKey::parse(RSA_PUBLIC_KEY.as_bytes()).unwrap(), |
260 | + Instant::now() + Duration::new(3600, 0), |
261 | + ); |
262 | + resolver.txt_add( |
263 | + "ed._domainkey.example.com.".to_string(), |
264 | + DomainKey::parse(ED25519_PUBLIC_KEY.as_bytes()).unwrap(), |
265 | + Instant::now() + Duration::new(3600, 0), |
266 | + ); |
267 | + resolver.txt_add( |
268 | + "_report._domainkey.example.com.".to_string(), |
269 | + DomainKeyReport::parse("ra=dkim-failures; rp=100; rr=x".as_bytes()).unwrap(), |
270 | + Instant::now() + Duration::new(3600, 0), |
271 | + ); |
272 | + } |
273 | |
274 | // Test RSA-SHA256 relaxed/relaxed |
275 | let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap(); |
276 | @@ -348,6 +352,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc= |
277 | |
278 | // Verify ATPS (success) |
279 | let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap(); |
280 | + #[cfg(feature = "test")] |
281 | resolver.txt_add( |
282 | "UN42N5XOV642KXRXRQIYANHCOUPGQL5LT4WTBKYT2IJFLBWODFDQ._atps.example.com.".to_string(), |
283 | Atps::parse(b"v=ATPS1;").unwrap(), |
284 | @@ -370,6 +375,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc= |
285 | |
286 | // Verify ATPS (success - no hash) |
287 | let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap(); |
288 | + #[cfg(feature = "test")] |
289 | resolver.txt_add( |
290 | "example.com._atps.example.com.".to_string(), |
291 | Atps::parse(b"v=ATPS1;").unwrap(), |
292 | diff --git a/src/dkim/verify.rs b/src/dkim/verify.rs |
293 | index 26099f9..1e80d44 100644 |
294 | --- a/src/dkim/verify.rs |
295 | +++ b/src/dkim/verify.rs |
296 | @@ -353,6 +353,7 @@ impl Verifier for &[u8] { |
297 | } |
298 | |
299 | #[cfg(test)] |
300 | + #[allow(unused)] |
301 | mod test { |
302 | use std::{ |
303 | fs, |
304 | @@ -412,6 +413,7 @@ mod test { |
305 | .split('\n') |
306 | .filter_map(|r| r.split_once(' ').map(|(a, b)| (a, b.as_bytes()))) |
307 | { |
308 | + #[cfg(feature = "test")] |
309 | resolver.txt_add( |
310 | format!("{}.", key), |
311 | DomainKey::parse(value).unwrap(), |
312 | diff --git a/src/dmarc/verify.rs b/src/dmarc/verify.rs |
313 | index 2521bf5..21a3287 100644 |
314 | --- a/src/dmarc/verify.rs |
315 | +++ b/src/dmarc/verify.rs |
316 | @@ -188,6 +188,7 @@ impl Resolver { |
317 | } |
318 | |
319 | #[cfg(test)] |
320 | + #[allow(unused)] |
321 | mod test { |
322 | use std::time::{Duration, Instant}; |
323 | |
324 | @@ -312,6 +313,7 @@ mod test { |
325 | Policy::Reject, |
326 | ), |
327 | ] { |
328 | + #[cfg(feature = "test")] |
329 | resolver.txt_add( |
330 | dmarc_dns, |
331 | Dmarc::parse(dmarc.as_bytes()).unwrap(), |
332 | @@ -347,6 +349,7 @@ mod test { |
333 | #[tokio::test] |
334 | async fn dmarc_verify_report_address() { |
335 | let resolver = Resolver::new_system_conf().unwrap(); |
336 | + #[cfg(feature = "test")] |
337 | resolver.txt_add( |
338 | "example.org.report.dmarc.external.org.", |
339 | Dmarc::parse(b"v=DMARC1").unwrap(), |
340 | diff --git a/src/lib.rs b/src/lib.rs |
341 | index aff4e34..5ef3194 100644 |
342 | --- a/src/lib.rs |
343 | +++ b/src/lib.rs |
344 | @@ -198,7 +198,7 @@ |
345 | //! To run the testsuite: |
346 | //! |
347 | //! ```bash |
348 | - //! $ cargo test --all-features |
349 | + //! $ cargo test --features test |
350 | //! ``` |
351 | //! |
352 | //! To fuzz the library with `cargo-fuzz`: |
353 | @@ -286,6 +286,7 @@ pub use flate2; |
354 | pub use sha1; |
355 | pub use sha2; |
356 | pub use trust_dns_resolver; |
357 | + pub use zip; |
358 | |
359 | pub struct Resolver { |
360 | pub(crate) resolver: TokioAsyncResolver, |
361 | diff --git a/src/report/arf/mod.rs b/src/report/arf/mod.rs |
362 | index c73b3da..f191d4e 100644 |
363 | --- a/src/report/arf/mod.rs |
364 | +++ b/src/report/arf/mod.rs |
365 | @@ -29,6 +29,10 @@ impl<'x> Feedback<'x> { |
366 | self.original_envelope_id.as_deref() |
367 | } |
368 | |
369 | + pub fn feedback_type(&self) -> FeedbackType { |
370 | + self.feedback_type |
371 | + } |
372 | + |
373 | pub fn with_original_envelope_id(mut self, value: impl Into<Cow<'x, str>>) -> Self { |
374 | self.original_envelope_id = Some(value.into()); |
375 | self |
376 | diff --git a/src/report/tlsrpt/mod.rs b/src/report/tlsrpt/mod.rs |
377 | index 1cf4c1d..fc50330 100644 |
378 | --- a/src/report/tlsrpt/mod.rs |
379 | +++ b/src/report/tlsrpt/mod.rs |
380 | @@ -133,7 +133,7 @@ pub enum PolicyType { |
381 | Other, |
382 | } |
383 | |
384 | - #[derive(Debug, Default, Hash, PartialEq, Eq, Serialize, Deserialize)] |
385 | + #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] |
386 | pub enum ResultType { |
387 | #[serde(rename = "starttls-not-supported")] |
388 | StartTlsNotSupported, |
389 | diff --git a/src/spf/verify.rs b/src/spf/verify.rs |
390 | index a5610bf..7337fe9 100644 |
391 | --- a/src/spf/verify.rs |
392 | +++ b/src/spf/verify.rs |
393 | @@ -513,6 +513,7 @@ impl HasLabels for &str { |
394 | } |
395 | |
396 | #[cfg(test)] |
397 | + #[allow(unused)] |
398 | mod test { |
399 | |
400 | use std::{ |
401 | @@ -557,104 +558,107 @@ mod test { |
402 | line |
403 | }; |
404 | |
405 | - if let Some(name) = line.strip_prefix("name:") { |
406 | - test_name = name.trim(); |
407 | - } else if let Some(record) = line.strip_prefix("spf:") { |
408 | - let (name, record) = record.trim().split_once(' ').unwrap(); |
409 | - resolver.txt_add( |
410 | - name.trim().to_string(), |
411 | - Spf::parse(record.as_bytes()), |
412 | - valid_until, |
413 | - ); |
414 | - } else if let Some(record) = line.strip_prefix("exp:") { |
415 | - let (name, record) = record.trim().split_once(' ').unwrap(); |
416 | - resolver.txt_add( |
417 | - name.trim().to_string(), |
418 | - Macro::parse(record.as_bytes()), |
419 | - valid_until, |
420 | - ); |
421 | - } else if let Some(record) = line.strip_prefix("a:") { |
422 | - let (name, record) = record.trim().split_once(' ').unwrap(); |
423 | - resolver.ipv4_add( |
424 | - name.trim().to_string(), |
425 | - record |
426 | - .split(',') |
427 | - .map(|item| item.trim().parse::<Ipv4Addr>().unwrap()) |
428 | - .collect(), |
429 | - valid_until, |
430 | - ); |
431 | - } else if let Some(record) = line.strip_prefix("aaaa:") { |
432 | - let (name, record) = record.trim().split_once(' ').unwrap(); |
433 | - resolver.ipv6_add( |
434 | - name.trim().to_string(), |
435 | - record |
436 | - .split(',') |
437 | - .map(|item| item.trim().parse::<Ipv6Addr>().unwrap()) |
438 | - .collect(), |
439 | - valid_until, |
440 | - ); |
441 | - } else if let Some(record) = line.strip_prefix("ptr:") { |
442 | - let (name, record) = record.trim().split_once(' ').unwrap(); |
443 | - resolver.ptr_add( |
444 | - name.trim().parse::<IpAddr>().unwrap(), |
445 | - record |
446 | - .split(',') |
447 | - .map(|item| item.trim().to_string()) |
448 | - .collect(), |
449 | - valid_until, |
450 | - ); |
451 | - } else if let Some(record) = line.strip_prefix("mx:") { |
452 | - let (name, record) = record.trim().split_once(' ').unwrap(); |
453 | - let mut mxs = Vec::new(); |
454 | - for (pos, item) in record.split(',').enumerate() { |
455 | - let ip = item.trim().parse::<IpAddr>().unwrap(); |
456 | - let mx_name = format!("mx.{}.{}", ip, pos); |
457 | - match ip { |
458 | - IpAddr::V4(ip) => { |
459 | - resolver.ipv4_add(mx_name.clone(), vec![ip], valid_until) |
460 | - } |
461 | - IpAddr::V6(ip) => { |
462 | - resolver.ipv6_add(mx_name.clone(), vec![ip], valid_until) |
463 | + #[cfg(feature = "test")] |
464 | + { |
465 | + if let Some(name) = line.strip_prefix("name:") { |
466 | + test_name = name.trim(); |
467 | + } else if let Some(record) = line.strip_prefix("spf:") { |
468 | + let (name, record) = record.trim().split_once(' ').unwrap(); |
469 | + resolver.txt_add( |
470 | + name.trim().to_string(), |
471 | + Spf::parse(record.as_bytes()), |
472 | + valid_until, |
473 | + ); |
474 | + } else if let Some(record) = line.strip_prefix("exp:") { |
475 | + let (name, record) = record.trim().split_once(' ').unwrap(); |
476 | + resolver.txt_add( |
477 | + name.trim().to_string(), |
478 | + Macro::parse(record.as_bytes()), |
479 | + valid_until, |
480 | + ); |
481 | + } else if let Some(record) = line.strip_prefix("a:") { |
482 | + let (name, record) = record.trim().split_once(' ').unwrap(); |
483 | + resolver.ipv4_add( |
484 | + name.trim().to_string(), |
485 | + record |
486 | + .split(',') |
487 | + .map(|item| item.trim().parse::<Ipv4Addr>().unwrap()) |
488 | + .collect(), |
489 | + valid_until, |
490 | + ); |
491 | + } else if let Some(record) = line.strip_prefix("aaaa:") { |
492 | + let (name, record) = record.trim().split_once(' ').unwrap(); |
493 | + resolver.ipv6_add( |
494 | + name.trim().to_string(), |
495 | + record |
496 | + .split(',') |
497 | + .map(|item| item.trim().parse::<Ipv6Addr>().unwrap()) |
498 | + .collect(), |
499 | + valid_until, |
500 | + ); |
501 | + } else if let Some(record) = line.strip_prefix("ptr:") { |
502 | + let (name, record) = record.trim().split_once(' ').unwrap(); |
503 | + resolver.ptr_add( |
504 | + name.trim().parse::<IpAddr>().unwrap(), |
505 | + record |
506 | + .split(',') |
507 | + .map(|item| item.trim().to_string()) |
508 | + .collect(), |
509 | + valid_until, |
510 | + ); |
511 | + } else if let Some(record) = line.strip_prefix("mx:") { |
512 | + let (name, record) = record.trim().split_once(' ').unwrap(); |
513 | + let mut mxs = Vec::new(); |
514 | + for (pos, item) in record.split(',').enumerate() { |
515 | + let ip = item.trim().parse::<IpAddr>().unwrap(); |
516 | + let mx_name = format!("mx.{}.{}", ip, pos); |
517 | + match ip { |
518 | + IpAddr::V4(ip) => { |
519 | + resolver.ipv4_add(mx_name.clone(), vec![ip], valid_until) |
520 | + } |
521 | + IpAddr::V6(ip) => { |
522 | + resolver.ipv6_add(mx_name.clone(), vec![ip], valid_until) |
523 | + } |
524 | } |
525 | + mxs.push(MX { |
526 | + exchanges: vec![mx_name], |
527 | + preference: (pos + 1) as u16, |
528 | + }); |
529 | + } |
530 | + resolver.mx_add(name.trim().to_string(), mxs, valid_until); |
531 | + } else if let Some(value) = line.strip_prefix("domain:") { |
532 | + helo = value.trim(); |
533 | + } else if let Some(value) = line.strip_prefix("sender:") { |
534 | + mail_from = value.trim(); |
535 | + } else if let Some(value) = line.strip_prefix("ip:") { |
536 | + client_ip = value.trim().parse().unwrap(); |
537 | + } else if let Some(value) = line.strip_prefix("expect:") { |
538 | + let value = value.trim(); |
539 | + let (result, exp): (SpfResult, &str) = |
540 | + if let Some((result, exp)) = value.split_once(' ') { |
541 | + (result.trim().try_into().unwrap(), exp.trim()) |
542 | + } else { |
543 | + (value.try_into().unwrap(), "") |
544 | + }; |
545 | + let output = resolver |
546 | + .verify_spf(client_ip, helo, "localdomain.org", mail_from) |
547 | + .await; |
548 | + assert_eq!( |
549 | + output.result(), |
550 | + result, |
551 | + "Failed for {:?}, test {}.", |
552 | + test_name, |
553 | + test_num, |
554 | + ); |
555 | + |
556 | + if !exp.is_empty() { |
557 | + assert_eq!(Some(exp.to_string()).as_deref(), output.explanation()); |
558 | + } |
559 | + test_num += 1; |
560 | + if test_name != last_test_name { |
561 | + println!("Passed test {:?}", test_name); |
562 | + last_test_name = test_name; |
563 | } |
564 | - mxs.push(MX { |
565 | - exchanges: vec![mx_name], |
566 | - preference: (pos + 1) as u16, |
567 | - }); |
568 | - } |
569 | - resolver.mx_add(name.trim().to_string(), mxs, valid_until); |
570 | - } else if let Some(value) = line.strip_prefix("domain:") { |
571 | - helo = value.trim(); |
572 | - } else if let Some(value) = line.strip_prefix("sender:") { |
573 | - mail_from = value.trim(); |
574 | - } else if let Some(value) = line.strip_prefix("ip:") { |
575 | - client_ip = value.trim().parse().unwrap(); |
576 | - } else if let Some(value) = line.strip_prefix("expect:") { |
577 | - let value = value.trim(); |
578 | - let (result, exp): (SpfResult, &str) = |
579 | - if let Some((result, exp)) = value.split_once(' ') { |
580 | - (result.trim().try_into().unwrap(), exp.trim()) |
581 | - } else { |
582 | - (value.try_into().unwrap(), "") |
583 | - }; |
584 | - let output = resolver |
585 | - .verify_spf(client_ip, helo, "localdomain.org", mail_from) |
586 | - .await; |
587 | - assert_eq!( |
588 | - output.result(), |
589 | - result, |
590 | - "Failed for {:?}, test {}.", |
591 | - test_name, |
592 | - test_num, |
593 | - ); |
594 | - |
595 | - if !exp.is_empty() { |
596 | - assert_eq!(Some(exp.to_string()).as_deref(), output.explanation()); |
597 | - } |
598 | - test_num += 1; |
599 | - if test_name != last_test_name { |
600 | - println!("Passed test {:?}", test_name); |
601 | - last_test_name = test_name; |
602 | } |
603 | } |
604 | } |