diff --git a/spec/ValidationAndPasswordsReset.spec.js b/spec/ValidationAndPasswordsReset.spec.js index e953204931..cac3c56cfd 100644 --- a/spec/ValidationAndPasswordsReset.spec.js +++ b/spec/ValidationAndPasswordsReset.spec.js @@ -1,7 +1,9 @@ "use strict"; -var request = require('request'); -var Config = require("../src/Config"); +let MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions'); +let request = require('request'); +let Config = require("../src/Config"); + describe("Custom Pages Configuration", () => { it("should set the custom pages", (done) => { setServerConfiguration({ @@ -62,7 +64,7 @@ describe("Email Verification", () => { var user = new Parse.User(); user.setPassword("asdf"); user.setUsername("zxcv"); - user.setEmail('cool_guy@parse.com'); + user.setEmail('testIfEnabled@parse.com'); user.signUp(null, { success: function(user) { expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled(); @@ -150,7 +152,7 @@ describe("Email Verification", () => { expect(emailAdapter.sendVerificationEmail).not.toHaveBeenCalled(); user.fetch() .then((user) => { - user.set("email", "cool_guy@parse.com"); + user.set("email", "testWhenUpdating@parse.com"); return user.save(); }).then((user) => { return user.fetch(); @@ -204,7 +206,7 @@ describe("Email Verification", () => { expect(emailAdapter.sendVerificationEmail).not.toHaveBeenCalled(); user.fetch() .then((user) => { - user.set("email", "cool_guy@parse.com"); + user.set("email", "testValidLinkWhenUpdating@parse.com"); return user.save(); }).then((user) => { return user.fetch(); @@ -228,7 +230,7 @@ describe("Email Verification", () => { var calls = 0; var emailAdapter = { sendMail: function(options){ - expect(options.to).toBe('cool_guy@parse.com'); + expect(options.to).toBe('testSendSimpleAdapter@parse.com'); if (calls == 0) { expect(options.subject).toEqual('Please verify your e-mail for My Cool App'); expect(options.text.match(/verify_email/)).not.toBe(null); @@ -258,7 +260,7 @@ describe("Email Verification", () => { var user = new Parse.User(); user.setPassword("asdf"); user.setUsername("zxcv"); - user.set("email", "cool_guy@parse.com"); + user.set("email", "testSendSimpleAdapter@parse.com"); user.signUp(null, { success: function(user) { expect(calls).toBe(1); @@ -266,7 +268,7 @@ describe("Email Verification", () => { .then((user) => { return user.save(); }).then((user) => { - return Parse.User.requestPasswordReset("cool_guy@parse.com").catch((err) => { + return Parse.User.requestPasswordReset("testSendSimpleAdapter@parse.com").catch((err) => { fail('Should not fail requesting a password'); done(); }) @@ -282,6 +284,42 @@ describe("Email Verification", () => { }); }); + it('fails if you include an emailAdapter, set verifyUserEmails to false, dont set a publicServerURL, and try to send a password reset email (regression test for #1649)', done => { + setServerConfiguration({ + serverURL: 'http://localhost:8378/1', + appId: 'test', + appName: 'unused', + javascriptKey: 'test', + dotNetKey: 'windows', + clientKey: 'client', + restAPIKey: 'rest', + masterKey: 'test', + collectionPrefix: 'test_', + fileKey: 'test', + verifyUserEmails: false, + emailAdapter: MockEmailAdapterWithOptions({ + fromAddress: 'parse@example.com', + apiKey: 'k', + domain: 'd', + }), + }) + + let user = new Parse.User(); + user.setPassword("asdf"); + user.setUsername("zxcv"); + user.set("email", "testInvalidConfig@parse.com"); + user.signUp(null) + .then(user => Parse.User.requestPasswordReset("testInvalidConfig@parse.com")) + .then(result => { + console.log(result); + fail('sending password reset email should not have succeeded'); + done(); + }, error => { + expect(error.message).toEqual('An appName, publicServerURL, and emailAdapter are required for password reset functionality.') + done(); + }); + }); + it('does not send verification email if email verification is disabled', done => { var emailAdapter = { sendVerificationEmail: () => Promise.resolve(), diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index adba752f83..1d73359eb0 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -1,7 +1,7 @@ // These methods handle the User-related routes. import deepcopy from 'deepcopy'; - +import Config from '../Config'; import ClassesRouter from './ClassesRouter'; import PromiseRouter from '../PromiseRouter'; import rest from '../rest'; @@ -155,19 +155,36 @@ export class UsersRouter extends ClassesRouter { } handleResetRequest(req) { - let { email } = req.body; - if (!email) { - throw new Parse.Error(Parse.Error.EMAIL_MISSING, "you must provide an email"); - } - let userController = req.config.userController; - - return userController.sendPasswordResetEmail(email).then((token) => { - return Promise.resolve({ - response: {} - }); - }, (err) => { - throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, `no user found with email ${email}`); - }); + try { + Config.validateEmailConfiguration({ + verifyUserEmails: true, //A bit of a hack, as this isn't the intended purpose of this parameter + appName: req.config.appName, + publicServerURL: req.config.publicServerURL, + }); + } catch (e) { + if (typeof e === 'string') { + // Maybe we need a Bad Configuration error, but the SDKs won't understand it. For now, Internal Server Error. + throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'An appName, publicServerURL, and emailAdapter are required for password reset functionality.'); + } else { + throw e; + } + } + let { email } = req.body; + if (!email) { + throw new Parse.Error(Parse.Error.EMAIL_MISSING, "you must provide an email"); + } + let userController = req.config.userController; + return userController.sendPasswordResetEmail(email).then(token => { + return Promise.resolve({ + response: {} + }); + }, err => { + if (err.code === Parse.Error.OBJECT_NOT_FOUND) { + throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, `No user found with email ${email}.`); + } else { + throw err; + } + }); }