2013-12-08 03:56:03 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2016-09-14 07:51:51 +03:00
|
|
|
/* eslint-disable no-console */
|
2017-03-23 08:51:18 +03:00
|
|
|
|
|
|
|
'use strict'
|
|
|
|
const MailParser = require('mailparser').MailParser
|
|
|
|
const simplesmtp = require('simplesmtp')
|
|
|
|
const P = require('../lib/promise')
|
|
|
|
|
|
|
|
const config = require('../config').getProperties()
|
|
|
|
|
|
|
|
const TEMPLATES_WITH_NO_CODE = new Set([
|
|
|
|
'passwordResetEmail'
|
|
|
|
])
|
2013-12-08 03:56:03 +04:00
|
|
|
|
|
|
|
// SMTP half
|
|
|
|
|
2013-12-17 09:36:42 +04:00
|
|
|
var users = {}
|
|
|
|
|
|
|
|
function emailName(emailAddress) {
|
2017-02-04 00:29:46 +03:00
|
|
|
var utf8Address = Buffer.from(emailAddress, 'binary').toString('utf-8')
|
|
|
|
return utf8Address.split('@')[0]
|
2013-12-17 09:36:42 +04:00
|
|
|
}
|
|
|
|
|
2017-03-23 08:51:18 +03:00
|
|
|
module.exports = (printLogs) => {
|
|
|
|
printLogs = printLogs || process.env.MAIL_HELPER_LOGS
|
|
|
|
const console = printLogs ? global.console : {
|
|
|
|
log() {},
|
|
|
|
error() {}
|
|
|
|
}
|
|
|
|
return new P((resolve, reject) => {
|
|
|
|
const smtp = simplesmtp.createSimpleServer(
|
|
|
|
{
|
|
|
|
SMTPBanner: 'FXATEST'
|
|
|
|
},
|
|
|
|
function (req) {
|
|
|
|
var mp = new MailParser({ defaultCharset: 'utf-8' })
|
|
|
|
mp.on('end',
|
|
|
|
function (mail) {
|
|
|
|
var link = mail.headers['x-link']
|
|
|
|
var rc = mail.headers['x-recovery-code']
|
|
|
|
var rul = mail.headers['x-report-signin-link']
|
|
|
|
var uc = mail.headers['x-unblock-code']
|
|
|
|
var vc = mail.headers['x-verify-code']
|
2017-12-20 20:03:32 +03:00
|
|
|
var sc = mail.headers['x-signin-verify-code']
|
2017-03-23 08:51:18 +03:00
|
|
|
var template = mail.headers['x-template-name']
|
2017-05-30 19:26:19 +03:00
|
|
|
|
|
|
|
var smsLink
|
|
|
|
if (/MockNexmo\.message\.sendSms/.test(mail.subject)) {
|
|
|
|
const smsUrlMatch = /(https?:\/\/.*$)/.exec(mail.text)
|
|
|
|
smsLink = smsUrlMatch && smsUrlMatch[1]
|
|
|
|
}
|
|
|
|
|
2017-03-23 08:51:18 +03:00
|
|
|
var name = emailName(mail.headers.to)
|
|
|
|
if (vc) {
|
|
|
|
console.log('\x1B[32m', link, '\x1B[39m')
|
|
|
|
}
|
2017-12-20 20:03:32 +03:00
|
|
|
else if (sc) {
|
|
|
|
console.log('\x1B[32mToken code: ', sc, '\x1B[39m')
|
|
|
|
}
|
2017-03-23 08:51:18 +03:00
|
|
|
else if (rc) {
|
|
|
|
console.log('\x1B[34m', link, '\x1B[39m')
|
|
|
|
}
|
|
|
|
else if (uc) {
|
|
|
|
console.log('\x1B[36mUnblock code:', uc, '\x1B[39m')
|
|
|
|
console.log('\x1B[36mReport link:', rul, '\x1B[39m')
|
|
|
|
}
|
2017-05-30 19:26:19 +03:00
|
|
|
else if (smsLink) {
|
|
|
|
console.log('\x1B[36mSMS link:', smsLink, '\x1B[39m')
|
|
|
|
}
|
2017-03-23 08:51:18 +03:00
|
|
|
else if (TEMPLATES_WITH_NO_CODE.has(template)) {
|
|
|
|
console.log(`Notification email: ${template}`)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.error('\x1B[31mNo verify code match\x1B[39m')
|
|
|
|
console.error(mail)
|
|
|
|
}
|
|
|
|
if (users[name]) {
|
|
|
|
users[name].push(mail)
|
|
|
|
} else {
|
|
|
|
users[name] = [mail]
|
|
|
|
}
|
2017-06-09 18:32:54 +03:00
|
|
|
|
|
|
|
if (mail.headers.cc) {
|
|
|
|
// Support for CC headers
|
|
|
|
var ccName = emailName(mail.headers.cc)
|
|
|
|
|
|
|
|
if (users[ccName]) {
|
|
|
|
users[ccName].push(mail)
|
|
|
|
} else {
|
|
|
|
users[ccName] = [mail]
|
|
|
|
}
|
|
|
|
}
|
2017-03-23 08:51:18 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
req.pipe(mp)
|
|
|
|
req.accept()
|
2013-12-08 04:54:15 +04:00
|
|
|
}
|
2013-12-17 09:36:42 +04:00
|
|
|
)
|
2017-03-23 08:51:18 +03:00
|
|
|
smtp.listen(config.smtp.port, config.smtp.host)
|
2013-12-08 03:56:03 +04:00
|
|
|
|
2017-03-23 08:51:18 +03:00
|
|
|
// HTTP half
|
2013-12-08 03:56:03 +04:00
|
|
|
|
2017-03-23 08:51:18 +03:00
|
|
|
var hapi = require('hapi')
|
2018-07-11 16:19:05 +03:00
|
|
|
var api = new hapi.Server({
|
2017-03-23 08:51:18 +03:00
|
|
|
host: config.smtp.api.host,
|
|
|
|
port: config.smtp.api.port
|
|
|
|
})
|
2013-12-08 03:56:03 +04:00
|
|
|
|
2017-03-23 08:51:18 +03:00
|
|
|
function loop(email, cb) {
|
|
|
|
var mail = users[email]
|
|
|
|
if (! mail) {
|
|
|
|
return setTimeout(loop.bind(null, email, cb), 50)
|
2013-12-17 09:36:42 +04:00
|
|
|
}
|
2017-03-23 08:51:18 +03:00
|
|
|
cb(mail)
|
2013-12-08 03:56:03 +04:00
|
|
|
}
|
|
|
|
|
2017-03-23 08:51:18 +03:00
|
|
|
api.route(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
method: 'GET',
|
|
|
|
path: '/mail/{email}',
|
2018-07-11 16:19:05 +03:00
|
|
|
handler: async function (request) {
|
|
|
|
const emailLoop = function () {
|
|
|
|
return new P((resolve) => {
|
|
|
|
loop(
|
|
|
|
decodeURIComponent(request.params.email),
|
|
|
|
function (emailData) {
|
|
|
|
resolve(emailData)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return emailLoop().then((emailData) => {
|
|
|
|
return emailData;
|
|
|
|
})
|
2017-03-23 08:51:18 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
method: 'DELETE',
|
|
|
|
path: '/mail/{email}',
|
2018-07-11 16:19:05 +03:00
|
|
|
handler: async function (request) {
|
2017-03-23 08:51:18 +03:00
|
|
|
delete users[decodeURIComponent(request.params.email)]
|
2018-07-11 16:19:05 +03:00
|
|
|
return {}
|
2017-03-23 08:51:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2018-07-11 16:19:05 +03:00
|
|
|
api.start().then(() => {
|
2017-03-23 08:51:18 +03:00
|
|
|
console.log('mail_helper started...')
|
|
|
|
|
2018-07-11 16:19:05 +03:00
|
|
|
return resolve({
|
2017-03-23 08:51:18 +03:00
|
|
|
close() {
|
|
|
|
return new P((resolve, reject) => {
|
|
|
|
let smtpClosed = false
|
|
|
|
let apiClosed = false
|
|
|
|
smtp.server.end(() => {
|
|
|
|
smtpClosed = true
|
|
|
|
if (apiClosed) {
|
|
|
|
resolve()
|
|
|
|
}
|
|
|
|
})
|
2018-07-11 16:19:05 +03:00
|
|
|
api.stop().then(() => {
|
2017-03-23 08:51:18 +03:00
|
|
|
apiClosed = true
|
|
|
|
if (smtpClosed) {
|
|
|
|
resolve()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2017-03-24 02:34:15 +03:00
|
|
|
|
|
|
|
if (require.main === module) {
|
|
|
|
module.exports(true)
|
|
|
|
}
|