diff --git a/src/ParseUser.js b/src/ParseUser.js index d2014f1ac..67c26a854 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -653,6 +653,34 @@ class ParseUser extends ParseObject { return user.logIn(options); } + /** + * Logs in a user with a username (or email) and password, and authData. On success, this + * saves the session to disk, so you can retrieve the currently logged in + * user using current. + * + * @param {string} username The username (or email) to log in with. + * @param {string} password The password to log in with. + * @param {object} authData The authData to log in with. + * @param {object} options + * @static + * @returns {Promise} A promise that is fulfilled with the user when + * the login completes. + */ + static logInWithAdditionalAuth(username: string, password: string, authData: AuthData, options?: FullOptions) { + if (typeof username !== 'string') { + return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); + } + if (typeof password !== 'string') { + return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Password must be a string.')); + } + if (Object.prototype.toString.call(authData) !== '[object Object]') { + return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Auth must be an object.')); + } + const user = new this(); + user._finishFetch({ username: username, password: password, authData }); + return user.logIn(options); + } + /** * Logs in a user with an objectId. On success, this saves the session * to disk, so you can retrieve the currently logged in user using @@ -1098,6 +1126,7 @@ const DefaultController = { const auth = { username: user.get('username'), password: user.get('password'), + authData: user.get('authData'), }; return RESTController.request(options.usePost ? 'POST' : 'GET', 'login', auth, options).then( response => { diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index f671149c3..7ddc66088 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -326,6 +326,53 @@ describe('ParseUser', () => { }); }); + describe('loginWithAdditional', () => { + it('loginWithAdditonal fails with invalid payload', async () => { + ParseUser.enableUnsafeCurrentUser(); + ParseUser._clearCache(); + CoreManager.setRESTController({ + request(method, path, body) { + expect(method).toBe('POST'); + expect(path).toBe('login'); + expect(body.username).toBe('username'); + expect(body.password).toBe('password'); + expect(body.authData).toEqual({ mfa: { key: '1234' } }); + + return Promise.resolve( + { + objectId: 'uid2', + username: 'username', + sessionToken: '123abc', + authDataResponse: { + mfa: { enabled: true }, + }, + }, + 200 + ); + }, + ajax() {}, + }); + const response = await ParseUser.logInWithAdditionalAuth('username', 'password', {mfa: {key:'1234'}}); + expect(response instanceof ParseUser).toBe(true); + expect(response.get('authDataResponse')).toEqual({mfa: { enabled: true }}); + }); + + it('loginWithAdditonal fails with invalid payload', async () => { + ParseUser.enableUnsafeCurrentUser(); + ParseUser._clearCache(); + await expect(ParseUser.logInWithAdditionalAuth({}, 'password', {})).rejects.toThrowError( + new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.') + ); + await expect(ParseUser.logInWithAdditionalAuth('username', {}, {})).rejects.toThrowError( + new ParseError(ParseError.OTHER_CAUSE, 'Password must be a string.') + ); + await expect(ParseUser.logInWithAdditionalAuth('username', 'password', '')).rejects.toThrowError( + new ParseError(ParseError.OTHER_CAUSE, 'Auth must be an object.') + ); + }); + }); + + it('preserves changes when logging in', done => { ParseUser.enableUnsafeCurrentUser(); ParseUser._clearCache();