diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index ab95768e83..af554bf01a 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -3432,6 +3432,60 @@ describe('Parse.User testing', () => { }); }); + it('allows login when providing email as username', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + return Parse.User.logIn('yo@lo.com', 'yolopass'); + }).then((user) => { + expect(user.get('username')).toBe('yolo'); + }).then(done).catch(done.fail); + }); + + it('handles properly when 2 users share username / email pairs', (done) => { + const user = new Parse.User({ + username: 'yo@loname.com', + password: 'yolopass', + email: 'yo@lo.com' + }); + const user2 = new Parse.User({ + username: 'yo@lo.com', + email: 'yo@loname.com', + password: 'yolopass2' // different passwords + }); + + Parse.Object.saveAll([user, user2]).then(() => { + return Parse.User.logIn('yo@loname.com', 'yolopass'); + }).then((user) => { + // the username takes precedence over the email, + // so we get the user with username as passed in + expect(user.get('username')).toBe('yo@loname.com'); + }).then(done).catch(done.fail); + }); + + it('handles properly when 2 users share username / email pairs, counterpart', (done) => { + const user = new Parse.User({ + username: 'yo@loname.com', + password: 'yolopass', + email: 'yo@lo.com' + }); + const user2 = new Parse.User({ + username: 'yo@lo.com', + email: 'yo@loname.com', + password: 'yolopass2' // different passwords + }); + + Parse.Object.saveAll([user, user2]).then(() => { + return Parse.User.logIn('yo@loname.com', 'yolopass2'); + }).then(done.fail).catch((err) => { + expect(err.message).toEqual('Invalid username/password.'); + done(); + }); + }); + it('fails to login when password is not provided', (done) => { const user = new Parse.User(); user.save({ diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index 0cdba7b1e0..86763d7eea 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -84,13 +84,26 @@ export class UsersRouter extends ClassesRouter { let user; let isValidPassword = false; - const query = Object.assign({}, username ? { username } : {}, email ? { email } : {}); + let query; + if (email && username) { + query = { email, username }; + } else if (email) { + query = { email }; + } else { + query = { $or: [{ username } , { email: username }] }; + } return req.config.database.find('_User', query) .then((results) => { if (!results.length) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.'); } - user = results[0]; + + if (results.length > 1) { // corner case where user1 has username == user2 email + req.config.loggerController.warn('There is a user which email is the same as another user\'s username, logging in based on username'); + user = results.filter((user) => user.username === username)[0]; + } else { + 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.');