From 4325eb0aabf2c7b6a50efbf070b5ac586f293ec2 Mon Sep 17 00:00:00 2001 From: Vijay Budhram Date: Wed, 20 Sep 2017 11:36:03 -0400 Subject: [PATCH] feat(email): Throw error when attempting to resend email code for email that doesn't belong to account (#2129), r=philbooth --- docs/api.md | 13 +++++++- lib/error.js | 10 +++++++ lib/routes/emails.js | 5 ++++ .../recovery_email_resend_code_tests.js | 30 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 1be58325..5b67aca8 100644 --- a/docs/api.md +++ b/docs/api.md @@ -253,6 +253,8 @@ for `code` and `errno` are: Can not change primary email to an email that does not belong to this account * `code: 400, errno: 149`: This email can not currently be used to login +* `code: 400, errno: 150`: + Can not resend email code to an email that does not belong to this account * `code: 503, errno: 201`: Service unavailable * `code: 503, errno: 202`: @@ -349,7 +351,7 @@ those common validations are defined here. * `pushCallback`: isA.string.uri({ scheme: 'https' }).regex(PUSH_SERVER_REGEX).max(255).allow('') * `pushPublicKey`: isA.string.max(88).regex(URL_SAFE_BASE_64).allow('') * `pushAuthKey`: isA.string.max(24).regex(URL_SAFE_BASE_64).allow('') - * `pushEndpointExpired`: isA.boolean + * `pushEndpointExpired`: isA.boolean.strict } @@ -1395,6 +1397,15 @@ as a query parameter. +##### Error responses + +Failing requests may be caused +by the following errors +(this is not an exhaustive list): + +* `code: 400, errno: 150`: + Can not resend email code to an email that does not belong to this account + #### POST /recovery_email/verify_code diff --git a/lib/error.js b/lib/error.js index fc99807a..9b4b1945 100644 --- a/lib/error.js +++ b/lib/error.js @@ -59,6 +59,7 @@ var ERRNO = { CHANGE_EMAIL_TO_UNVERIFIED_EMAIL: 147, CHANGE_EMAIL_TO_UNOWNED_EMAIL: 148, LOGIN_WITH_INVALID_EMAIL: 149, + RESEND_EMAIL_CODE_TO_UNOWNED_EMAIL: 150, SERVER_BUSY: 201, FEATURE_NOT_ENABLED: 202, @@ -705,6 +706,15 @@ AppError.cannotLoginWithEmail = function () { }) } +AppError.cannotResendEmailCodeToUnownedEmail = function () { + return new AppError({ + code: 400, + error: 'Bad Request', + errno: ERRNO.RESEND_EMAIL_CODE_TO_UNOWNED_EMAIL, + message: 'Can not resend email code to an email that does not belong to this account' + }) +} + AppError.unexpectedError = () => { return new AppError({}) } diff --git a/lib/routes/emails.js b/lib/routes/emails.js index 3f71f3c5..32effbb0 100644 --- a/lib/routes/emails.js +++ b/lib/routes/emails.js @@ -226,6 +226,11 @@ module.exports = (log, db, mailer, config, customs, push) => { } }) + // This user is attempting to verify a secondary email that doesn't belong to the account. + if (emails.length === 0) { + throw error.cannotResendEmailCodeToUnownedEmail() + } + // Don't resend code for already verified emails if (emailVerified) { return reply({}) diff --git a/test/remote/recovery_email_resend_code_tests.js b/test/remote/recovery_email_resend_code_tests.js index 03f90e4b..7f13d7a5 100644 --- a/test/remote/recovery_email_resend_code_tests.js +++ b/test/remote/recovery_email_resend_code_tests.js @@ -7,6 +7,7 @@ const assert = require('insist') const Client = require('../client')() var TestServer = require('../test_server') +const P = require('../../lib/promise') var config = require('../../config').getProperties() @@ -147,6 +148,35 @@ describe('remote recovery email resend code', function() { } ) + it('fail when resending verification email when not owned by account', () => { + const email = server.uniqueEmail() + const secondEmail = server.uniqueEmail() + const password = 'something' + let client = null + const options = { + keys: true + } + return P.all([ + Client.createAndVerify(config.publicUrl, email, password, server.mailbox, options), + Client.create(config.publicUrl, secondEmail, password, server.mailbox, options) + ]) + .then((res) => { + // Login with `email` and attempt to resend verification code for `secondEmail` + client = res[0] + client.options = { + email: secondEmail + } + return client.requestVerifyEmail() + .then(() => { + assert.fail('Should not have succeeded in sending verification code') + }) + }) + .catch((err) => { + assert.equal(err.code, 400) + assert.equal(err.errno, 150) + }) + }) + after(() => { return TestServer.stop(server) })