add email sending script
refs: #4053
Change-Id: I1ffe550b20e7fe394fb7f25d71eafa61d4a8fc6f
diff --git a/ndncert-mail.conf.sample b/ndncert-mail.conf.sample
new file mode 100644
index 0000000..492c1e5
--- /dev/null
+++ b/ndncert-mail.conf.sample
@@ -0,0 +1,12 @@
+[ndncert_smtp_settings]
+SMTP_SERVER = localhost or remote smtp server
+SMTP_PORT = port number, usually one from 25 465 587
+ENCRYPT_MODE = select one from ssl/tls/none
+SMTP_USER = leave it empty if you do not have one
+SMTP_PASSWORD = leave it empty if you do not have one
+
+[ndncert_email_settings]
+MAIL_FROM = NDN Testbed Certificate Robot <noreply-ndncert@named-data.net>
+SUBJECT = Email Challenge Triggered by NDNCERT
+TEXT_TEMPLATE = Your PIN code: {0} from NDNCERT CA {1}. Please keep it secret and type in to your application to finish the certificiate issuance process. If you do not know what is going on, please ignore the message.
+HTML_TEMPLATE = <html><head></head><body><p><b>Your PIN code: {0} from NDNCERT CA {1}</b></p><p>Please keep it secret and type in to your application to finish the certificiate issuance process. If you do not know what is going on, please ignore the message.</p><p>Sincerely,<br/>NDN Testbed NDNCERT robot</p>
\ No newline at end of file
diff --git a/ndncert-send-email-challenge.py b/ndncert-send-email-challenge.py
new file mode 100755
index 0000000..1916791
--- /dev/null
+++ b/ndncert-send-email-challenge.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+import sys
+import smtplib
+import argparse
+import socket
+from ConfigParser import SafeConfigParser
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+
+socket.setdefaulttimeout(10)
+
+# init arg parser and parse
+parser = argparse.ArgumentParser(description='Email-challenge-sender for NDNCERT')
+parser.add_argument("email", help="the receiver email address")
+parser.add_argument("secret", help="the secret of the challenge")
+parser.add_argument("caName", help="the CA name")
+args = parser.parse_args()
+
+# open config
+confParser = SafeConfigParser()
+confParser.read('@SYSCONFDIR@/ndncert/ndncert-mail.conf')
+
+# read smtp settings
+encrypt_mode = confParser.get('ndncert_smtp_settings', "ENCRYPT_MODE")
+server = confParser.get('ndncert_smtp_settings', 'SMTP_SERVER')
+port = confParser.get('ndncert_smtp_settings', 'SMTP_PORT')
+username = confParser.get('ndncert_smtp_settings', 'SMTP_USER')
+password = confParser.get('ndncert_smtp_settings', 'SMTP_PASSWORD')
+
+# read email settings
+msg_from = confParser.get('ndncert_email_settings', 'MAIL_FROM')
+subject = confParser.get('ndncert_email_settings', 'SUBJECT')
+text = confParser.get('ndncert_email_settings', 'TEXT_TEMPLATE').format(args.secret, args.caName)
+html = confParser.get('ndncert_email_settings', 'HTML_TEMPLATE').format(args.secret, args.caName)
+
+# form email message
+msg = MIMEMultipart('alternative')
+msg.attach(MIMEText(text, 'plain'))
+msg.attach(MIMEText(html, 'html'))
+msg['From'] = msg_from
+msg['To'] = args.email
+msg['Subject'] = subject
+
+# send email
+if encrypt_mode == 'ssl':
+ smtp_server = smtplib.SMTP_SSL(server, port)
+else: # none or tls
+ smtp_server = smtplib.SMTP(server, port)
+
+if encrypt_mode != 'none':
+ smtp_server.ehlo()
+ if encrypt_mode == 'tls':
+ smtp_server.starttls()
+
+if username != '' and password != '':
+ smtp_server.login(username, password)
+
+smtp_server.sendmail(msg_from, args.email, msg.as_string())
+smtp_server.close()
+sys.exit()
diff --git a/src/challenge-module/challenge-email.cpp b/src/challenge-module/challenge-email.cpp
index fc25d8c..c63961c 100644
--- a/src/challenge-module/challenge-email.cpp
+++ b/src/challenge-module/challenge-email.cpp
@@ -65,7 +65,7 @@
}
std::string emailCode = generateSecretCode();
- sendEmail(emailAddress, emailCode);
+ sendEmail(emailAddress, emailCode, request.getCaName().toUri());
request.setStatus(NEED_CODE);
request.setChallengeType(CHALLENGE_TYPE);
@@ -185,30 +185,17 @@
}
void
-ChallengeEmail::sendEmail(const std::string& emailAddress, const std::string& secret) const
+ChallengeEmail::sendEmail(const std::string& emailAddress, const std::string& secret,
+ const std::string& caName) const
{
- pid_t pid = fork();
-
- if (pid < 0) {
- _LOG_TRACE("Cannot fork before trying to call email sending script");
+ std::string command = m_sendEmailScript;
+ command += " \"" + emailAddress + "\" \"" + secret + "\" \"" + caName + "\"";
+ int result = system(command.c_str());
+ if (result == -1) {
+ _LOG_TRACE("EmailSending Script " + m_sendEmailScript + " fails.");
}
- else if (pid == 0) {
- int ret;
- std::vector<char> emailParam(emailAddress.begin(), emailAddress.end());
- emailParam.push_back('\0');
-
- std::vector<char> secretParam(secret.begin(), secret.end());
- secretParam.push_back('\0');
-
- std::vector<char> defaultParam(m_sendEmailScript.begin(), m_sendEmailScript.end());
- defaultParam.push_back('\0');
-
- char* argv[] = {&defaultParam[0], &emailParam[0], &secretParam[0], nullptr};
- ret = execve(m_sendEmailScript.c_str(), argv, nullptr);
-
- BOOST_THROW_EXCEPTION(Error("Email sending script went wrong, error code: " + std::to_string(ret)));
- }
-
+ _LOG_TRACE("EmailSending Script " + m_sendEmailScript +
+ " was executed successfully with return value" + std::to_string(result) + ".");
return;
}
diff --git a/src/challenge-module/challenge-email.hpp b/src/challenge-module/challenge-email.hpp
index 0f0d935..a014d00 100644
--- a/src/challenge-module/challenge-email.hpp
+++ b/src/challenge-module/challenge-email.hpp
@@ -30,7 +30,10 @@
/**
* @brief Provide Email based challenge
*
+ * For challenge design
* @sa https://github.com/named-data/ndncert/wiki/NDN-Certificate-Management-Protocol
+ * For deployment instructions:
+ * @sa https://github.com/named-data/ndncert/wiki/Deploy-Email-Challenge
*
* The main process of this challenge module is:
* 1. Requester provides its email address.
@@ -49,7 +52,7 @@
class ChallengeEmail : public ChallengeModule
{
public:
- ChallengeEmail(const std::string& scriptPath = "send-mail.sh",
+ ChallengeEmail(const std::string& scriptPath = "ndncert-send-email-challenge",
const size_t& maxAttemptTimes = 3,
const time::seconds secretLifetime = time::minutes(20));
@@ -79,7 +82,8 @@
isValidEmailAddress(const std::string& emailAddress);
void
- sendEmail(const std::string& emailAddress, const std::string& secret) const;
+ sendEmail(const std::string& emailAddress, const std::string& secret,
+ const std::string& caName) const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static std::tuple<time::system_clock::TimePoint, std::string, int>
diff --git a/src/client-module.cpp b/src/client-module.cpp
index 67c6201..9994c31 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -94,7 +94,7 @@
certRequest.setName(Name(state->m_key.getName()).append("cert-request").appendVersion());
certRequest.setContentType(tlv::ContentType_Key);
certRequest.setFreshnessPeriod(time::hours(24));
- certRequest.setContent(state->m_key.getPublicKey().get<uint8_t>(), state->m_key.getPublicKey().size());
+ certRequest.setContent(state->m_key.getPublicKey().data(), state->m_key.getPublicKey().size());
SignatureInfo signatureInfo;
signatureInfo.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
time::system_clock::now() + time::days(10)));
diff --git a/tests/identity-management-fixture.cpp b/tests/identity-management-fixture.cpp
index 1eef608..aeaab40 100644
--- a/tests/identity-management-fixture.cpp
+++ b/tests/identity-management-fixture.cpp
@@ -99,7 +99,7 @@
certificate.setFreshnessPeriod(time::hours(1));
// set content
- certificate.setContent(key.getPublicKey().get<uint8_t>(), key.getPublicKey().size());
+ certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size());
// set signature-info
SignatureInfo info;
diff --git a/tests/unit-tests/challenge-email.t.cpp b/tests/unit-tests/challenge-email.t.cpp
index ad3ef83..f048f61 100644
--- a/tests/unit-tests/challenge-email.t.cpp
+++ b/tests/unit-tests/challenge-email.t.cpp
@@ -18,8 +18,8 @@
* See AUTHORS.md for complete list of ndncert authors and contributors.
*/
-#include "identity-management-fixture.hpp"
#include "challenge-module/challenge-email.hpp"
+#include "identity-management-fixture.hpp"
namespace ndn {
namespace ndncert {
@@ -76,6 +76,23 @@
BOOST_CHECK_EQUAL(request.getStatus(), ChallengeEmail::NEED_CODE);
BOOST_CHECK_EQUAL(request.getChallengeType(), "Email");
+
+ std::string line = "";
+ std::string delimiter = " ";
+ std::ifstream emailFile("tmp.txt");
+ if (emailFile.is_open())
+ {
+ getline(emailFile, line);
+ emailFile.close();
+ }
+ std::string recipientEmail = line.substr(0, line.find(delimiter));
+ std::string secret = line.substr(line.find(delimiter) + 1);
+
+ BOOST_CHECK_EQUAL(recipientEmail, "zhiyi@cs.ucla.edu");
+ auto stored_secret = request.getChallengeSecrets().get<std::string>(ChallengeEmail::JSON_CODE);
+ BOOST_CHECK_EQUAL(secret, stored_secret);
+
+ std::remove("tmp.txt");
}
BOOST_AUTO_TEST_CASE(OnSelectInterestComingWithInvalidEmail)
diff --git a/tests/unit-tests/test-send-email.sh b/tests/unit-tests/test-send-email.sh
index 78117fc..901d057 100755
--- a/tests/unit-tests/test-send-email.sh
+++ b/tests/unit-tests/test-send-email.sh
@@ -3,6 +3,6 @@
RECEIVER=$1
SECRET=$2
-MESSAGE=$RECEIVER$SECRET
+MESSAGE=$RECEIVER" "$SECRET
-echo $MESSAGE
+echo $MESSAGE > tmp.txt
diff --git a/wscript b/wscript
index 2f86766..438b03f 100644
--- a/wscript
+++ b/wscript
@@ -91,6 +91,15 @@
bld.install_files("${SYSCONFDIR}/ndncert", "client.conf.sample")
+ bld.install_files("${SYSCONFDIR}/ndncert", "ndncert-mail.conf.sample")
+
+ bld(features="subst",
+ source='ndncert-send-email-challenge.py',
+ target='ndncert-send-email-challenge',
+ install_path="${BINDIR}",
+ chmod=Utils.O755,
+ )
+
bld(features = "subst",
source='libndn-cert.pc.in',
target='libndn-cert.pc',