Skip to content
This repository was archived by the owner on Oct 6, 2024. It is now read-only.

Commit d6788bd

Browse files
author
尼亚
authored
Merge pull request #3 from ch3ck/using-structs
Using structs to ensure sns message is accessed correctly
2 parents 06a9af7 + 407f2a3 commit d6788bd

File tree

1 file changed

+66
-25
lines changed

1 file changed

+66
-25
lines changed

src/lib.rs

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rusoto_core::Region;
2727
use rusoto_ses::{
2828
Body, Content, Destination, Message, SendEmailRequest, Ses, SesClient,
2929
};
30-
use serde::Serialize;
30+
use serde::{Deserialize, Serialize};
3131
use serde_json::Value;
3232
use simple_logger::SimpleLogger;
3333
use std::collections::HashMap;
@@ -81,6 +81,54 @@ impl fmt::Display for LambdaResponse {
8181
}
8282
}
8383

84+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
85+
pub struct EmailReceiptNotification {
86+
#[serde(rename = "notificationType")]
87+
notification_type: String,
88+
mail: Mail,
89+
receipt: Receipt,
90+
content: String,
91+
// #[serde(flatten)]
92+
// other: HashMap<String, Value>,
93+
}
94+
95+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
96+
pub struct Mail {
97+
timestamp: String,
98+
source: String,
99+
#[serde(rename = "messageId")]
100+
message_id: String,
101+
destination: Vec<String>,
102+
commonHeaders: CommonHeaders,
103+
#[serde(flatten)]
104+
other: HashMap<String, Value>,
105+
}
106+
107+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
108+
pub struct CommonHeaders {
109+
// replyTo: Vec<String>,
110+
subject: String,
111+
#[serde(rename = "returnPath")]
112+
return_path: String,
113+
#[serde(flatten)]
114+
other: HashMap<String, Value>,
115+
}
116+
117+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
118+
pub struct Receipt {
119+
#[serde(rename = "spamVerdict")]
120+
spam_verdict: Verdict,
121+
#[serde(rename = "virusVerdict")]
122+
virus_verdict: Verdict,
123+
#[serde(flatten)]
124+
other: HashMap<String, Value>,
125+
}
126+
127+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
128+
pub struct Verdict {
129+
status: String,
130+
}
131+
84132
/// PrivatEmail_Handler: processes incoming messages from SNS
85133
/// and forwards to the appropriate recipient email
86134
pub(crate) async fn privatemail_handler(
@@ -101,36 +149,28 @@ pub(crate) async fn privatemail_handler(
101149
let sns_payload = event["Records"][0]["Sns"].as_object().unwrap();
102150
info!("Raw Email Info: {:?}", sns_payload);
103151

104-
let sns_message: HashMap<String, Value> =
105-
serde_json::from_str(sns_payload["Message"].as_str().unwrap()).unwrap();
152+
let sns_message: EmailReceiptNotification =
153+
serde_json::from_str(sns_payload["Message"].as_str().unwrap())?;
106154
info!("Parsed SES Message: {:#?}", sns_message);
107-
info!("Parsed SES Message content: {:#?}", sns_message["content"]);
108-
info!("Is String: {}", sns_message["content"].is_string());
155+
info!("Parsed SES Message Mail: {:#?}", sns_message.mail);
156+
info!("Parsed SES Message Receipt: {:#?}", sns_message.receipt);
157+
info!("Parsed SES Message content: {:#?}", sns_message.content);
109158

110159
// skip spam messages
111-
let spam_verdict: &str = sns_message.get("receipt").unwrap()["spamVerdict"]
112-
["status"]
113-
.as_str()
114-
.unwrap_or_default();
115-
let virus_verdict: &str = sns_message.get("receipt").unwrap()["virus"]
116-
["status"]
117-
.as_str()
118-
.unwrap_or_default();
119-
if spam_verdict == "FAIL" || virus_verdict == "FAIL" {
160+
if sns_message.receipt.spam_verdict.status == "FAIL"
161+
|| sns_message.receipt.virus_verdict.status == "FAIL"
162+
{
120163
warn!("Message contains spam or virus, skipping!");
121164
process::exit(200);
165+
// Ok(LambdaResponse(200, "message skipped"))
122166
}
123-
124167
// Rewrite Email From header to contain sender's name with forwarder's email address
125-
let original_sender: Vec<String> = serde_json::from_value(
126-
sns_message["mail"]["commonHeaders"]["replyTo"].clone(),
127-
)?;
128-
let subject: String = serde_json::from_value(
129-
sns_message["mail"]["commonHeaders"]["subject"].clone(),
130-
)?;
168+
let original_sender: String = sns_message.mail.commonHeaders.return_path;
131169

170+
let subject: String = sns_message.mail.commonHeaders.subject;
132171
// <<<< The bug is extracting the email from the JSON <<<< //
133-
let mail_content: String = sns_message["content"].to_string().clone();
172+
173+
let mail_content: String = sns_message.content;
134174

135175
info!("sender: {:#?}", original_sender);
136176
info!("Subject: {:#?}", subject);
@@ -157,7 +197,7 @@ pub(crate) async fn privatemail_handler(
157197
data: subject,
158198
},
159199
},
160-
reply_to_addresses: Some(original_sender),
200+
reply_to_addresses: Some(vec![original_sender]),
161201
return_path: None,
162202
return_path_arn: None,
163203
source: email_config.from_email.to_string(),
@@ -202,9 +242,10 @@ mod tests {
202242
#[tokio::test]
203243
// #[ignore = "skipping integration because because of IAM requirements"]
204244
async fn handler_handles() {
205-
env::set_var("TO_EMAIL", "[email protected]");
206-
env::set_var("FROM_EMAIL", "achu@fufu.soup");
245+
env::set_var("TO_EMAIL", "[email protected]");
246+
env::set_var("FROM_EMAIL", "achu@fufu.africa");
207247
let test_event = read_test_event();
248+
208249
assert_eq!(
209250
privatemail_handler(test_event, Context::default())
210251
.await

0 commit comments

Comments
 (0)