Skip to content

Commit 72e20be

Browse files
authored
fix #3451 duplicate session upon login (#4337)
* Adds failing test for #3451 (on multiple logins) * Factor sessionDestruction as part of Session creation flow in RestWrite * nits
1 parent 932a474 commit 72e20be

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

spec/ParseUser.spec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3453,4 +3453,34 @@ describe('Parse.User testing', () => {
34533453
done();
34543454
});
34553455
});
3456+
3457+
it('does not duplicate session when logging in multiple times #3451', (done) => {
3458+
const user = new Parse.User();
3459+
user.signUp({
3460+
username: 'yolo',
3461+
password: 'yolo',
3462+
3463+
}).then(() => {
3464+
const promises = [];
3465+
while(promises.length != 5) {
3466+
Parse.User.logIn('yolo', 'yolo')
3467+
promises.push(Parse.User.logIn('yolo', 'yolo').then((res) => {
3468+
// ensure a new session token is generated at each login
3469+
expect(res.getSessionToken()).not.toBe(user.getSessionToken());
3470+
}));
3471+
}
3472+
return Promise.all(promises);
3473+
}).then(() => {
3474+
// wait because session destruction is not synchronous
3475+
return new Promise((resolve) => {
3476+
setTimeout(resolve, 100);
3477+
});
3478+
}).then(() => {
3479+
const query = new Parse.Query('_Session');
3480+
return query.find({ useMasterKey: true });
3481+
}).then((results) => {
3482+
// only one session in the end
3483+
expect(results.length).toBe(1);
3484+
}).then(done, done.fail);
3485+
});
34563486
});

src/RestWrite.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ RestWrite.prototype.execute = function() {
8181
return this.transformUser();
8282
}).then(() => {
8383
return this.expandFilesForExistingObjects();
84+
}).then(() => {
85+
return this.destroyDuplicatedSessions();
8486
}).then(() => {
8587
return this.runDatabaseOperation();
8688
}).then(() => {
@@ -588,17 +590,31 @@ RestWrite.prototype.createSessionToken = function() {
588590
this.response.response.sessionToken = token;
589591
}
590592

593+
return new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData).execute();
594+
}
595+
596+
RestWrite.prototype.destroyDuplicatedSessions = function() {
597+
// Only for _Session, and at creation time
598+
if (this.className != '_Session' || this.query) {
599+
return;
600+
}
591601
// Destroy the sessions in 'Background'
602+
const {
603+
user,
604+
installationId,
605+
sessionToken,
606+
} = this.data;
607+
if (!user || !installationId) {
608+
return;
609+
}
610+
if (!user.objectId) {
611+
return;
612+
}
592613
this.config.database.destroy('_Session', {
593-
user: {
594-
__type: 'Pointer',
595-
className: '_User',
596-
objectId: this.objectId()
597-
},
598-
installationId: this.auth.installationId,
599-
sessionToken: { '$ne': token },
614+
user,
615+
installationId,
616+
sessionToken: { '$ne': sessionToken },
600617
});
601-
return new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData).execute();
602618
}
603619

604620
// Handles any followup logic

0 commit comments

Comments
 (0)