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