From 7360d2796d621b75adfa19f8beb57cfea3a3aed0 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 19 Aug 2020 14:11:34 +1000 Subject: [PATCH 1/3] Update CloudCode.js Hi all, Not sure if my formatting is perfect but closes #1176 (removes pre. SDK 2.0 success functions), and adds documentation for LiveQuery triggers. Also, for me, when I google "Parse Javascript SDK", it takes me to v1.11.0. Is there any way we can add "This SDK is outdated" or some other warning to point users to the latest SDK? Thank you! --- src/CloudCode.js | 85 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/src/CloudCode.js b/src/CloudCode.js index 5169834a2..04f6d7e47 100644 --- a/src/CloudCode.js +++ b/src/CloudCode.js @@ -62,11 +62,11 @@ * * If you want to use beforeDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. * ``` - * Parse.Cloud.beforeDelete('MyCustomClass', (request, response) => { + * Parse.Cloud.beforeDelete('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.beforeDelete(Parse.User, (request, response) => { + * Parse.Cloud.beforeDelete(Parse.User, (request) => { * // code here * }) *``` @@ -74,7 +74,7 @@ * @method beforeDelete * @name Parse.Cloud.beforeDelete * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before delete function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a delete. This function should take two parameters a {@link Parse.Cloud.TriggerRequest} and a {@link Parse.Cloud.BeforeDeleteResponse}. + * @param {Function} func The function to run after a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. */ /** @@ -86,11 +86,11 @@ * If you want to use beforeSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. * * ``` - * Parse.Cloud.beforeSave('MyCustomClass', (request, response) => { + * Parse.Cloud.beforeSave('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.beforeSave(Parse.User, (request, response) => { + * Parse.Cloud.beforeSave(Parse.User, (request) => { * // code here * }) * ``` @@ -98,7 +98,7 @@ * @method beforeSave * @name Parse.Cloud.beforeSave * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a save. This function should take two parameters a {@link Parse.Cloud.TriggerRequest} and a {@link Parse.Cloud.BeforeSaveResponse}. + * @param {Function} func The function to run after a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. */ /** @@ -166,6 +166,51 @@ * @param {Function} func The function to run after a file saves. This function should take one parameter, a {@link Parse.Cloud.FileTriggerRequest}. */ +/** + * @method beforeConnect + * @name Parse.Cloud.beforeConnect + * @param {Function} func The function to before connection is made. This function can be async and should take just one parameter, {@link Parse.Cloud.ConnectTriggerRequest}. + */ +/** + * + * Registers a before connect function. + * + * **Available in Cloud Code only.** + * + * Example: restrict LiveQueries to logged in users. + * ``` + * Parse.Cloud.beforeConnect((request) => { + * if (!request.user) { + * throw "Please login before you attempt to connect." + * } + * }); + * ``` +*/ + +/** + * @method beforeSubscribe + * @name Parse.Cloud.beforeSubscribe + * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before subscription function for. This can instead be a String that is the className of the subclass. + * @param {Function} func The function to run before a subscription. This function can be async and should take one parameter, a {@link Parse.Cloud.TriggerRequest}. + */ +/** + * + * Registers a before subscribe function. + * + * **Available in Cloud Code only.** + * Example: restrict subscriptions to MyObject to Admin accounts only. + * ``` + * Parse.Cloud.beforeSubscribe('MyObject', (request) => { + * if (!request.user.get('Admin')) { + * throw new Parse.Error(101, 'You are not authorized to subscribe to MyObject.'); + * } + * let query = request.query; // the Parse.Query + * query.select("name","year") + * }); + * ``` +*/ + + /** * Makes an HTTP Request. * @@ -229,6 +274,16 @@ * @property {Object} log The current logger inside Parse Server. */ +/** + * @typedef Parse.Cloud.ConnectTriggerRequest + * @property {String} installationId If set, the installationId triggering the request. + * @property {Boolean} useMasterKey If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {Integer} clients The number of clients connected. + * @property {Integer} subscriptions The number of subscriptions connected. + * @property {String} sessionToken If set, the session of the user that made the request. + */ + /** * @typedef Parse.Cloud.FunctionRequest * @property {String} installationId If set, the installationId triggering the request. @@ -249,24 +304,6 @@ * @property {function} success If success is called, will end the job successfullly with the optional completion message to be stored in the job status. */ -/** - * @typedef Parse.Cloud.BeforeSaveResponse - * @property {function} success If called, will allow the save to happen. If a Parse.Object is passed in, then the passed in object will be saved instead. - * @property {function} error If called, will reject the save. An optional error message may be passed in. - */ - -/** - * @typedef Parse.Cloud.BeforeDeleteResponse - * @property {function} success If called, will allow the delete to happen. - * @property {function} error If called, will reject the save. An optional error message may be passed in. - */ - -/** - * @typedef Parse.Cloud.FunctionResponse - * @property {function} success If success is called, will return a successful response with the optional argument to the caller. - * @property {function} error If error is called, will return an error response with an optionally passed message. - */ - /** * @typedef Parse.Cloud.HTTPOptions * @property {String|Object} body The body of the request. If it is a JSON object, then the Content-Type set in the headers must be application/x-www-form-urlencoded or application/json. You can also set this to a {@link Buffer} object to send raw bytes. If you use a Buffer, you should also set the Content-Type header explicitly to describe what these bytes represent. From ed9e32a9a843f2d80a09501b0b0bd8dc09e175b5 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 19 Aug 2020 14:17:07 +1000 Subject: [PATCH 2/3] Update CloudCode.js --- src/CloudCode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CloudCode.js b/src/CloudCode.js index 04f6d7e47..6278da7ac 100644 --- a/src/CloudCode.js +++ b/src/CloudCode.js @@ -74,7 +74,7 @@ * @method beforeDelete * @name Parse.Cloud.beforeDelete * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before delete function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run after a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param {Function} func The function to run before a delete. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. */ /** @@ -98,7 +98,7 @@ * @method beforeSave * @name Parse.Cloud.beforeSave * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run after a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param {Function} func The function to run before a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. */ /** From 1029d8b2d1a91fc83953b025cfbb487acc0d3f50 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 2 Mar 2023 14:00:53 +1100 Subject: [PATCH 3/3] feat: allow logout with `clearSession` to logout with invalid session token --- src/ParseUser.js | 16 ++++++++++++---- src/__tests__/ParseUser-test.js | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/ParseUser.js b/src/ParseUser.js index 9e2f43d9a..d5ad1769b 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -1134,8 +1134,14 @@ const DefaultController = { logOut(options: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); + const promiseCatch = e => { + if (e.code === ParseError.INVALID_SESSION_TOKEN && options.clearSession) { + return; + } + throw e; + }; if (options.sessionToken) { - return RESTController.request('POST', 'logout', {}, options); + return RESTController.request('POST', 'logout', {}, options).catch(promiseCatch); } return DefaultController.currentUserAsync().then(currentUser => { const path = Storage.generatePath(CURRENT_USER_KEY); @@ -1143,9 +1149,11 @@ const DefaultController = { if (currentUser !== null) { const currentSession = currentUser.getSessionToken(); if (currentSession && isRevocableSession(currentSession)) { - promise = promise.then(() => { - return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); - }); + promise = promise + .then(() => { + return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); + }) + .catch(promiseCatch); } currentUser._logOutWithAll(); currentUser._finishFetch({ sessionToken: undefined }); diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index ba0fbda75..18e6e3f16 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -940,6 +940,40 @@ describe('ParseUser', () => { }); }); + it('can logout user with clear session', async () => { + ParseUser.disableUnsafeCurrentUser(); + ParseUser._clearCache(); + Storage._clear(); + const RESTController = { + request() { + const error = new ParseError(ParseError.INVALID_SESSION_TOKEN, 'Invalid session token.'); + return Promise.reject(error); + }, + ajax() {}, + }; + jest.spyOn(RESTController, 'request'); + CoreManager.setRESTController(RESTController); + + await ParseUser.logOut({ clearSession: true }); + }); + + it('can logout user with clear session and session token', async () => { + ParseUser.disableUnsafeCurrentUser(); + ParseUser._clearCache(); + Storage._clear(); + const RESTController = { + request() { + const error = new ParseError(ParseError.INVALID_SESSION_TOKEN, 'Invalid session token.'); + return Promise.reject(error); + }, + ajax() {}, + }; + jest.spyOn(RESTController, 'request'); + CoreManager.setRESTController(RESTController); + + await ParseUser.logOut({ sessionToken: '1234', clearSession: true }); + }); + it('can retreive a user with sessionToken (me)', async () => { ParseUser.disableUnsafeCurrentUser(); ParseUser._clearCache();