mail_auth/common/
message.rs1use super::headers::{AuthenticatedHeader, Header, HeaderParser};
8use crate::{AuthenticatedMessage, arc, common::crypto::HashAlgorithm, dkim};
9use mail_parser::{Address, HeaderName, HeaderValue, Message, parsers::MessageStream};
10
11impl<'x> AuthenticatedMessage<'x> {
12 pub fn parse(raw_message: &'x [u8]) -> Option<Self> {
13 Self::parse_with_opts(raw_message, true)
14 }
15
16 pub fn from_parsed(parsed: &'x Message<'x>, strict: bool) -> Self {
17 let root = parsed.root_part();
18 let mut message = AuthenticatedMessage {
19 raw_message: parsed.raw_message(),
20 body_offset: root.raw_body_offset(),
21 headers: Vec::with_capacity(root.headers.len()),
22 ..Default::default()
23 };
24
25 for header in root.headers() {
26 let name =
27 &parsed.raw_message[header.offset_field as usize..header.offset_start as usize - 1];
28 let value =
29 &parsed.raw_message[header.offset_start as usize..header.offset_end as usize];
30
31 match &header.name {
32 HeaderName::From => {
33 message.parse_from(&header.value);
34 }
35 HeaderName::Date => {
36 message.date_header_present = true;
37 }
38 HeaderName::Received => {
39 message.received_headers_count += 1;
40 }
41 HeaderName::MessageId => {
42 message.message_id_header_present = true;
43 }
44 HeaderName::DkimSignature => {
45 message.parse_dkim(name, value, strict);
46 }
47 HeaderName::ArcAuthenticationResults => {
48 message.parse_aar(name, value);
49 }
50 HeaderName::ArcSeal => {
51 message.parse_as(name, value);
52 }
53 HeaderName::ArcMessageSignature => {
54 message.parse_ams(name, value, strict);
55 }
56 _ => (),
57 }
58
59 message.headers.push((name, value))
60 }
61
62 message.finalize()
63 }
64
65 pub fn parse_with_opts(raw_message: &'x [u8], strict: bool) -> Option<Self> {
66 let mut message = AuthenticatedMessage {
67 raw_message,
68 ..Default::default()
69 };
70
71 let mut headers = HeaderParser::new(raw_message);
72
73 for (header, value) in &mut headers {
74 let name = match header {
75 AuthenticatedHeader::Ds(name) => {
76 message.parse_dkim(name, value, strict);
77 name
78 }
79 AuthenticatedHeader::Aar(name) => {
80 message.parse_aar(name, value);
81 name
82 }
83 AuthenticatedHeader::Ams(name) => {
84 message.parse_ams(name, value, strict);
85 name
86 }
87 AuthenticatedHeader::As(name) => {
88 message.parse_as(name, value);
89 name
90 }
91 AuthenticatedHeader::From(name) => {
92 message.parse_from(&MessageStream::new(value).parse_address());
93 name
94 }
95 AuthenticatedHeader::Other(name) => name,
96 };
97
98 message.headers.push((name, value));
99 }
100
101 if !message.headers.is_empty() {
102 message.received_headers_count = headers.num_received;
104 message.message_id_header_present = headers.has_message_id;
105 message.date_header_present = headers.has_date;
106
107 if let Some(offset) = headers.body_offset() {
109 message.body_offset = offset as u32;
110 } else {
111 message.body_offset = raw_message.len() as u32;
112 }
113 Some(message.finalize())
114 } else {
115 None
116 }
117 }
118
119 fn parse_dkim(&mut self, name: &'x [u8], value: &'x [u8], strict: bool) {
120 let signature = match dkim::Signature::parse(value) {
121 Ok(signature) if signature.l == 0 || !strict => {
122 let ha = HashAlgorithm::from(signature.a);
123 if !self
124 .body_hashes
125 .iter()
126 .any(|(c, h, l, _)| c == &signature.cb && h == &ha && l == &signature.l)
127 {
128 self.body_hashes
129 .push((signature.cb, ha, signature.l, Vec::new()));
130 }
131 Ok(signature)
132 }
133 Ok(_) => Err(crate::Error::SignatureLength),
134 Err(err) => Err(err),
135 };
136
137 self.dkim_headers.push(Header::new(name, value, signature));
138 }
139
140 fn parse_aar(&mut self, name: &'x [u8], value: &'x [u8]) {
141 let results = arc::Results::parse(value);
142 if !self.has_arc_errors {
143 self.has_arc_errors = results.is_err();
144 }
145 self.aar_headers.push(Header::new(name, value, results));
146 }
147
148 fn parse_ams(&mut self, name: &'x [u8], value: &'x [u8], strict: bool) {
149 let signature = match arc::Signature::parse(value) {
150 Ok(signature) if signature.l == 0 || !strict => {
151 let ha = HashAlgorithm::from(signature.a);
152 if !self
153 .body_hashes
154 .iter()
155 .any(|(c, h, l, _)| c == &signature.cb && h == &ha && l == &signature.l)
156 {
157 self.body_hashes
158 .push((signature.cb, ha, signature.l, Vec::new()));
159 }
160 Ok(signature)
161 }
162 Ok(_) => {
163 self.has_arc_errors = true;
164 Err(crate::Error::SignatureLength)
165 }
166 Err(err) => {
167 self.has_arc_errors = true;
168 Err(err)
169 }
170 };
171
172 self.ams_headers.push(Header::new(name, value, signature));
173 }
174
175 fn parse_as(&mut self, name: &'x [u8], value: &'x [u8]) {
176 let seal = arc::Seal::parse(value);
177 if !self.has_arc_errors {
178 self.has_arc_errors = seal.is_err();
179 }
180 self.as_headers.push(Header::new(name, value, seal));
181 }
182
183 fn parse_from(&mut self, value: &HeaderValue<'x>) {
184 match value {
185 HeaderValue::Address(Address::List(list)) => {
186 self.from.extend(
187 list.iter()
188 .filter_map(|a| a.address.as_ref().map(|a| a.to_lowercase())),
189 );
190 }
191 HeaderValue::Address(Address::Group(group_list)) => {
192 self.from.extend(group_list.iter().flat_map(|group| {
193 group
194 .addresses
195 .iter()
196 .filter_map(|a| a.address.as_ref().map(|a| a.to_lowercase()))
197 }))
198 }
199 _ => (),
200 }
201 }
202
203 fn finalize(mut self) -> Self {
204 let body = self
205 .raw_message
206 .get(self.body_offset as usize..)
207 .unwrap_or_default();
208
209 for (cb, ha, l, bh) in &mut self.body_hashes {
211 *bh = ha.hash(cb.canonical_body(body, *l)).as_ref().to_vec();
212 }
213
214 if !self.as_headers.is_empty() && !self.has_arc_errors {
216 self.as_headers.sort_unstable_by(|a, b| {
217 a.header
218 .as_ref()
219 .unwrap()
220 .i
221 .cmp(&b.header.as_ref().unwrap().i)
222 });
223 self.ams_headers.sort_unstable_by(|a, b| {
224 a.header
225 .as_ref()
226 .unwrap()
227 .i
228 .cmp(&b.header.as_ref().unwrap().i)
229 });
230 self.aar_headers.sort_unstable_by(|a, b| {
231 a.header
232 .as_ref()
233 .unwrap()
234 .i
235 .cmp(&b.header.as_ref().unwrap().i)
236 });
237 }
238
239 self
240 }
241
242 pub fn received_headers_count(&self) -> usize {
243 self.received_headers_count
244 }
245
246 pub fn has_message_id_header(&self) -> bool {
247 self.message_id_header_present
248 }
249
250 pub fn has_date_header(&self) -> bool {
251 self.date_header_present
252 }
253
254 pub fn raw_message(&self) -> &[u8] {
255 self.raw_message
256 }
257
258 pub fn raw_headers(&self) -> &[u8] {
259 self.raw_message
260 .get(..self.body_offset as usize)
261 .unwrap_or_default()
262 }
263
264 pub fn raw_parsed_headers(&self) -> &[(&[u8], &[u8])] {
265 &self.headers
266 }
267
268 pub fn raw_body(&self) -> &[u8] {
269 self.raw_message
270 .get(self.body_offset as usize..)
271 .unwrap_or_default()
272 }
273
274 pub fn body_offset(&self) -> usize {
275 self.body_offset as usize
276 }
277
278 pub fn froms(&self) -> &[String] {
279 &self.from
280 }
281
282 pub fn from(&self) -> &str {
283 self.from.first().map_or("", |f| f.as_str())
284 }
285}