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