fxa-auth-server/scripts/e2e-email/index.js

239 строки
6.3 KiB
JavaScript
Executable File

#!/usr/bin/env node
/* 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/. */
const crypto = require('crypto')
const commander = require('commander')
const P = require('../../lib/promise')
const Client = require('../../test/client')()
const mailbox = require('../../test/mailbox')
const validateEmail = require('./validate-email')
const emailMessages = {}
var program
function configure() {
commander
.option('-a, --auth-server [url]',
'URL of FxA Auth Server',
'https://api-accounts.stage.mozaws.net')
.option('-l, --locales [path]',
'Path to file with a list of locales to test',
'../../config/supportedLanguages.js')
.option('-r, --restmail-domain [fqdn]',
'URL of the restmail server',
'restmail.net')
.option('-L, --locale <en[,zh-TW,de,...]>',
'Test only this csv list of locales',
function(list) {
return list.split(/,/)
})
.parse(process.argv)
commander.basename = crypto.randomBytes(8).toString('hex')
commander.password = crypto.randomBytes(16).toString('hex')
commander.supportedLanguages = commander.locale ||
require(commander.locales).slice(0)
var mailserver = commander.mailserver = mailbox(commander.restmailDomain, 80)
mailserver.eventEmitter.on('email:message', function(email, message) {
emailMessages[email] = emailMessages[email] || []
emailMessages[email].push(message)
})
mailserver.eventEmitter.on('email:error', function(email, error) {
emailMessages[email] = emailMessages[email] || []
emailMessages[email].push(error)
})
return commander
}
function log(level /*, rest */) {
if (level < log.level) return
var args = Array.prototype.slice.call(arguments)
var timestamp = '[' + new Date().toISOString() + ']'
args[0] = timestamp
console.log.apply(null, args)
}
log.ERROR = 3
log.INFO = 2
log.DEBUG = 1
log.level = log.INFO
function emailFromLang(lang) {
return program.basename + '-' + lang + '@' + program.restmailDomain
}
function langFromEmail(email) {
// is like 'deadbeef-es@...' or 'deadbeef-es-AR@...'
return email.split('@')[0].match(/^[^-]*-([^-]*(?:-[^-]*)?)/)[1]
}
/*
- signup for service sync
- signin as if second device
- change the password
- trigger a password reset
With the collected emails:
- CHECK that I get a signup email
- CHECK that I get a notification email of a second device
- CHECK that I get a notification email of a password change
- CHECK that I get a password reset email
- CHECK that I get a notification email of a password reset
*/
function signupForSync(lang) {
var email = emailFromLang(lang)
var options = {
service: 'sync',
keys: true,
lang: lang
}
return Client.createAndVerify(program.authServer,
email,
program.password,
program.mailserver,
options)
}
function signinAsSecondDevice(client) {
var email = client.email
var password = program.password
var opts = {
service: 'sync',
keys: true,
reason: 'signin',
lang: client.options.lang
}
return Client.login(program.authServer, email, password, opts)
.then(function(client) {
return client.keys()
.then(function () {
return fetchNotificationEmail(client)
})
})
}
function changePassword(client) {
var email = client.email
var password = program.password
var lang = langFromEmail(email)
var headers = {
'accept-language': lang
}
return client.changePassword(password, headers, client.sessionToken)
.then(function () {
return fetchNotificationEmail(client)
})
}
function passwordReset(client) {
var email = client.email
var lang = langFromEmail(email)
var headers = {
'accept-language': lang
}
return client.forgotPassword(lang)
.then(function () {
return program.mailserver.waitForCode(email)
})
.then(function (code) {
return client.verifyPasswordResetCode(code, headers)
})
.then(function() {
return client.resetPassword(program.password, headers)
})
.then(function () {
return fetchNotificationEmail(client)
})
}
function fetchNotificationEmail(client) {
// Gather the notification email that was just sent for (new-device-added,
// password-change, password-reset).
return program.mailserver.waitForEmail(client.email)
.then(function () {
return client
})
}
function checkLocale(lang, index) {
// AWS SES in `stage` has rate-limiting of 5/sec, so start slow.
var delay = index * 750
return P.delay(delay)
.then(function() {
log(log.INFO, 'Starting', lang)
return signupForSync(lang)
.then(signinAsSecondDevice)
.then(changePassword)
.then(passwordReset)
})
}
function dumpMessages(messages) {
console.log('---')
console.log('--- Dumping messages ---')
console.log('---')
Object.keys(messages)
.map(function(key) {
console.log('--- %s ---', key)
emailMessages[key]
.map(function(email) {
console.log(email.to[0], email.subject)
})
})
}
function main() {
program = configure()
var checks = program.supportedLanguages.map(checkLocale)
P.all(checks)
.then(function() {
if (process.env.DEBUG) {
dumpMessages(emailMessages)
}
var errors = validateEmail(emailMessages, log)
var output = []
var errorCount = 0
Object.keys(errors).sort().forEach(function(lang) {
output.push(' ' + lang + ':')
var errorList = errors[lang]
errorList.forEach(function(err) {
errorCount++
output.push(' ' + err)
})
})
if (errorCount > 0) {
console.log('\nLocalization or other email errors found. However, some untranslated')
console.log('locales are listed in ./localeQuirks to get the full state.\n')
console.log(output.join('\n'))
process.exit(1)
} else {
console.log('\nAll strings expected to be translated are ok.\n')
process.exit(0)
}
}).catch(function(err) {
log(log.ERROR, err.stack || err)
process.exit(1)
})
}
main()