Adds ability to prevent login with unverified emails (#2175)
This commit is contained in:
committed by
Florent Vilmart
parent
b641712d4d
commit
08c63f324a
@@ -209,6 +209,11 @@ var server = ParseServer({
|
||||
...otherOptions,
|
||||
// Enable email verification
|
||||
verifyUserEmails: true,
|
||||
|
||||
// set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
|
||||
// set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
|
||||
preventLoginWithUnverifiedEmail: false, // defaults to false
|
||||
|
||||
// The public URL of your app.
|
||||
// This will appear in the link that is used to verify email addresses and reset passwords.
|
||||
// Set the mount path as it is in serverURL
|
||||
|
||||
@@ -238,6 +238,129 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true', done => {
|
||||
reconfigureServer({
|
||||
appName: 'test',
|
||||
publicServerURL: 'http://localhost:1337/1',
|
||||
verifyUserEmails: true,
|
||||
preventLoginWithUnverifiedEmail: true,
|
||||
emailAdapter: MockEmailAdapterWithOptions({
|
||||
fromAddress: 'parse@example.com',
|
||||
apiKey: 'k',
|
||||
domain: 'd',
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
let user = new Parse.User();
|
||||
user.setPassword("asdf");
|
||||
user.setUsername("zxcv");
|
||||
user.set("email", "testInvalidConfig@parse.com");
|
||||
user.signUp(null)
|
||||
.then(user => Parse.User.logIn("zxcv", "asdf"))
|
||||
.then(result => {
|
||||
fail('login should have failed');
|
||||
done();
|
||||
}, error => {
|
||||
expect(error.message).toEqual('User email is not verified.')
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
fail(JSON.stringify(error));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => {
|
||||
var user = new Parse.User();
|
||||
var sendEmailOptions;
|
||||
var emailAdapter = {
|
||||
sendVerificationEmail: options => {
|
||||
sendEmailOptions = options;
|
||||
},
|
||||
sendPasswordResetEmail: () => Promise.resolve(),
|
||||
sendMail: () => {}
|
||||
}
|
||||
reconfigureServer({
|
||||
appName: 'emailing app',
|
||||
verifyUserEmails: true,
|
||||
preventLoginWithUnverifiedEmail: true,
|
||||
emailAdapter: emailAdapter,
|
||||
publicServerURL: "http://localhost:8378/1"
|
||||
})
|
||||
.then(() => {
|
||||
user.setPassword("other-password");
|
||||
user.setUsername("user");
|
||||
user.set('email', 'user@parse.com');
|
||||
return user.signUp();
|
||||
}).then(() => {
|
||||
expect(sendEmailOptions).not.toBeUndefined();
|
||||
request.get(sendEmailOptions.link, {
|
||||
followRedirect: false,
|
||||
}, (error, response, body) => {
|
||||
expect(response.statusCode).toEqual(302);
|
||||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user');
|
||||
user.fetch()
|
||||
.then(() => {
|
||||
expect(user.get('emailVerified')).toEqual(true);
|
||||
|
||||
Parse.User.logIn("user", "other-password")
|
||||
.then(user => {
|
||||
expect(typeof user).toBe('object');
|
||||
expect(user.get('emailVerified')).toBe(true);
|
||||
done();
|
||||
}, error => {
|
||||
fail('login should have succeeded');
|
||||
done();
|
||||
});
|
||||
}, (err) => {
|
||||
console.error(err);
|
||||
fail("this should not fail");
|
||||
done();
|
||||
}).catch((err) =>
|
||||
{
|
||||
console.error(err);
|
||||
fail(err);
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => {
|
||||
reconfigureServer({
|
||||
appName: 'test',
|
||||
publicServerURL: 'http://localhost:1337/1',
|
||||
verifyUserEmails: true,
|
||||
preventLoginWithUnverifiedEmail: false,
|
||||
emailAdapter: MockEmailAdapterWithOptions({
|
||||
fromAddress: 'parse@example.com',
|
||||
apiKey: 'k',
|
||||
domain: 'd',
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
let user = new Parse.User();
|
||||
user.setPassword("asdf");
|
||||
user.setUsername("zxcv");
|
||||
user.set("email", "testInvalidConfig@parse.com");
|
||||
user.signUp(null)
|
||||
.then(user => Parse.User.logIn("zxcv", "asdf"))
|
||||
.then(user => {
|
||||
expect(typeof user).toBe('object');
|
||||
expect(user.get('emailVerified')).toBe(false);
|
||||
done();
|
||||
}, error => {
|
||||
fail('login should have succeeded');
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
fail(JSON.stringify(error));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => {
|
||||
reconfigureServer({
|
||||
appName: undefined,
|
||||
|
||||
@@ -36,6 +36,7 @@ export class Config {
|
||||
this.serverURL = cacheInfo.serverURL;
|
||||
this.publicServerURL = removeTrailingSlash(cacheInfo.publicServerURL);
|
||||
this.verifyUserEmails = cacheInfo.verifyUserEmails;
|
||||
this.preventLoginWithUnverifiedEmail = cacheInfo.preventLoginWithUnverifiedEmail;
|
||||
this.appName = cacheInfo.appName;
|
||||
|
||||
this.cacheController = cacheInfo.cacheController;
|
||||
|
||||
@@ -117,6 +117,7 @@ class ParseServer {
|
||||
serverURL = requiredParameter('You must provide a serverURL!'),
|
||||
maxUploadSize = '20mb',
|
||||
verifyUserEmails = false,
|
||||
preventLoginWithUnverifiedEmail = false,
|
||||
cacheAdapter,
|
||||
emailAdapter,
|
||||
publicServerURL,
|
||||
@@ -231,6 +232,7 @@ class ParseServer {
|
||||
hooksController: hooksController,
|
||||
userController: userController,
|
||||
verifyUserEmails: verifyUserEmails,
|
||||
preventLoginWithUnverifiedEmail: preventLoginWithUnverifiedEmail,
|
||||
allowClientClassCreation: allowClientClassCreation,
|
||||
authDataManager: authDataManager(oauth, enableAnonymousUsers),
|
||||
appName: appName,
|
||||
|
||||
@@ -83,6 +83,11 @@ export class UsersRouter extends ClassesRouter {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
|
||||
}
|
||||
user = results[0];
|
||||
|
||||
if (req.config.verifyUserEmails && req.config.preventLoginWithUnverifiedEmail && !user.emailVerified) {
|
||||
throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.');
|
||||
}
|
||||
|
||||
return passwordCrypto.compare(req.body.password, user.password);
|
||||
}).then((correct) => {
|
||||
|
||||
|
||||
@@ -146,6 +146,11 @@ export default {
|
||||
help: "Enable (or disable) user email validation, defaults to false",
|
||||
action: booleanParser
|
||||
},
|
||||
"preventLoginWithUnverifiedEmail": {
|
||||
env: "PARSE_SERVER_PREVENT_LOGIN_WITH_UNVERIFIED_EMAIL",
|
||||
help: "Prevent user from login if email is not verified and PARSE_SERVER_VERIFY_USER_EMAILS is true, defaults to false",
|
||||
action: booleanParser
|
||||
},
|
||||
"appName": {
|
||||
env: "PARSE_SERVER_APP_NAME",
|
||||
help: "Sets the app name"
|
||||
|
||||
Reference in New Issue
Block a user