mail_auth/dkim/
headers.rs1use std::fmt::{Display, Formatter};
8
9use crate::common::headers::{HeaderWriter, Writer};
10
11use super::{Algorithm, Canonicalization, HashAlgorithm, Signature};
12
13impl Signature {
14 pub fn write(&self, writer: &mut impl Writer, as_header: bool) {
15 let (header, new_line) = match self.ch {
16 Canonicalization::Relaxed if !as_header => (&b"dkim-signature:"[..], &b" "[..]),
17 _ => (&b"DKIM-Signature: "[..], &b"\r\n\t"[..]),
18 };
19 writer.write(header);
20 writer.write(b"v=1; a=");
21 writer.write(match self.a {
22 Algorithm::RsaSha256 => b"rsa-sha256",
23 Algorithm::RsaSha1 => b"rsa-sha1",
24 Algorithm::Ed25519Sha256 => b"ed25519-sha256",
25 });
26 for (tag, value) in [(&b"; s="[..], &self.s), (&b"; d="[..], &self.d)] {
27 writer.write(tag);
28 writer.write(value.as_bytes());
29 }
30 writer.write(b"; c=");
31 self.ch.serialize_name(writer);
32 writer.write(b"/");
33 self.cb.serialize_name(writer);
34
35 if let Some(atps) = &self.atps {
36 writer.write(b"; atps=");
37 writer.write(atps.as_bytes());
38 writer.write(b"; atpsh=");
39 writer.write(match self.atpsh {
40 Some(HashAlgorithm::Sha256) => b"sha256",
41 Some(HashAlgorithm::Sha1) => b"sha1",
42 _ => b"none",
43 });
44 }
45 if self.r {
46 writer.write(b"; r=y");
47 }
48
49 writer.write(b";");
50 writer.write(new_line);
51
52 let mut bw = 1;
53 for (num, h) in self.h.iter().enumerate() {
54 if bw + h.len() + 1 >= 76 {
55 writer.write(new_line);
56 bw = 1;
57 }
58 if num > 0 {
59 writer.write_len(b":", &mut bw);
60 } else {
61 writer.write_len(b"h=", &mut bw);
62 }
63 writer.write_len(h.as_bytes(), &mut bw);
64 }
65
66 if !self.i.is_empty() {
67 if bw + self.i.len() + 3 >= 76 {
68 writer.write(b";");
69 writer.write(new_line);
70 bw = 1;
71 } else {
72 writer.write_len(b"; ", &mut bw);
73 }
74 writer.write_len(b"i=", &mut bw);
75
76 for &ch in self.i.as_bytes().iter() {
77 match ch {
78 0..=0x20 | b';' | 0x7f..=u8::MAX => {
79 writer.write_len(format!("={ch:02X}").as_bytes(), &mut bw);
80 }
81 _ => {
82 writer.write_len(&[ch], &mut bw);
83 }
84 }
85 if bw >= 76 {
86 writer.write(new_line);
87 bw = 1;
88 }
89 }
90 }
91
92 for (tag, value) in [
93 (&b"t="[..], self.t),
94 (&b"x="[..], self.x),
95 (&b"l="[..], self.l),
96 ] {
97 if value > 0 {
98 let value = value.to_string();
99 writer.write_len(b";", &mut bw);
100 if bw + tag.len() + value.len() >= 76 {
101 writer.write(new_line);
102 bw = 1;
103 } else {
104 writer.write_len(b" ", &mut bw);
105 }
106
107 writer.write_len(tag, &mut bw);
108 writer.write_len(value.as_bytes(), &mut bw);
109 }
110 }
111
112 for (tag, value) in [(&b"; bh="[..], &self.bh), (&b"; b="[..], &self.b)] {
113 writer.write_len(tag, &mut bw);
114 for &byte in value {
115 writer.write_len(&[byte], &mut bw);
116 if bw >= 76 {
117 writer.write(new_line);
118 bw = 1;
119 }
120 }
121 }
122
123 writer.write(b";");
124 if as_header {
125 writer.write(b"\r\n");
126 }
127 }
128}
129
130impl HeaderWriter for Signature {
131 fn write_header(&self, writer: &mut impl Writer) {
132 self.write(writer, true);
133 }
134}
135
136impl Display for Signature {
137 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
138 let mut buf = Vec::new();
139 self.write(&mut buf, false);
140 f.write_str(&String::from_utf8_lossy(&buf))
141 }
142}