Skip to content

Commit 1eb95ae

Browse files
authored
fix: Incomplete user object in verifyEmail function if both username and email are changed (#8889)
1 parent 355baf9 commit 1eb95ae

11 files changed

+129
-43
lines changed

spec/.eslintrc.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"fit_exclude_node_version": true,
2929
"it_exclude_dbs": true,
3030
"describe_only_db": true,
31+
"fdescribe_only_db": true,
3132
"describe_only": true,
3233
"on_db": true,
3334
"defaultConfiguration": true,

spec/EmailVerificationToken.spec.js

+50
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ describe('Email Verification Token Expiration: ', () => {
127127
user.set('email', '[email protected]');
128128
return user.signUp();
129129
})
130+
.then(() => jasmine.timeout())
130131
.then(() => {
131132
request({
132133
url: sendEmailOptions.link,
@@ -168,6 +169,7 @@ describe('Email Verification Token Expiration: ', () => {
168169
user.set('email', '[email protected]');
169170
return user.signUp();
170171
})
172+
.then(() => jasmine.timeout())
171173
.then(() => {
172174
request({
173175
url: sendEmailOptions.link,
@@ -215,6 +217,7 @@ describe('Email Verification Token Expiration: ', () => {
215217
user.set('email', '[email protected]');
216218
return user.signUp();
217219
})
220+
.then(() => jasmine.timeout())
218221
.then(() => {
219222
request({
220223
url: sendEmailOptions.link,
@@ -388,6 +391,7 @@ describe('Email Verification Token Expiration: ', () => {
388391
user2.setPassword('expiringToken');
389392
user2.set('email', '[email protected]');
390393
await user2.signUp();
394+
await jasmine.timeout();
391395
expect(user2.getSessionToken()).toBeUndefined();
392396
expect(sendEmailOptions).toBeDefined();
393397
expect(verifySpy).toHaveBeenCalledTimes(5);
@@ -422,10 +426,47 @@ describe('Email Verification Token Expiration: ', () => {
422426
newUser.set('email', '[email protected]');
423427
await newUser.signUp();
424428
await Parse.User.requestEmailVerification('[email protected]');
429+
await jasmine.timeout();
425430
expect(sendSpy).toHaveBeenCalledTimes(2);
426431
expect(emailSpy).toHaveBeenCalledTimes(0);
427432
});
428433

434+
it('provides full user object in email verification function on email and username change', async () => {
435+
const emailAdapter = {
436+
sendVerificationEmail: () => {},
437+
sendPasswordResetEmail: () => Promise.resolve(),
438+
sendMail: () => {},
439+
};
440+
const sendVerificationEmail = {
441+
method(req) {
442+
expect(req.user).toBeDefined();
443+
expect(req.user.id).toBeDefined();
444+
expect(req.user.get('createdAt')).toBeDefined();
445+
expect(req.user.get('updatedAt')).toBeDefined();
446+
expect(req.master).toBeDefined();
447+
return false;
448+
},
449+
};
450+
await reconfigureServer({
451+
appName: 'emailVerifyToken',
452+
verifyUserEmails: true,
453+
emailAdapter: emailAdapter,
454+
emailVerifyTokenValidityDuration: 5,
455+
publicServerURL: 'http://localhost:8378/1',
456+
sendUserEmailVerification: sendVerificationEmail.method,
457+
});
458+
const user = new Parse.User();
459+
user.setPassword('password');
460+
user.setUsername('[email protected]');
461+
user.setEmail('[email protected]');
462+
await user.save(null, { useMasterKey: true });
463+
464+
// Update email and username
465+
user.setUsername('[email protected]');
466+
user.setEmail('[email protected]');
467+
await user.save(null, { useMasterKey: true });
468+
});
469+
429470
it('beforeSave options do not change existing behaviour', async () => {
430471
let sendEmailOptions;
431472
const emailAdapter = {
@@ -448,6 +489,7 @@ describe('Email Verification Token Expiration: ', () => {
448489
newUser.setPassword('expiringToken');
449490
newUser.set('email', '[email protected]');
450491
await newUser.signUp();
492+
await jasmine.timeout();
451493
const response = await request({
452494
url: sendEmailOptions.link,
453495
followRedirects: false,
@@ -490,6 +532,7 @@ describe('Email Verification Token Expiration: ', () => {
490532
user.set('email', '[email protected]');
491533
return user.signUp();
492534
})
535+
.then(() => jasmine.timeout())
493536
.then(() => {
494537
request({
495538
url: sendEmailOptions.link,
@@ -549,6 +592,7 @@ describe('Email Verification Token Expiration: ', () => {
549592
user.set('email', '[email protected]');
550593
return user.signUp();
551594
})
595+
.then(() => jasmine.timeout())
552596
.then(() => {
553597
return request({
554598
url: sendEmailOptions.link,
@@ -766,6 +810,9 @@ describe('Email Verification Token Expiration: ', () => {
766810
})
767811
.then(response => {
768812
expect(response.status).toBe(200);
813+
})
814+
.then(() => jasmine.timeout())
815+
.then(() => {
769816
expect(sendVerificationEmailCallCount).toBe(2);
770817
expect(sendEmailOptions).toBeDefined();
771818

@@ -917,6 +964,7 @@ describe('Email Verification Token Expiration: ', () => {
917964
'Content-Type': 'application/json',
918965
},
919966
});
967+
await jasmine.timeout();
920968
expect(response.status).toBe(200);
921969
expect(sendVerificationEmailCallCount).toBe(2);
922970
expect(sendEmailOptions).toBeDefined();
@@ -959,6 +1007,7 @@ describe('Email Verification Token Expiration: ', () => {
9591007
user.set('email', '[email protected]');
9601008
return user.signUp();
9611009
})
1010+
.then(() => jasmine.timeout())
9621011
.then(() => {
9631012
return request({
9641013
url: sendEmailOptions.link,
@@ -1197,6 +1246,7 @@ describe('Email Verification Token Expiration: ', () => {
11971246
user.set('email', '[email protected]');
11981247
return user.signUp();
11991248
})
1249+
.then(() => jasmine.timeout())
12001250
.then(() => {
12011251
request({
12021252
url: sendEmailOptions.link,

spec/PagesRouter.spec.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ describe('Pages Router', () => {
749749
user.setPassword('examplePassword');
750750
user.set('email', '[email protected]');
751751
await user.signUp();
752+
await jasmine.timeout();
752753

753754
const link = sendVerificationEmail.calls.all()[0].args[0].link;
754755
const linkWithLocale = new URL(link);
@@ -777,6 +778,7 @@ describe('Pages Router', () => {
777778
user.setPassword('examplePassword');
778779
user.set('email', '[email protected]');
779780
await user.signUp();
781+
await jasmine.timeout();
780782

781783
const link = sendVerificationEmail.calls.all()[0].args[0].link;
782784
const linkWithLocale = new URL(link);
@@ -830,6 +832,7 @@ describe('Pages Router', () => {
830832
user.setPassword('examplePassword');
831833
user.set('email', '[email protected]');
832834
await user.signUp();
835+
await jasmine.timeout();
833836

834837
const link = sendVerificationEmail.calls.all()[0].args[0].link;
835838
const linkWithLocale = new URL(link);
@@ -846,6 +849,8 @@ describe('Pages Router', () => {
846849
const locale = linkResponse.headers['x-parse-page-param-locale'];
847850
const username = linkResponse.headers['x-parse-page-param-username'];
848851
const publicServerUrl = linkResponse.headers['x-parse-page-param-publicserverurl'];
852+
await jasmine.timeout();
853+
849854
const invalidVerificationPagePath = pageResponse.calls.all()[0].args[0];
850855
expect(appId).toBeDefined();
851856
expect(locale).toBe(exampleLocale);
@@ -1190,14 +1195,14 @@ describe('Pages Router', () => {
11901195
user.setPassword('examplePassword');
11911196
user.set('email', '[email protected]');
11921197
await user.signUp();
1198+
await jasmine.timeout();
11931199

11941200
const link = sendVerificationEmail.calls.all()[0].args[0].link;
11951201
const linkResponse = await request({
11961202
url: link,
11971203
followRedirects: false,
11981204
});
11991205
expect(linkResponse.status).toBe(200);
1200-
12011206
const pagePath = pageResponse.calls.all()[0].args[0];
12021207
expect(pagePath).toMatch(new RegExp(`\/${pages.emailVerificationSuccess.defaultFile}`));
12031208
});

spec/Parse.Push.spec.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
const request = require('../lib/request');
44

5-
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
6-
75
const pushCompleted = async pushId => {
86
const query = new Parse.Query('_PushStatus');
97
query.equalTo('objectId', pushId);
108
let result = await query.first({ useMasterKey: true });
119
while (!(result && result.get('status') === 'succeeded')) {
12-
await sleep(100);
10+
await jasmine.timeout();
1311
result = await query.first({ useMasterKey: true });
1412
}
1513
};

spec/ParseHooks.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ describe('Hooks', () => {
190190

191191
it('should fail trying to create two times the same function', done => {
192192
Parse.Hooks.createFunction('my_new_function', 'http://url.com')
193-
.then(() => new Promise(resolve => setTimeout(resolve, 100)))
193+
.then(() => jasmine.timeout())
194194
.then(
195195
() => {
196196
return Parse.Hooks.createFunction('my_new_function', 'http://url.com');

spec/ParseUser.spec.js

+1
Original file line numberDiff line numberDiff line change
@@ -3067,6 +3067,7 @@ describe('Parse.User testing', () => {
30673067
},
30683068
});
30693069
})
3070+
.then(() => jasmine.timeout())
30703071
.then(() => {
30713072
expect(emailCalled).toBe(true);
30723073
expect(emailOptions).not.toBeUndefined();

spec/PushController.spec.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,12 @@ const successfulIOS = function (body, installations) {
2626
return Promise.all(promises);
2727
};
2828

29-
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
30-
3129
const pushCompleted = async pushId => {
3230
const query = new Parse.Query('_PushStatus');
3331
query.equalTo('objectId', pushId);
3432
let result = await query.first({ useMasterKey: true });
3533
while (!(result && result.get('status') === 'succeeded')) {
36-
await sleep(100);
34+
await jasmine.timeout();
3735
result = await query.first({ useMasterKey: true });
3836
}
3937
};
@@ -562,7 +560,7 @@ describe('PushController', () => {
562560
});
563561
const pushStatusId = await sendPush(payload, {}, config, auth);
564562
// it is enqueued so it can take time
565-
await sleep(1000);
563+
await jasmine.timeout(1000);
566564
Parse.serverURL = 'http://localhost:8378/1'; // GOOD url
567565
const result = await Parse.Push.getPushStatus(pushStatusId);
568566
expect(result).toBeDefined();
@@ -801,7 +799,7 @@ describe('PushController', () => {
801799
});
802800
await Parse.Object.saveAll(installations);
803801
await pushController.sendPush(payload, {}, config, auth);
804-
await sleep(1000);
802+
await jasmine.timeout(1000);
805803
const query = new Parse.Query('_PushStatus');
806804
const results = await query.find({ useMasterKey: true });
807805
expect(results.length).toBe(1);
@@ -856,7 +854,7 @@ describe('PushController', () => {
856854
const config = Config.get(Parse.applicationId);
857855
await Parse.Object.saveAll(installations);
858856
await pushController.sendPush(payload, {}, config, auth);
859-
await sleep(1000);
857+
await jasmine.timeout(1000);
860858
const query = new Parse.Query('_PushStatus');
861859
const results = await query.find({ useMasterKey: true });
862860
expect(results.length).toBe(1);

spec/UserController.spec.js

+44-22
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
const emailAdapter = require('./support/MockEmailAdapter');
2+
const Config = require('../lib/Config');
3+
const Auth = require('../lib/Auth');
24

35
describe('UserController', () => {
4-
const user = {
5-
_email_verify_token: 'testToken',
6-
username: 'testUser',
7-
8-
};
9-
106
describe('sendVerificationEmail', () => {
117
describe('parseFrameURL not provided', () => {
12-
it('uses publicServerURL', async done => {
13-
const server = await reconfigureServer({
8+
it('uses publicServerURL', async () => {
9+
await reconfigureServer({
1410
publicServerURL: 'http://www.example.com',
1511
customPages: {
1612
parseFrameURL: undefined,
@@ -19,20 +15,33 @@ describe('UserController', () => {
1915
emailAdapter,
2016
appName: 'test',
2117
});
18+
19+
let emailOptions;
2220
emailAdapter.sendVerificationEmail = options => {
23-
expect(options.link).toEqual(
24-
'http://www.example.com/apps/test/verify_email?token=testToken&username=testUser'
25-
);
26-
emailAdapter.sendVerificationEmail = () => Promise.resolve();
27-
done();
21+
emailOptions = options;
22+
return Promise.resolve();
2823
};
29-
server.config.userController.sendVerificationEmail(user);
24+
25+
const username = 'verificationUser';
26+
const user = new Parse.User();
27+
user.setUsername(username);
28+
user.setPassword('pass');
29+
user.setEmail('[email protected]');
30+
await user.signUp();
31+
32+
const config = Config.get('test');
33+
const rawUser = await config.database.find('_User', { username }, {}, Auth.maintenance(config));
34+
const rawUsername = rawUser[0].username;
35+
const rawToken = rawUser[0]._email_verify_token;
36+
expect(rawToken).toBeDefined();
37+
expect(rawUsername).toBe(username);
38+
expect(emailOptions.link).toEqual(`http://www.example.com/apps/test/verify_email?token=${rawToken}&username=${username}`);
3039
});
3140
});
3241

3342
describe('parseFrameURL provided', () => {
34-
it('uses parseFrameURL and includes the destination in the link parameter', async done => {
35-
const server = await reconfigureServer({
43+
it('uses parseFrameURL and includes the destination in the link parameter', async () => {
44+
await reconfigureServer({
3645
publicServerURL: 'http://www.example.com',
3746
customPages: {
3847
parseFrameURL: 'http://someother.example.com/handle-parse-iframe',
@@ -41,14 +50,27 @@ describe('UserController', () => {
4150
emailAdapter,
4251
appName: 'test',
4352
});
53+
54+
let emailOptions;
4455
emailAdapter.sendVerificationEmail = options => {
45-
expect(options.link).toEqual(
46-
'http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=testToken&username=testUser'
47-
);
48-
emailAdapter.sendVerificationEmail = () => Promise.resolve();
49-
done();
56+
emailOptions = options;
57+
return Promise.resolve();
5058
};
51-
server.config.userController.sendVerificationEmail(user);
59+
60+
const username = 'verificationUser';
61+
const user = new Parse.User();
62+
user.setUsername(username);
63+
user.setPassword('pass');
64+
user.setEmail('[email protected]');
65+
await user.signUp();
66+
67+
const config = Config.get('test');
68+
const rawUser = await config.database.find('_User', { username }, {}, Auth.maintenance(config));
69+
const rawUsername = rawUser[0].username;
70+
const rawToken = rawUser[0]._email_verify_token;
71+
expect(rawToken).toBeDefined();
72+
expect(rawUsername).toBe(username);
73+
expect(emailOptions.link).toEqual(`http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=${rawToken}&username=${username}`);
5274
});
5375
});
5476
});

0 commit comments

Comments
 (0)