From ea8254cc65c8321cf556fb0e95ccdd7b5788c1be Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 23 Jun 2023 14:08:06 +1000 Subject: [PATCH 1/2] feat: `ParseUser.logInWithAdditionalAuth` --- src/ParseUser.js | 29 ++++++++++++++++++++ src/__tests__/ParseUser-test.js | 47 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/ParseUser.js b/src/ParseUser.js index d2014f1ac..6bb3aa3c6 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(auth) !== '[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: auth }); + 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(); From 0f4ff4994b87a52b047ad4b5073409b31cc39990 Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 23 Jun 2023 14:58:47 +1000 Subject: [PATCH 2/2] Update ParseUser.js --- src/ParseUser.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ParseUser.js b/src/ParseUser.js index 6bb3aa3c6..67c26a854 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -666,18 +666,18 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login completes. */ - static logInWithAdditionalAuth(username: string, password: string, authData: AuthData, options?: FullOptions) { + 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(auth) !== '[object Object]') { + 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: auth }); + user._finishFetch({ username: username, password: password, authData }); return user.logIn(options); }