Implement Email DAO for sending verification mails

This commit is contained in:
Tankred Hase
2016-05-29 16:47:45 +02:00
parent c805371f0e
commit d3cce89b06
10 changed files with 235 additions and 24 deletions

View File

@@ -17,6 +17,9 @@
'use strict';
const log = require('npmlog');
const util = require('../service/util');
/**
* A simple wrapper around Nodemailer to send verification emails
*/
@@ -30,21 +33,131 @@ class Email {
this._mailer = mailer;
}
/**
* Create an instance of the reusable nodemailer SMTP transport.
* @param {string} host The SMTP server's hostname e.g. 'smtp.gmail.com'
* @param {Object} auth Auth credential e.g. { user:'user@gmail.com', pass:'pass' }
* @param {Object} sender The message 'FROM' field e.g. { name:'Your Support', email:'noreply@exmple.com' }
* @param {string} port (optional) The SMTP server's SMTP port. Defaults to 465.
* @param {boolean} secure (optional) If TSL should be used. Defaults to true.
* @param {boolean} requireTLS (optional) If TSL is mandatory. Defaults to true.
*/
init(options) {
this._transport = this._mailer.createTransport({
host: options.host,
port: options.port || 465,
auth: options.auth,
secure: options.secure || true,
requireTLS: options.requireTLS || true
});
this._sender = options.sender;
}
/**
* A generic method to send an email message via nodemail.
* @param {Object} from The sender user id object e.g. { name:'Jon Smith', email:'j@smith.com' }
* @param {Object} to The recipient user id object e.g. { name:'Jon Smith', email:'j@smith.com' }
* @param {string} subject The message subject
* @param {string} text The message plaintext body
* @param {string} html The message html body
* @yield {Object} The reponse object containing SMTP info
*/
*send(options) {
let mailOptions = {
from: {
name: options.from.name,
address: options.from.email
},
to: {
name: options.to.name,
address: options.to.email
},
subject: options.subject,
text: options.text,
html: options.html
};
try {
let info = yield this._transport.sendMail(mailOptions);
log.silly('email', 'Email sent.', info);
return info;
} catch(error) {
log.error('email', 'Sending email failed.', error, options);
throw error;
}
}
/**
* Send the verification email to the user to verify email address
* ownership. If the primary email address is provided, only one email
* will be sent out. Otherwise all of the PGP key's user IDs will be
* verified, resulting in an email sent per user ID.
* @param {Array} options.userIds The user id documents containing the nonces
* @param {Array} options.primaryEmail (optional) The user's primary email address
* @param {Array} userIds The user id documents containing the nonces
* @param {Array} primaryEmail (optional) The user's primary email address
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
* @yield {undefined}
*/
sendVerification() {
return Promise.resolve();
*sendVerification(options) {
let primaryEmail = options.primaryEmail, userIds = options.userIds, origin = options.origin;
let primaryUserId = userIds.find(uid => uid.email === primaryEmail);
if (primaryUserId) { // send only one email to the primary user id
return yield this._sendVerificationHelper(primaryUserId, origin);
}
for (let uid of userIds) {
yield this._sendVerificationHelper(uid, origin);
}
}
send() {
/**
* Help method to send a verification message
* @param {Object} userId The user id document
* @param {Object} origin The origin of the server
* @yield {Object} The send response from the SMTP server
*/
*_sendVerificationHelper(userId, origin) {
let message = this._createVerifyMessage(userId, origin);
try {
let info = yield this.send(message);
if (!this._checkResponse(info)) {
log.warn('email', 'Verification mail may not have been received.', info);
}
return info;
} catch(e) {
util.throw(500, 'Sending verification email failed');
}
}
/**
* Helper function to create a verification message object.
* @param {Object} userId The user id document
* @param {Object} origin The origin of the server
* @return {Object} The message object
*/
_createVerifyMessage(userId, origin) {
let verifyLink = origin.protocol + '://' + origin.host +
'/api/v1/verify/?keyid=' + encodeURIComponent(userId.keyid) +
'&nonce=' + encodeURIComponent(userId.nonce);
let text = `Hey${userId.name ? ' ' + userId.name : ''},
please click here to verify your key: ${verifyLink}
`;
return {
from: this._sender,
to: userId,
subject: 'Verify Your Key',
text: text
};
}
/**
* Check if the message was sent successfully according to SMTP
* reply codes: http://www.supermailer.de/smtp_reply_codes.htm
* @param {Object} info The info object return from nodemailer
* @return {boolean} If the message was received by the user
*/
_checkResponse(info) {
return /^2/.test(info.response);
}
}