Skip to content

Commit bfb96e2

Browse files
committed
Update tests
1 parent 4a6eb57 commit bfb96e2

File tree

5 files changed

+96
-128
lines changed

5 files changed

+96
-128
lines changed

spec/EmailVerificationToken.spec.js

Lines changed: 47 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -604,11 +604,9 @@ describe('Email Verification Token Expiration: ', () => {
604604
});
605605
});
606606

607-
it('should match codes with emailVerifyTokenReuseIfValid', done => {
608-
const user = new Parse.User();
607+
it('should match codes with emailVerifyTokenReuseIfValid', async done => {
609608
let sendEmailOptions;
610609
let sendVerificationEmailCallCount = 0;
611-
let userBeforeRequest;
612610
const emailAdapter = {
613611
sendVerificationEmail: options => {
614612
sendEmailOptions = options;
@@ -617,72 +615,58 @@ describe('Email Verification Token Expiration: ', () => {
617615
sendPasswordResetEmail: () => Promise.resolve(),
618616
sendMail: () => {},
619617
};
620-
reconfigureServer({
618+
await reconfigureServer({
621619
appName: 'emailVerifyToken',
622620
verifyUserEmails: true,
623621
emailAdapter: emailAdapter,
624622
emailVerifyTokenValidityDuration: 5 * 60, // 5 minutes
625623
publicServerURL: 'http://localhost:8378/1',
626624
emailVerifyTokenReuseIfValid: true,
627-
})
628-
.then(() => {
629-
user.setUsername('resends_verification_token');
630-
user.setPassword('expiringToken');
631-
user.set('email', '[email protected]');
632-
return user.signUp();
633-
})
634-
.then(() => {
635-
const config = Config.get('test');
636-
return config.database
637-
.find('_User', { username: 'resends_verification_token' })
638-
.then(results => {
639-
return results[0];
640-
});
641-
})
642-
.then(newUser => {
643-
// store this user before we make our email request
644-
userBeforeRequest = newUser;
645-
expect(sendVerificationEmailCallCount).toBe(1);
646-
647-
return request({
648-
url: 'http://localhost:8378/1/verificationEmailRequest',
649-
method: 'POST',
650-
body: {
651-
652-
},
653-
headers: {
654-
'X-Parse-Application-Id': Parse.applicationId,
655-
'X-Parse-REST-API-Key': 'rest',
656-
'Content-Type': 'application/json',
657-
},
658-
});
659-
})
660-
.then(response => {
661-
expect(response.status).toBe(200);
662-
expect(sendVerificationEmailCallCount).toBe(2);
663-
expect(sendEmailOptions).toBeDefined();
664-
665-
// query for this user again
666-
const config = Config.get('test');
667-
return config.database
668-
.find('_User', { username: 'resends_verification_token' })
669-
.then(results => {
670-
return results[0];
671-
});
672-
})
673-
.then(userAfterRequest => {
674-
// verify that our token & expiration has been changed for this new request
675-
expect(typeof userAfterRequest).toBe('object');
676-
expect(userBeforeRequest._email_verify_token).toEqual(userAfterRequest._email_verify_token);
677-
expect(userBeforeRequest._email_verify_token_expires_at).toEqual(
678-
userAfterRequest._email_verify_token_expires_at
679-
);
680-
done();
681-
})
682-
.catch(error => {
683-
jfail(error);
684-
done();
685-
});
625+
});
626+
const user = new Parse.User();
627+
user.setUsername('resends_verification_token');
628+
user.setPassword('expiringToken');
629+
user.set('email', '[email protected]');
630+
await user.signUp();
631+
632+
const config = Config.get('test');
633+
const [userBeforeRequest] = await config.database.find('_User', {
634+
username: 'resends_verification_token',
635+
});
636+
// store this user before we make our email request
637+
expect(sendVerificationEmailCallCount).toBe(1);
638+
await new Promise(resolve => {
639+
setTimeout(() => {
640+
resolve();
641+
}, 1000);
642+
});
643+
const response = await request({
644+
url: 'http://localhost:8378/1/verificationEmailRequest',
645+
method: 'POST',
646+
body: {
647+
648+
},
649+
headers: {
650+
'X-Parse-Application-Id': Parse.applicationId,
651+
'X-Parse-REST-API-Key': 'rest',
652+
'Content-Type': 'application/json',
653+
},
654+
});
655+
expect(response.status).toBe(200);
656+
expect(sendVerificationEmailCallCount).toBe(2);
657+
expect(sendEmailOptions).toBeDefined();
658+
659+
const [userAfterRequest] = await config.database.find('_User', {
660+
username: 'resends_verification_token',
661+
});
662+
663+
// verify that our token & expiration has been changed for this new request
664+
expect(typeof userAfterRequest).toBe('object');
665+
expect(userBeforeRequest._email_verify_token).toEqual(userAfterRequest._email_verify_token);
666+
expect(userBeforeRequest._email_verify_token_expires_at).toEqual(
667+
userAfterRequest._email_verify_token_expires_at
668+
);
669+
done();
686670
});
687671

688672
it('should not send a new verification email when a resend is requested and the user is VERIFIED', done => {

spec/PasswordPolicy.spec.js

Lines changed: 24 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ describe('Password Policy: ', () => {
122122
});
123123
});
124124

125-
it('should not keep reset token', done => {
126-
const user = new Parse.User();
125+
it('should not keep reset token by default', async done => {
127126
const sendEmailOptions = [];
128127
const emailAdapter = {
129128
sendVerificationEmail: () => Promise.resolve(),
@@ -132,46 +131,26 @@ describe('Password Policy: ', () => {
132131
},
133132
sendMail: () => {},
134133
};
135-
reconfigureServer({
134+
await reconfigureServer({
136135
appName: 'passwordPolicy',
137136
emailAdapter: emailAdapter,
138137
passwordPolicy: {
139138
resetTokenValidityDuration: 5 * 60, // 5 minutes
140139
},
141140
publicServerURL: 'http://localhost:8378/1',
142-
})
143-
.then(() => {
144-
user.setUsername('testResetTokenValidity');
145-
user.setPassword('original');
146-
user.set('email', '[email protected]');
147-
return user.signUp();
148-
})
149-
.then(() => {
150-
return Parse.User.requestPasswordReset('[email protected]').catch(err => {
151-
jfail(err);
152-
fail('Reset password request should not fail');
153-
done();
154-
});
155-
})
156-
.then(() => {
157-
return Parse.User.requestPasswordReset('[email protected]').catch(err => {
158-
jfail(err);
159-
fail('Reset password request should not fail');
160-
done();
161-
});
162-
})
163-
.then(() => {
164-
expect(sendEmailOptions[0].link).not.toBe(sendEmailOptions[1].link);
165-
done();
166-
})
167-
.catch(err => {
168-
jfail(err);
169-
done();
170-
});
141+
});
142+
const user = new Parse.User();
143+
user.setUsername('testResetTokenValidity');
144+
user.setPassword('original');
145+
user.set('email', '[email protected]');
146+
await user.signUp();
147+
await Parse.User.requestPasswordReset('[email protected]');
148+
await Parse.User.requestPasswordReset('[email protected]');
149+
expect(sendEmailOptions[0].link).not.toBe(sendEmailOptions[1].link);
150+
done();
171151
});
172152

173-
it('should keep reset token with resetTokenReuseIfValid', done => {
174-
const user = new Parse.User();
153+
it('should keep reset token with resetTokenReuseIfValid', async done => {
175154
const sendEmailOptions = [];
176155
const emailAdapter = {
177156
sendVerificationEmail: () => Promise.resolve(),
@@ -180,43 +159,24 @@ describe('Password Policy: ', () => {
180159
},
181160
sendMail: () => {},
182161
};
183-
reconfigureServer({
162+
await reconfigureServer({
184163
appName: 'passwordPolicy',
185164
emailAdapter: emailAdapter,
186165
passwordPolicy: {
187166
resetTokenValidityDuration: 5 * 60, // 5 minutes
188167
resetTokenReuseIfValid: true,
189168
},
190169
publicServerURL: 'http://localhost:8378/1',
191-
})
192-
.then(() => {
193-
user.setUsername('testResetTokenValidity');
194-
user.setPassword('original');
195-
user.set('email', '[email protected]');
196-
return user.signUp();
197-
})
198-
.then(() => {
199-
return Parse.User.requestPasswordReset('[email protected]').catch(err => {
200-
jfail(err);
201-
fail('Reset password request should not fail');
202-
done();
203-
});
204-
})
205-
.then(() => {
206-
return Parse.User.requestPasswordReset('[email protected]').catch(err => {
207-
jfail(err);
208-
fail('Reset password request should not fail');
209-
done();
210-
});
211-
})
212-
.then(() => {
213-
expect(sendEmailOptions[0].link).toBe(sendEmailOptions[1].link);
214-
done();
215-
})
216-
.catch(err => {
217-
jfail(err);
218-
done();
219-
});
170+
});
171+
const user = new Parse.User();
172+
user.setUsername('testResetTokenValidity');
173+
user.setPassword('original');
174+
user.set('email', '[email protected]');
175+
await user.signUp();
176+
await Parse.User.requestPasswordReset('[email protected]');
177+
await Parse.User.requestPasswordReset('[email protected]');
178+
expect(sendEmailOptions[0].link).toBe(sendEmailOptions[1].link);
179+
done();
220180
});
221181

222182
it('should fail if passwordPolicy.resetTokenValidityDuration is not a number', done => {

src/Config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export class Config {
7070
readOnlyMasterKey,
7171
allowHeaders,
7272
idempotencyOptions,
73+
emailVerifyTokenReuseIfValid,
7374
}) {
7475
if (masterKey === readOnlyMasterKey) {
7576
throw new Error('masterKey and readOnlyMasterKey should be different');
@@ -82,6 +83,7 @@ export class Config {
8283
appName,
8384
publicServerURL,
8485
emailVerifyTokenValidityDuration,
86+
emailVerifyTokenReuseIfValid,
8587
});
8688
}
8789

@@ -190,6 +192,16 @@ export class Config {
190192
) {
191193
throw 'passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20';
192194
}
195+
196+
if (
197+
passwordPolicy.resetTokenReuseIfValid &&
198+
typeof passwordPolicy.resetTokenReuseIfValid !== 'boolean'
199+
) {
200+
throw 'resetTokenReuseIfValid must be a boolean value';
201+
}
202+
if (passwordPolicy.resetTokenReuseIfValid && !passwordPolicy.resetTokenValidityDuration) {
203+
throw 'You cannot use resetTokenReuseIfValid without resetTokenValidityDuration';
204+
}
193205
}
194206
}
195207

@@ -207,6 +219,7 @@ export class Config {
207219
appName,
208220
publicServerURL,
209221
emailVerifyTokenValidityDuration,
222+
emailVerifyTokenReuseIfValid,
210223
}) {
211224
if (!emailAdapter) {
212225
throw 'An emailAdapter is required for e-mail verification and password resets.';
@@ -224,6 +237,12 @@ export class Config {
224237
throw 'Email verify token validity duration must be a value greater than 0.';
225238
}
226239
}
240+
if (emailVerifyTokenReuseIfValid && typeof emailVerifyTokenReuseIfValid !== 'boolean') {
241+
throw 'emailVerifyTokenReuseIfValid must be a boolean value';
242+
}
243+
if (emailVerifyTokenReuseIfValid && !emailVerifyTokenValidityDuration) {
244+
throw 'You cannot use emailVerifyTokenReuseIfValid without emailVerifyTokenValidityDuration';
245+
}
227246
}
228247

229248
static validateMasterKeyIps(masterKeyIps) {

src/Controllers/UserController.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,11 @@ export class UserController extends AdaptableController {
158158
* @returns {*}
159159
*/
160160
regenerateEmailVerifyToken(user) {
161-
const { _email_verify_token, _email_verify_token_expires_at } = user;
161+
const { _email_verify_token } = user;
162+
let { _email_verify_token_expires_at } = user;
163+
if (_email_verify_token_expires_at && _email_verify_token_expires_at.__type === 'Date') {
164+
_email_verify_token_expires_at = _email_verify_token_expires_at.iso;
165+
}
162166
if (
163167
this.config.emailVerifyTokenReuseIfValid &&
164168
this.config.emailVerifyTokenValidityDuration &&

src/Routers/UsersRouter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ export class UsersRouter extends ClassesRouter {
308308
appName: req.config.appName,
309309
publicServerURL: req.config.publicServerURL,
310310
emailVerifyTokenValidityDuration: req.config.emailVerifyTokenValidityDuration,
311+
emailVerifyTokenReuseIfValid: req.config.emailVerifyTokenReuseIfValid,
311312
});
312313
} catch (e) {
313314
if (typeof e === 'string') {

0 commit comments

Comments
 (0)