From 2a3076cc40ad845d630bab9d1271de4a7718c77a Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 7 Jun 2022 16:17:05 +1000 Subject: [PATCH 01/19] fix: clear live query role cache when a user is added to a role --- spec/ParseLiveQuery.spec.js | 44 ++++++++++++++++++++++++ src/Auth.js | 8 +++++ src/Controllers/LiveQueryController.js | 7 ++++ src/LiveQuery/ParseCloudCodePublisher.js | 7 ++++ src/LiveQuery/ParseLiveQueryServer.js | 35 ++++++++++++++++++- src/RestWrite.js | 1 + 6 files changed, 101 insertions(+), 1 deletion(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index d9b79bc588..7cd147afab 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -836,6 +836,50 @@ describe('ParseLiveQuery', function () { } }); + it('LiveQuery should work with changing role', async () => { + await reconfigureServer({ + liveQuery: { + classNames: ['Chat'], + }, + startLiveQueryServer: true, + }); + const user = new Parse.User(); + user.setUsername('username'); + user.setPassword('password'); + await user.signUp(); + + const role = new Parse.Role('Test', new Parse.ACL(user)); + await role.save(); + + const chatQuery = new Parse.Query('Chat'); + const subscription = await chatQuery.subscribe(); + subscription.on('create', () => { + fail('should not call create as user is not part of role.'); + }); + + const object = new Parse.Object('Chat'); + const acl = new Parse.ACL(); + acl.setRoleReadAccess(role, true); + object.setACL(acl); + object.set({ foo: 'bar' }); + await object.save(null, { useMasterKey: true }); + + role.getUsers().add(user); + await role.save(); + + object.set('foo', 'yolo'); + await Promise.all([ + new Promise(resolve => { + subscription.on('update', obj => { + expect(obj.get('foo')).toBe('yolo'); + expect(obj.getACL().toJSON()).toEqual({ 'role:Test': { read: true } }); + resolve(); + }); + }), + object.save(null, { useMasterKey: true }), + ]); + }); + it('liveQuery on Session class', async done => { await reconfigureServer({ liveQuery: { classNames: [Parse.Session] }, diff --git a/src/Auth.js b/src/Auth.js index e3196105c7..32c912769d 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -230,6 +230,14 @@ Auth.prototype.cacheRoles = function () { return true; }; +Auth.prototype.clearRoleCache = function () { + if (!this.cacheController) { + return false; + } + this.cacheController.role.del(this.user.id); + return true; +}; + Auth.prototype.getRolesByIds = async function (ins) { const results = []; // Build an OR query across all parentRoles diff --git a/src/Controllers/LiveQueryController.js b/src/Controllers/LiveQueryController.js index 064084caa4..9a5b6d0ef1 100644 --- a/src/Controllers/LiveQueryController.js +++ b/src/Controllers/LiveQueryController.js @@ -56,6 +56,13 @@ export class LiveQueryController { return false; } + clearCachedRoles(user: any) { + if (!user) { + return; + } + return this.liveQueryPublisher.onClearCachedRoles(user); + } + _makePublisherRequest(currentObject: any, originalObject: any, classLevelPermissions: ?any): any { const req = { object: currentObject, diff --git a/src/LiveQuery/ParseCloudCodePublisher.js b/src/LiveQuery/ParseCloudCodePublisher.js index 85e95121fb..b84b14ef31 100644 --- a/src/LiveQuery/ParseCloudCodePublisher.js +++ b/src/LiveQuery/ParseCloudCodePublisher.js @@ -19,6 +19,13 @@ class ParseCloudCodePublisher { this._onCloudCodeMessage(Parse.applicationId + 'afterDelete', request); } + onClearCachedRoles(user: Parse.Object) { + this.parsePublisher.publish( + Parse.applicationId + 'clearCache', + JSON.stringify({ userId: user.id }) + ); + } + // Request is the request object from cloud code functions. request.object is a ParseObject. _onCloudCodeMessage(type: string, request: any): void { logger.verbose( diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index fa05f23711..12c9a60fbb 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -10,7 +10,13 @@ import { ParsePubSub } from './ParsePubSub'; import SchemaController from '../Controllers/SchemaController'; import _ from 'lodash'; import { v4 as uuidv4 } from 'uuid'; -import { runLiveQueryEventHandlers, getTrigger, runTrigger, resolveError, toJSONwithObjects } from '../triggers'; +import { + runLiveQueryEventHandlers, + getTrigger, + runTrigger, + resolveError, + toJSONwithObjects, +} from '../triggers'; import { getAuthForSessionToken, Auth } from '../Auth'; import { getCacheController } from '../Controllers'; import LRU from 'lru-cache'; @@ -71,6 +77,7 @@ class ParseLiveQueryServer { this.subscriber = ParsePubSub.createSubscriber(config); this.subscriber.subscribe(Parse.applicationId + 'afterSave'); this.subscriber.subscribe(Parse.applicationId + 'afterDelete'); + this.subscriber.subscribe(Parse.applicationId + 'clearCache'); // Register message handler for subscriber. When publisher get messages, it will publish message // to the subscribers and the handler will be called. this.subscriber.on('message', (channel, messageStr) => { @@ -82,6 +89,10 @@ class ParseLiveQueryServer { logger.error('unable to parse message', messageStr, e); return; } + if (channel === Parse.applicationId + 'clearCache') { + this._clearCachedRoles(message.userId); + return; + } this._inflateParseObject(message); if (channel === Parse.applicationId + 'afterSave') { this._onAfterSave(message); @@ -468,6 +479,28 @@ class ParseLiveQueryServer { return matchesQuery(parseObject, subscription.query); } + async _clearCachedRoles(userId: string) { + try { + const validTokens = await new Parse.Query(Parse.Session) + .equalTo('user', Parse.User.createWithoutData(userId)) + .find({ useMasterKey: true }); + await Promise.all( + validTokens.map(async token => { + const sessionToken = token.get('sessionToken'); + const authPromise = this.authCache.get(sessionToken); + if (!authPromise) { + return; + } + const { auth } = await authPromise; + auth.clearRoleCache(); + this.authCache.del(sessionToken); + }) + ); + } catch (e) { + logger.verbose(`Could not clear role cache. ${e}`); + } + } + getAuthForSessionToken(sessionToken: ?string): Promise<{ auth: ?Auth, userId: ?string }> { if (!sessionToken) { return Promise.resolve({}); diff --git a/src/RestWrite.js b/src/RestWrite.js index fd81561732..482e297ccd 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -1326,6 +1326,7 @@ RestWrite.prototype.runDatabaseOperation = function () { if (this.className === '_Role') { this.config.cacheController.role.clear(); + this.config.liveQueryController.clearCachedRoles(this.auth.user); } if (this.className === '_User' && this.query && this.auth.isUnauthenticated()) { From 28e64377bac68c8cce1167b522d3e39f3eab4b47 Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 7 Jun 2022 16:33:51 +1000 Subject: [PATCH 02/19] Update ParseLiveQuery.spec.js --- spec/ParseLiveQuery.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 7cd147afab..86de83e07a 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -866,7 +866,7 @@ describe('ParseLiveQuery', function () { role.getUsers().add(user); await role.save(); - + await new Promise(resolve => setTimeout(resolve, 500)); object.set('foo', 'yolo'); await Promise.all([ new Promise(resolve => { From e5976eadce2aa0d42c44094fe005840fad4f104a Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 7 Jun 2022 17:17:32 +1000 Subject: [PATCH 03/19] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 12c9a60fbb..171e3d6b50 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -609,6 +609,7 @@ class ParseLiveQueryServer { } const roleNames = await auth.getUserRoles(); + console.log({ roleNames }); // Finally, see if any of the user's roles allow them read access for (const role of roleNames) { // We use getReadAccess as `role` is in the form `role:roleName` From d20926a6945fd8a059da3b5f9e54e420f99be045 Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 7 Jun 2022 20:03:52 +1000 Subject: [PATCH 04/19] log error --- spec/ParseLiveQuery.spec.js | 2 +- src/Controllers/LiveQueryController.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 86de83e07a..19ff6951eb 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -866,7 +866,7 @@ describe('ParseLiveQuery', function () { role.getUsers().add(user); await role.save(); - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 2000)); object.set('foo', 'yolo'); await Promise.all([ new Promise(resolve => { diff --git a/src/Controllers/LiveQueryController.js b/src/Controllers/LiveQueryController.js index 9a5b6d0ef1..66568880a9 100644 --- a/src/Controllers/LiveQueryController.js +++ b/src/Controllers/LiveQueryController.js @@ -57,6 +57,7 @@ export class LiveQueryController { } clearCachedRoles(user: any) { + console.log('clear cache =>', user); if (!user) { return; } From fb3ffe205dd06dbefc85c022685089296c3ae5ad Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 7 Jun 2022 20:22:17 +1000 Subject: [PATCH 05/19] log --- src/Controllers/LiveQueryController.js | 1 - src/LiveQuery/ParseLiveQueryServer.js | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controllers/LiveQueryController.js b/src/Controllers/LiveQueryController.js index 66568880a9..9a5b6d0ef1 100644 --- a/src/Controllers/LiveQueryController.js +++ b/src/Controllers/LiveQueryController.js @@ -57,7 +57,6 @@ export class LiveQueryController { } clearCachedRoles(user: any) { - console.log('clear cache =>', user); if (!user) { return; } diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 171e3d6b50..eeb90bc638 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -494,6 +494,7 @@ class ParseLiveQueryServer { const { auth } = await authPromise; auth.clearRoleCache(); this.authCache.del(sessionToken); + console.log('did clear', this.authCache.get(sessionToken)); }) ); } catch (e) { From c754c323ad54816e648262355714cb2221bc392e Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 7 Jun 2022 21:32:07 +1000 Subject: [PATCH 06/19] more log --- src/Auth.js | 2 ++ src/LiveQuery/ParseLiveQueryServer.js | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Auth.js b/src/Auth.js index 32c912769d..222fd11ff9 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -184,6 +184,7 @@ Auth.prototype.getRolesForUser = async function () { Auth.prototype._loadRoles = async function () { if (this.cacheController) { const cachedRoles = await this.cacheController.role.get(this.user.id); + console.log({ cachedRoles }); if (cachedRoles != null) { this.fetchedRoles = true; this.userRoles = cachedRoles; @@ -235,6 +236,7 @@ Auth.prototype.clearRoleCache = function () { return false; } this.cacheController.role.del(this.user.id); + console.log('clear', this.user.id); return true; }; diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index eeb90bc638..b6d3dfd754 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -610,7 +610,6 @@ class ParseLiveQueryServer { } const roleNames = await auth.getUserRoles(); - console.log({ roleNames }); // Finally, see if any of the user's roles allow them read access for (const role of roleNames) { // We use getReadAccess as `role` is in the form `role:roleName` From 846f3c69fb059cd0c9ef7016e8b39ad077ef07e1 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 8 Jun 2022 12:07:21 +1000 Subject: [PATCH 07/19] clear user cache --- src/Auth.js | 3 ++- src/LiveQuery/ParseLiveQueryServer.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Auth.js b/src/Auth.js index 222fd11ff9..73c0700aca 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -231,11 +231,12 @@ Auth.prototype.cacheRoles = function () { return true; }; -Auth.prototype.clearRoleCache = function () { +Auth.prototype.clearRoleCache = function (sessionToken) { if (!this.cacheController) { return false; } this.cacheController.role.del(this.user.id); + this.cacheController.user.del(sessionToken); console.log('clear', this.user.id); return true; }; diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index b6d3dfd754..c1f29fff58 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -492,7 +492,7 @@ class ParseLiveQueryServer { return; } const { auth } = await authPromise; - auth.clearRoleCache(); + auth.clearRoleCache(sessionToken); this.authCache.del(sessionToken); console.log('did clear', this.authCache.get(sessionToken)); }) From a406b24a4e5006deef402c841337ea6da967d709 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 8 Jun 2022 12:42:23 +1000 Subject: [PATCH 08/19] more log --- src/Auth.js | 3 ++- src/LiveQuery/ParseLiveQueryServer.js | 13 +++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Auth.js b/src/Auth.js index 73c0700aca..ba2707658f 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -231,13 +231,14 @@ Auth.prototype.cacheRoles = function () { return true; }; -Auth.prototype.clearRoleCache = function (sessionToken) { +Auth.prototype.clearRoleCache = async function (sessionToken) { if (!this.cacheController) { return false; } this.cacheController.role.del(this.user.id); this.cacheController.user.del(sessionToken); console.log('clear', this.user.id); + console.log(await this.cacheController.role.get(this.user.id)); return true; }; diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index c1f29fff58..908f3c3ecf 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -91,6 +91,7 @@ class ParseLiveQueryServer { } if (channel === Parse.applicationId + 'clearCache') { this._clearCachedRoles(message.userId); + console.log('did clear cache...'); return; } this._inflateParseObject(message); @@ -491,13 +492,17 @@ class ParseLiveQueryServer { if (!authPromise) { return; } - const { auth } = await authPromise; - auth.clearRoleCache(sessionToken); + const [auth1, auth2] = await Promise.all([ + authPromise, + getAuthForSessionToken({ cacheController: this.cacheController, sessionToken }), + ]); + auth1.auth?.clearRoleCache(sessionToken); + auth2.auth?.clearRoleCache(sessionToken); this.authCache.del(sessionToken); - console.log('did clear', this.authCache.get(sessionToken)); }) ); } catch (e) { + console.log(e); logger.verbose(`Could not clear role cache. ${e}`); } } @@ -608,8 +613,8 @@ class ParseLiveQueryServer { if (!acl_has_roles) { return false; } - const roleNames = await auth.getUserRoles(); + console.log({ roleNames, token }); // Finally, see if any of the user's roles allow them read access for (const role of roleNames) { // We use getReadAccess as `role` is in the form `role:roleName` From e9f64722b6ba3e5eccfebcbf985864caaff21f87 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 8 Jun 2022 16:24:57 +1000 Subject: [PATCH 09/19] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 908f3c3ecf..1daf9a191c 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -485,6 +485,7 @@ class ParseLiveQueryServer { const validTokens = await new Parse.Query(Parse.Session) .equalTo('user', Parse.User.createWithoutData(userId)) .find({ useMasterKey: true }); + console.log('clearing', userId); await Promise.all( validTokens.map(async token => { const sessionToken = token.get('sessionToken'); @@ -499,6 +500,7 @@ class ParseLiveQueryServer { auth1.auth?.clearRoleCache(sessionToken); auth2.auth?.clearRoleCache(sessionToken); this.authCache.del(sessionToken); + console.log('DID Clear', sessionToken); }) ); } catch (e) { From 89f467a22ed55015fb8c8e083e2d24a00393ef56 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 8 Jun 2022 17:01:26 +1000 Subject: [PATCH 10/19] logs --- src/Auth.js | 4 +- src/LiveQuery/ParseLiveQueryServer.js | 53 ++++++++++++++------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/Auth.js b/src/Auth.js index ba2707658f..00cfb77256 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -183,6 +183,7 @@ Auth.prototype.getRolesForUser = async function () { // Iterates through the role tree and compiles a user's roles Auth.prototype._loadRoles = async function () { if (this.cacheController) { + console.log(this.cacheController.role); const cachedRoles = await this.cacheController.role.get(this.user.id); console.log({ cachedRoles }); if (cachedRoles != null) { @@ -231,14 +232,13 @@ Auth.prototype.cacheRoles = function () { return true; }; -Auth.prototype.clearRoleCache = async function (sessionToken) { +Auth.prototype.clearRoleCache = function (sessionToken) { if (!this.cacheController) { return false; } this.cacheController.role.del(this.user.id); this.cacheController.user.del(sessionToken); console.log('clear', this.user.id); - console.log(await this.cacheController.role.get(this.user.id)); return true; }; diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 1daf9a191c..ec241b0377 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -481,32 +481,33 @@ class ParseLiveQueryServer { } async _clearCachedRoles(userId: string) { - try { - const validTokens = await new Parse.Query(Parse.Session) - .equalTo('user', Parse.User.createWithoutData(userId)) - .find({ useMasterKey: true }); - console.log('clearing', userId); - await Promise.all( - validTokens.map(async token => { - const sessionToken = token.get('sessionToken'); - const authPromise = this.authCache.get(sessionToken); - if (!authPromise) { - return; - } - const [auth1, auth2] = await Promise.all([ - authPromise, - getAuthForSessionToken({ cacheController: this.cacheController, sessionToken }), - ]); - auth1.auth?.clearRoleCache(sessionToken); - auth2.auth?.clearRoleCache(sessionToken); - this.authCache.del(sessionToken); - console.log('DID Clear', sessionToken); - }) - ); - } catch (e) { - console.log(e); - logger.verbose(`Could not clear role cache. ${e}`); - } + this.authCache.clear(); + // try { + // const validTokens = await new Parse.Query(Parse.Session) + // .equalTo('user', Parse.User.createWithoutData(userId)) + // .find({ useMasterKey: true }); + // console.log('clearing', userId); + // await Promise.all( + // validTokens.map(async token => { + // const sessionToken = token.get('sessionToken'); + // const authPromise = this.authCache.get(sessionToken); + // if (!authPromise) { + // return; + // } + // const [auth1, auth2] = await Promise.all([ + // authPromise, + // getAuthForSessionToken({ cacheController: this.cacheController, sessionToken }), + // ]); + // auth1.auth?.clearRoleCache(sessionToken); + // auth2.auth?.clearRoleCache(sessionToken); + // this.authCache.del(sessionToken); + // console.log('DID Clear', sessionToken); + // }) + // ); + // } catch (e) { + // console.log(e); + // logger.verbose(`Could not clear role cache. ${e}`); + // } } getAuthForSessionToken(sessionToken: ?string): Promise<{ auth: ?Auth, userId: ?string }> { From 171cc39b5cb5361a282a0ac9047bb017cc1743fd Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 8 Jun 2022 17:13:28 +1000 Subject: [PATCH 11/19] reorder --- spec/ParseLiveQuery.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 19ff6951eb..8796646d44 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -865,8 +865,8 @@ describe('ParseLiveQuery', function () { await object.save(null, { useMasterKey: true }); role.getUsers().add(user); - await role.save(); await new Promise(resolve => setTimeout(resolve, 2000)); + await role.save(); object.set('foo', 'yolo'); await Promise.all([ new Promise(resolve => { From ab85c325d8ed135a0777077f44df08cb2e45592a Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 8 Jun 2022 17:31:03 +1000 Subject: [PATCH 12/19] lint --- src/LiveQuery/ParseLiveQueryServer.js | 53 +++++++++++++-------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index ec241b0377..1daf9a191c 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -481,33 +481,32 @@ class ParseLiveQueryServer { } async _clearCachedRoles(userId: string) { - this.authCache.clear(); - // try { - // const validTokens = await new Parse.Query(Parse.Session) - // .equalTo('user', Parse.User.createWithoutData(userId)) - // .find({ useMasterKey: true }); - // console.log('clearing', userId); - // await Promise.all( - // validTokens.map(async token => { - // const sessionToken = token.get('sessionToken'); - // const authPromise = this.authCache.get(sessionToken); - // if (!authPromise) { - // return; - // } - // const [auth1, auth2] = await Promise.all([ - // authPromise, - // getAuthForSessionToken({ cacheController: this.cacheController, sessionToken }), - // ]); - // auth1.auth?.clearRoleCache(sessionToken); - // auth2.auth?.clearRoleCache(sessionToken); - // this.authCache.del(sessionToken); - // console.log('DID Clear', sessionToken); - // }) - // ); - // } catch (e) { - // console.log(e); - // logger.verbose(`Could not clear role cache. ${e}`); - // } + try { + const validTokens = await new Parse.Query(Parse.Session) + .equalTo('user', Parse.User.createWithoutData(userId)) + .find({ useMasterKey: true }); + console.log('clearing', userId); + await Promise.all( + validTokens.map(async token => { + const sessionToken = token.get('sessionToken'); + const authPromise = this.authCache.get(sessionToken); + if (!authPromise) { + return; + } + const [auth1, auth2] = await Promise.all([ + authPromise, + getAuthForSessionToken({ cacheController: this.cacheController, sessionToken }), + ]); + auth1.auth?.clearRoleCache(sessionToken); + auth2.auth?.clearRoleCache(sessionToken); + this.authCache.del(sessionToken); + console.log('DID Clear', sessionToken); + }) + ); + } catch (e) { + console.log(e); + logger.verbose(`Could not clear role cache. ${e}`); + } } getAuthForSessionToken(sessionToken: ?string): Promise<{ auth: ?Auth, userId: ?string }> { From 6762d738bb9d28e2ef7ae6d6bab10a3091674ed4 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 9 Jun 2022 00:18:00 +1000 Subject: [PATCH 13/19] Update src/LiveQuery/ParseLiveQueryServer.js Co-authored-by: Antoine Cormouls --- src/LiveQuery/ParseLiveQueryServer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 1daf9a191c..db397c49a6 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -616,7 +616,6 @@ class ParseLiveQueryServer { return false; } const roleNames = await auth.getUserRoles(); - console.log({ roleNames, token }); // Finally, see if any of the user's roles allow them read access for (const role of roleNames) { // We use getReadAccess as `role` is in the form `role:roleName` From 624eeb95e51a3ef37d9681f87165aa013a8180d3 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 9 Jun 2022 00:18:07 +1000 Subject: [PATCH 14/19] Update src/LiveQuery/ParseLiveQueryServer.js Co-authored-by: Antoine Cormouls --- src/LiveQuery/ParseLiveQueryServer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index db397c49a6..b0bda8fe05 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -504,7 +504,6 @@ class ParseLiveQueryServer { }) ); } catch (e) { - console.log(e); logger.verbose(`Could not clear role cache. ${e}`); } } From c1bbb0629f4e9a5f07bc5cb094fa90c749f93b52 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 9 Jun 2022 00:18:14 +1000 Subject: [PATCH 15/19] Update src/LiveQuery/ParseLiveQueryServer.js Co-authored-by: Antoine Cormouls --- src/LiveQuery/ParseLiveQueryServer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index b0bda8fe05..ed5994c37c 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -500,7 +500,6 @@ class ParseLiveQueryServer { auth1.auth?.clearRoleCache(sessionToken); auth2.auth?.clearRoleCache(sessionToken); this.authCache.del(sessionToken); - console.log('DID Clear', sessionToken); }) ); } catch (e) { From eb7e79bcb31c34b9ecb93bece885c9eacf1bb5d6 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 9 Jun 2022 00:18:20 +1000 Subject: [PATCH 16/19] Update src/LiveQuery/ParseLiveQueryServer.js Co-authored-by: Antoine Cormouls --- src/LiveQuery/ParseLiveQueryServer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index ed5994c37c..4c4545eeb2 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -485,7 +485,6 @@ class ParseLiveQueryServer { const validTokens = await new Parse.Query(Parse.Session) .equalTo('user', Parse.User.createWithoutData(userId)) .find({ useMasterKey: true }); - console.log('clearing', userId); await Promise.all( validTokens.map(async token => { const sessionToken = token.get('sessionToken'); From 99b12d45015ba5d7418c694ee04ad480225b3c9f Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 9 Jun 2022 00:35:32 +1000 Subject: [PATCH 17/19] remove logging --- src/Auth.js | 3 --- src/LiveQuery/ParseLiveQueryServer.js | 1 - 2 files changed, 4 deletions(-) diff --git a/src/Auth.js b/src/Auth.js index 00cfb77256..ce5c71c860 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -183,9 +183,7 @@ Auth.prototype.getRolesForUser = async function () { // Iterates through the role tree and compiles a user's roles Auth.prototype._loadRoles = async function () { if (this.cacheController) { - console.log(this.cacheController.role); const cachedRoles = await this.cacheController.role.get(this.user.id); - console.log({ cachedRoles }); if (cachedRoles != null) { this.fetchedRoles = true; this.userRoles = cachedRoles; @@ -238,7 +236,6 @@ Auth.prototype.clearRoleCache = function (sessionToken) { } this.cacheController.role.del(this.user.id); this.cacheController.user.del(sessionToken); - console.log('clear', this.user.id); return true; }; diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 4c4545eeb2..3a91797a2f 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -91,7 +91,6 @@ class ParseLiveQueryServer { } if (channel === Parse.applicationId + 'clearCache') { this._clearCachedRoles(message.userId); - console.log('did clear cache...'); return; } this._inflateParseObject(message); From 5438cb127539d391539c897a1dff079e9011e1c1 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 9 Jun 2022 10:36:09 +1000 Subject: [PATCH 18/19] Update ParseLiveQuery.spec.js --- spec/ParseLiveQuery.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 8796646d44..dd0610f966 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -863,10 +863,10 @@ describe('ParseLiveQuery', function () { object.setACL(acl); object.set({ foo: 'bar' }); await object.save(null, { useMasterKey: true }); - role.getUsers().add(user); - await new Promise(resolve => setTimeout(resolve, 2000)); + await new Promise(resolve => setTimeout(resolve, 1000)); await role.save(); + await new Promise(resolve => setTimeout(resolve, 1000)); object.set('foo', 'yolo'); await Promise.all([ new Promise(resolve => { From 92ce1cd7a766bde2fddb1697057426da05d92c65 Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 10 Jun 2022 12:49:37 +1000 Subject: [PATCH 19/19] Update RestWrite.js --- src/RestWrite.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/RestWrite.js b/src/RestWrite.js index 482e297ccd..2be833ad30 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -1326,7 +1326,9 @@ RestWrite.prototype.runDatabaseOperation = function () { if (this.className === '_Role') { this.config.cacheController.role.clear(); - this.config.liveQueryController.clearCachedRoles(this.auth.user); + if (this.config.liveQueryController) { + this.config.liveQueryController.clearCachedRoles(this.auth.user); + } } if (this.className === '_User' && this.query && this.auth.isUnauthenticated()) {