diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index c9f0e972..8581b955 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -3224,4 +3224,166 @@ describe('Parse.User testing', () => { .then(done) .catch(done.fail); }); + + it('can login with email', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: { email: "yo@lo.com", password: 'yolopass'} + } + return rp.get(options); + }).then(done).catch(done.fail); + }); + + it('cannot login with email and invalid password', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: { email: "yo@lo.com", password: 'yolopass2'} + } + return rp.get(options); + }).then(done.fail).catch(done); + }); + + it('can login with email through query string', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login?email=yo@lo.com&password=yolopass`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + } + return rp.get(options); + }).then(done).catch(done.fail); + }); + + it('can login when both email and username are passed', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login?email=yo@lo.com&username=yolo&password=yolopass`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + } + return rp.get(options); + }).then(done).catch(done.fail); + }); + + it("fails to login when username doesn't match email", (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login?email=yo@lo.com&username=yolo2&password=yolopass`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: true, + } + return rp.get(options); + }).then(done.fail).catch((err) => { + expect(err.response.body.error).toEqual('Invalid username/password.'); + done(); + }); + }); + + it("fails to login when email doesn't match username", (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login?email=yo@lo2.com&username=yolo&password=yolopass`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: true, + } + return rp.get(options); + }).then(done.fail).catch((err) => { + expect(err.response.body.error).toEqual('Invalid username/password.'); + done(); + }); + }); + + it('fails to login when email and username are not provided', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login?password=yolopass`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: true, + } + return rp.get(options); + }).then(done.fail).catch((err) => { + expect(err.response.body.error).toEqual('username/email is required.'); + done(); + }); + }); + + it('fails to login when password is not provided', (done) => { + const user = new Parse.User(); + user.save({ + username: 'yolo', + password: 'yolopass', + email: 'yo@lo.com' + }).then(() => { + const options = { + url: `http://localhost:8378/1/login?username=yolo`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: true, + } + return rp.get(options); + }).then(done.fail).catch((err) => { + expect(err.response.body.error).toEqual('password is required.'); + done(); + }); + }); }); diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index ec1116b0..63e14b8a 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -51,25 +51,33 @@ export class UsersRouter extends ClassesRouter { handleLogIn(req) { // Use query parameters instead if provided in url - if (!req.body.username && req.query.username) { - req.body = req.query; + let payload = req.body; + if (!payload.username && req.query.username || !payload.email && req.query.email) { + payload = req.query; } + const { + username, + email, + password, + } = payload; // TODO: use the right error codes / descriptions. - if (!req.body.username) { - throw new Parse.Error(Parse.Error.USERNAME_MISSING, 'username is required.'); + if (!username && !email) { + throw new Parse.Error(Parse.Error.USERNAME_MISSING, 'username/email is required.'); } - if (!req.body.password) { + if (!password) { throw new Parse.Error(Parse.Error.PASSWORD_MISSING, 'password is required.'); } - if (typeof req.body.username !== 'string' || typeof req.body.password !== 'string') { + if (typeof password !== 'string' + || email && typeof email !== 'string' + || username && typeof username !== 'string') { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.'); } let user; let isValidPassword = false; - - return req.config.database.find('_User', { username: req.body.username }) + const query = Object.assign({}, username ? { username } : {}, email ? { email } : {}); + return req.config.database.find('_User', query) .then((results) => { if (!results.length) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.'); @@ -79,7 +87,7 @@ export class UsersRouter extends ClassesRouter { if (req.config.verifyUserEmails && req.config.preventLoginWithUnverifiedEmail && !user.emailVerified) { throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.'); } - return passwordCrypto.compare(req.body.password, user.password); + return passwordCrypto.compare(password, user.password); }) .then((correct) => { isValidPassword = correct;