fix: Conditional email verification not working in some cases if verifyUserEmails, preventLoginWithUnverifiedEmail set to functions (#8838)
This commit is contained in:
@@ -389,7 +389,7 @@ describe('Email Verification Token Expiration: ', () => {
|
|||||||
await user2.signUp();
|
await user2.signUp();
|
||||||
expect(user2.getSessionToken()).toBeUndefined();
|
expect(user2.getSessionToken()).toBeUndefined();
|
||||||
expect(sendEmailOptions).toBeDefined();
|
expect(sendEmailOptions).toBeDefined();
|
||||||
expect(verifySpy).toHaveBeenCalledTimes(4);
|
expect(verifySpy).toHaveBeenCalledTimes(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can conditionally send user email verification', async () => {
|
it('can conditionally send user email verification', async () => {
|
||||||
|
|||||||
@@ -242,6 +242,31 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('prevents user from signup and login if email is not verified and preventLoginWithUnverifiedEmail is set to function returning true', async () => {
|
||||||
|
await reconfigureServer({
|
||||||
|
appName: 'test',
|
||||||
|
publicServerURL: 'http://localhost:1337/1',
|
||||||
|
verifyUserEmails: async () => true,
|
||||||
|
preventLoginWithUnverifiedEmail: async () => true,
|
||||||
|
preventSignupWithUnverifiedEmail: true,
|
||||||
|
emailAdapter: MockEmailAdapterWithOptions({
|
||||||
|
fromAddress: 'parse@example.com',
|
||||||
|
apiKey: 'k',
|
||||||
|
domain: 'd',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = new Parse.User();
|
||||||
|
user.setPassword('asdf');
|
||||||
|
user.setUsername('zxcv');
|
||||||
|
user.set('email', 'testInvalidConfig@parse.com');
|
||||||
|
const signupRes = await user.signUp(null).catch(e => e);
|
||||||
|
expect(signupRes.message).toEqual('User email is not verified.');
|
||||||
|
|
||||||
|
const loginRes = await Parse.User.logIn('zxcv', 'asdf').catch(e => e);
|
||||||
|
expect(loginRes.message).toEqual('User email is not verified.');
|
||||||
|
});
|
||||||
|
|
||||||
it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', async () => {
|
it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', async () => {
|
||||||
let sendEmailOptions;
|
let sendEmailOptions;
|
||||||
const emailAdapter = {
|
const emailAdapter = {
|
||||||
|
|||||||
@@ -36,11 +36,10 @@ export class UserController extends AdaptableController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setEmailVerifyToken(user, req, storage = {}) {
|
async setEmailVerifyToken(user, req, storage = {}) {
|
||||||
let shouldSendEmail = this.shouldVerifyEmails;
|
const shouldSendEmail =
|
||||||
if (typeof shouldSendEmail === 'function') {
|
this.shouldVerifyEmails === true ||
|
||||||
const response = await Promise.resolve(shouldSendEmail(req));
|
(typeof this.shouldVerifyEmails === 'function' &&
|
||||||
shouldSendEmail = response !== false;
|
(await Promise.resolve(this.shouldVerifyEmails(req))) === true);
|
||||||
}
|
|
||||||
if (!shouldSendEmail) {
|
if (!shouldSendEmail) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -930,31 +930,25 @@ RestWrite.prototype.createSessionTokenIfNeeded = async function () {
|
|||||||
if (this.auth.user && this.data.authData) {
|
if (this.auth.user && this.data.authData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
// If sign-up call
|
||||||
!this.storage.authProvider && // signup call, with
|
if (!this.storage.authProvider) {
|
||||||
this.config.preventLoginWithUnverifiedEmail === true && // no login without verification
|
// Create request object for verification functions
|
||||||
this.config.verifyUserEmails
|
const { originalObject, updatedObject } = this.buildParseObjects();
|
||||||
) {
|
const request = {
|
||||||
// verification is on
|
original: originalObject,
|
||||||
this.storage.rejectSignup = true;
|
object: updatedObject,
|
||||||
return;
|
master: this.auth.isMaster,
|
||||||
}
|
ip: this.config.ip,
|
||||||
if (!this.storage.authProvider && this.config.verifyUserEmails) {
|
installationId: this.auth.installationId,
|
||||||
let shouldPreventUnverifedLogin = this.config.preventLoginWithUnverifiedEmail;
|
};
|
||||||
if (typeof this.config.preventLoginWithUnverifiedEmail === 'function') {
|
// Get verification conditions which can be booleans or functions; the purpose of this async/await
|
||||||
const { originalObject, updatedObject } = this.buildParseObjects();
|
// structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the
|
||||||
const request = {
|
// conditional statement below, as a developer may decide to execute expensive operations in them
|
||||||
original: originalObject,
|
const verifyUserEmails = async () => this.config.verifyUserEmails === true || (typeof this.config.verifyUserEmails === 'function' && await Promise.resolve(this.config.verifyUserEmails(request)) === true);
|
||||||
object: updatedObject,
|
const preventLoginWithUnverifiedEmail = async () => this.config.preventLoginWithUnverifiedEmail === true || (typeof this.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(this.config.preventLoginWithUnverifiedEmail(request)) === true);
|
||||||
master: this.auth.isMaster,
|
// If verification is required
|
||||||
ip: this.config.ip,
|
if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail()) {
|
||||||
installationId: this.auth.installationId,
|
this.storage.rejectSignup = true;
|
||||||
};
|
|
||||||
shouldPreventUnverifedLogin = await Promise.resolve(
|
|
||||||
this.config.preventLoginWithUnverifiedEmail(request)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (shouldPreventUnverifedLogin === true) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export class UsersRouter extends ClassesRouter {
|
|||||||
const accountLockoutPolicy = new AccountLockout(user, req.config);
|
const accountLockoutPolicy = new AccountLockout(user, req.config);
|
||||||
return accountLockoutPolicy.handleLoginAttempt(isValidPassword);
|
return accountLockoutPolicy.handleLoginAttempt(isValidPassword);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(async () => {
|
||||||
if (!isValidPassword) {
|
if (!isValidPassword) {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
|
||||||
}
|
}
|
||||||
@@ -137,11 +137,18 @@ export class UsersRouter extends ClassesRouter {
|
|||||||
if (!req.auth.isMaster && user.ACL && Object.keys(user.ACL).length == 0) {
|
if (!req.auth.isMaster && user.ACL && Object.keys(user.ACL).length == 0) {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
|
||||||
}
|
}
|
||||||
if (
|
// Create request object for verification functions
|
||||||
req.config.verifyUserEmails &&
|
const request = {
|
||||||
req.config.preventLoginWithUnverifiedEmail &&
|
master: req.auth.isMaster,
|
||||||
!user.emailVerified
|
ip: req.config.ip,
|
||||||
) {
|
installationId: req.auth.installationId,
|
||||||
|
};
|
||||||
|
// Get verification conditions which can be booleans or functions; the purpose of this async/await
|
||||||
|
// structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the
|
||||||
|
// conditional statement below, as a developer may decide to execute expensive operations in them
|
||||||
|
const verifyUserEmails = async () => req.config.verifyUserEmails === true || (typeof req.config.verifyUserEmails === 'function' && await Promise.resolve(req.config.verifyUserEmails(request)) === true);
|
||||||
|
const preventLoginWithUnverifiedEmail = async () => req.config.preventLoginWithUnverifiedEmail === true || (typeof req.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(req.config.preventLoginWithUnverifiedEmail(request)) === true);
|
||||||
|
if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail() && !user.emailVerified) {
|
||||||
throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.');
|
throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user