2016-05-26 13:45:32 +02:00
|
|
|
/**
|
|
|
|
* Mailvelope - secure email with OpenPGP encryption for Webmail
|
|
|
|
* Copyright (C) 2016 Mailvelope GmbH
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License version 3
|
|
|
|
* as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2016-05-29 16:47:45 +02:00
|
|
|
const log = require('npmlog');
|
|
|
|
const util = require('../service/util');
|
2016-06-08 14:01:30 +02:00
|
|
|
const nodemailer = require('nodemailer');
|
|
|
|
const openpgpEncrypt = require('nodemailer-openpgp').openpgpEncrypt;
|
2016-05-29 16:47:45 +02:00
|
|
|
|
2016-05-26 13:45:32 +02:00
|
|
|
/**
|
|
|
|
* A simple wrapper around Nodemailer to send verification emails
|
|
|
|
*/
|
|
|
|
class Email {
|
2016-05-29 16:47:45 +02:00
|
|
|
/**
|
|
|
|
* Create an instance of the reusable nodemailer SMTP transport.
|
2016-06-02 13:00:22 +02:00
|
|
|
* @param {string} host SMTP server's hostname: 'smtp.gmail.com'
|
|
|
|
* @param {Object} auth Auth credential: { user:'user@gmail.com', pass:'pass' }
|
|
|
|
* @param {Object} sender message 'FROM' field: { name:'Your Support', email:'noreply@exmple.com' }
|
|
|
|
* @param {string} port (optional) SMTP server's SMTP port. Defaults to 465.
|
|
|
|
* @param {boolean} tls (optional) if TSL should be used. Defaults to true.
|
|
|
|
* @param {boolean} starttls (optional) force STARTTLS to prevent downgrade attack. Defaults to true.
|
2016-06-02 16:19:54 +02:00
|
|
|
* @param {boolean} pgp (optional) if outgoing emails are encrypted to the user's public key.
|
2016-05-29 16:47:45 +02:00
|
|
|
*/
|
2017-08-15 16:03:06 +08:00
|
|
|
init({host, port = 465, auth, tls, starttls, pgp, sender}) {
|
2016-06-08 14:01:30 +02:00
|
|
|
this._transport = nodemailer.createTransport({
|
2017-01-21 11:51:33 +00:00
|
|
|
host,
|
|
|
|
port,
|
|
|
|
auth,
|
|
|
|
secure: (tls !== undefined) ? util.isTrue(tls) : true,
|
|
|
|
requireTLS: (starttls !== undefined) ? util.isTrue(starttls) : true,
|
2016-05-29 16:47:45 +02:00
|
|
|
});
|
2017-01-21 11:51:33 +00:00
|
|
|
if (util.isTrue(pgp)) {
|
2016-06-08 14:01:30 +02:00
|
|
|
this._transport.use('stream', openpgpEncrypt());
|
2016-06-02 16:19:54 +02:00
|
|
|
}
|
2017-01-21 11:51:33 +00:00
|
|
|
this._sender = sender;
|
2016-05-29 16:47:45 +02:00
|
|
|
}
|
|
|
|
|
2016-05-27 19:57:48 +02:00
|
|
|
/**
|
2016-05-31 16:48:18 +02:00
|
|
|
* Send the verification email to the user using a template.
|
|
|
|
* @param {Object} template the email template to use
|
|
|
|
* @param {Object} userId user id document
|
2016-06-09 11:38:00 +02:00
|
|
|
* @param {string} keyId key id of public key
|
2016-05-31 16:48:18 +02:00
|
|
|
* @param {Object} origin origin of the server
|
|
|
|
* @yield {Object} send response from the SMTP server
|
2016-05-27 19:57:48 +02:00
|
|
|
*/
|
2017-08-16 12:27:03 +08:00
|
|
|
async send({template, userId, keyId, origin}) {
|
2017-08-15 16:03:06 +08:00
|
|
|
const message = {
|
2016-05-30 15:36:32 +02:00
|
|
|
from: this._sender,
|
|
|
|
to: userId,
|
2016-05-31 16:48:18 +02:00
|
|
|
subject: template.subject,
|
|
|
|
text: template.text,
|
|
|
|
html: template.html,
|
2016-05-30 15:36:32 +02:00
|
|
|
params: {
|
|
|
|
name: userId.name,
|
2016-06-10 12:06:08 +02:00
|
|
|
baseUrl: util.url(origin),
|
2017-08-15 16:03:06 +08:00
|
|
|
keyId,
|
2016-06-10 13:17:28 +02:00
|
|
|
nonce: userId.nonce
|
2016-05-30 15:36:32 +02:00
|
|
|
}
|
|
|
|
};
|
2017-08-16 12:27:03 +08:00
|
|
|
return this._sendHelper(message);
|
2016-05-30 15:36:32 +02:00
|
|
|
}
|
|
|
|
|
2016-05-30 10:48:17 +02:00
|
|
|
/**
|
|
|
|
* A generic method to send an email message via nodemailer.
|
|
|
|
* @param {Object} from sender user id object: { name:'Jon Smith', email:'j@smith.com' }
|
|
|
|
* @param {Object} to recipient user id object: { name:'Jon Smith', email:'j@smith.com' }
|
|
|
|
* @param {string} subject message subject
|
|
|
|
* @param {string} text message plaintext body template
|
|
|
|
* @param {string} html message html body template
|
|
|
|
* @param {Object} params (optional) nodermailer template parameters
|
|
|
|
* @yield {Object} reponse object containing SMTP info
|
|
|
|
*/
|
2017-08-16 12:27:03 +08:00
|
|
|
async _sendHelper({from, to, subject, text, html, params = {}}) {
|
2017-08-15 16:03:06 +08:00
|
|
|
const template = {
|
2017-01-21 11:51:33 +00:00
|
|
|
subject,
|
|
|
|
text,
|
|
|
|
html,
|
|
|
|
encryptionKeys: [to.publicKeyArmored]
|
2016-05-30 10:48:17 +02:00
|
|
|
};
|
2017-08-15 16:03:06 +08:00
|
|
|
const sender = {
|
2016-05-30 10:48:17 +02:00
|
|
|
from: {
|
2017-01-21 11:51:33 +00:00
|
|
|
name: from.name,
|
|
|
|
address: from.email
|
2016-05-30 10:48:17 +02:00
|
|
|
}
|
|
|
|
};
|
2017-08-15 16:03:06 +08:00
|
|
|
const recipient = {
|
2016-05-30 10:48:17 +02:00
|
|
|
to: {
|
2017-01-21 11:51:33 +00:00
|
|
|
name: to.name,
|
|
|
|
address: to.email
|
2016-05-30 10:48:17 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-05-29 16:47:45 +02:00
|
|
|
try {
|
2017-08-15 16:03:06 +08:00
|
|
|
const sendFn = this._transport.templateSender(template, sender);
|
2017-08-16 12:27:03 +08:00
|
|
|
const info = await sendFn(recipient, params);
|
2016-05-29 16:47:45 +02:00
|
|
|
if (!this._checkResponse(info)) {
|
2016-05-30 10:48:17 +02:00
|
|
|
log.warn('email', 'Message may not have been received.', info);
|
2016-05-29 16:47:45 +02:00
|
|
|
}
|
|
|
|
return info;
|
2017-08-15 16:03:06 +08:00
|
|
|
} catch (error) {
|
2017-01-21 11:51:33 +00:00
|
|
|
log.error('email', 'Sending message failed.', error);
|
2016-05-30 10:48:17 +02:00
|
|
|
util.throw(500, 'Sending email to user failed');
|
2016-05-29 16:47:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the message was sent successfully according to SMTP
|
|
|
|
* reply codes: http://www.supermailer.de/smtp_reply_codes.htm
|
2016-05-29 17:51:10 +02:00
|
|
|
* @param {Object} info info object return from nodemailer
|
|
|
|
* @return {boolean} if the message was received by the user
|
2016-05-29 16:47:45 +02:00
|
|
|
*/
|
|
|
|
_checkResponse(info) {
|
|
|
|
return /^2/.test(info.response);
|
2016-05-27 19:57:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-15 16:03:06 +08:00
|
|
|
module.exports = Email;
|