/** * File which sends emails to me from * a captcha protected form on the contact * page. * * @author Jeffery Russell 8-19-18 */ /** used for file IO */ const utils = require('../utils/utils.js'); /** used for static files */ const includes = require('../includes/includes'); /** for parsing post data */ const qs = require('querystring'); /** cleans form submission */ const sanitizer = require('sanitizer'); /** used to send post data for the captcha */ const Request = require('request'); /** sends the email using a throw away gmail account */ const nodemailer = require("nodemailer"); /** agent for sending the email */ const smtpTransport = require('nodemailer-smtp-transport'); /** Used to load the config file from the disk */ const config = require('../utils/configLoader').getConfig(); //captcha secret const CAPTCHA_SECRET = config.CAPTCHA_SECRET; //password to gmail account const EMAIL_PASSWORD = config.EMAIL_PASSWORD; const TEMPLATE_FILE = "blog/contact.html"; const whiskers = require('whiskers'); /** * Verifies if the captcha response recieved from the post data was * valid, or are bots trying to get around the captcha * * @param data captcha data from post request * @returns {Promise} resolves whether the captcha is valid */ const verifyCapcha = function(data) { const recaptcha_url = "https://www.google.com/recaptcha/api/siteverify?" + "secret=" + CAPTCHA_SECRET + "&" + "response=" + data; return sync = new Promise(function(resolve, reject) { Request(recaptcha_url, function (error, response, body) { if (!error && response.statusCode == 200) { const googleAnswer = JSON.parse(body); if(googleAnswer.success == true) { resolve(true); } else { resolve(false); } } else { resolve(false); } } ); }); }; /** * Sends a email to my personal emaail address using a throw away * gmail account * * @param name from contact form * @param email from contact form * @param message from contact form */ const sendEmail = function(name, email, message) { const transporter = nodemailer.createTransport(smtpTransport({ service: 'gmail', host: 'smtp.gmail.com', auth: { user: config.GMAIL_ACCOUNT, pass: EMAIL_PASSWORD } })); const email_message_html = "
" + message + "
"; const email_message_text = "email: " + email + "\n" + "name: " + name + "\n" + "message: \n" + message; const mailOptions = { to: config.DESTINATION_EMAIL, // list of receivers subject: "Jrtechs.net form submission", // Subject line text: email_message_text, // plaintext body html: email_message_html }; // send mail with defined transport object transporter.sendMail(mailOptions, function(error, response) { if(error) { console.log(error); } else { console.log("Message sent: " + response); } transporter.close(); // shut down the connection pool, no more messages }); }; /** * If there was post data on the contact page, it processes it to see * if it was a valid captcha request and sends an email. If no post data was sent, * the normal form is displayed * * @param request -- main express request * @returns {Promise} renders the html of the contact widget */ const processContactPage = function(request, templateContext) { return new Promise(function(resolve, reject) { utils.getPostData(request).then(function(postData) { const data = qs.parse(postData); if(data.name && data.email && data["g-recaptcha-response"] && data.message) { verifyCapcha(sanitizer.sanitize(data["g-recaptcha-response"])) .then(function(valid) { if(valid) { templateContext.messageSent = true; resolve(); sendEmail(data.name, data.email, data.message); } else { resolve(); } }); } else { resolve(); } }).catch(function(err) { reject(err); }) }); }; module.exports = { /** * Displays the contact page along with the header, sidebar, and footer. * This uses the admin header because it doesn't need any minified css * which has been purged of some css classes which are not used in any * of the blog blog. * * @param request -- main express request * @param result -- renders the html of the contact page */ main: function(request, result) { result.writeHead(200, {'Content-Type': 'text/html'}); var templateContext = Object(); Promise.all([includes.fetchTemplate(TEMPLATE_FILE), processContactPage(request, templateContext), includes.printHeader(templateContext), includes.printFooter(templateContext), require("./sidebar.js").main(templateContext)]) .then(function (content) { const html = whiskers.render(content[0], templateContext); result.write(html); result.end(); }).catch(function(err) { console.log(err); }); } };