diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 43e91e03bb..65d1836c5f 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -645,6 +645,69 @@ describe('ParseLiveQuery', function () { await object.save(); }); + it('LiveQuery with ACL', async () => { + await reconfigureServer({ + liveQuery: { + classNames: ['Chat'], + }, + startLiveQueryServer: true, + verbose: false, + silent: true, + }); + const user = new Parse.User(); + user.setUsername('username'); + user.setPassword('password'); + await user.signUp(); + + const calls = { + beforeConnect(req) { + expect(req.event).toBe('connect'); + expect(req.clients).toBe(0); + expect(req.subscriptions).toBe(0); + expect(req.useMasterKey).toBe(false); + expect(req.installationId).toBeDefined(); + expect(req.client).toBeDefined(); + }, + beforeSubscribe(req) { + expect(req.op).toBe('subscribe'); + expect(req.requestId).toBe(1); + expect(req.query).toBeDefined(); + expect(req.user).toBeDefined(); + }, + afterLiveQueryEvent(req) { + expect(req.user).toBeDefined(); + expect(req.object.get('foo')).toBe('bar'); + }, + create(object) { + expect(object.get('foo')).toBe('bar'); + }, + delete(object) { + expect(object.get('foo')).toBe('bar'); + }, + }; + for (const key in calls) { + spyOn(calls, key).and.callThrough(); + } + Parse.Cloud.beforeConnect(calls.beforeConnect); + Parse.Cloud.beforeSubscribe('Chat', calls.beforeSubscribe); + Parse.Cloud.afterLiveQueryEvent('Chat', calls.afterLiveQueryEvent); + + const chatQuery = new Parse.Query('Chat'); + const subscription = await chatQuery.subscribe(); + subscription.on('create', calls.create); + subscription.on('delete', calls.delete); + const object = new Parse.Object('Chat'); + const acl = new Parse.ACL(user); + object.setACL(acl); + object.set({ foo: 'bar' }); + await object.save(); + await object.destroy(); + await new Promise(resolve => setTimeout(resolve, 200)); + for (const key in calls) { + expect(calls[key]).toHaveBeenCalled(); + } + }); + it('handle invalid websocket payload length', async done => { await reconfigureServer({ liveQuery: { diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index d60615d5b5..5a44ae5c8b 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -170,8 +170,10 @@ class ParseLiveQueryServer { }; const trigger = getTrigger(className, 'afterEvent', Parse.applicationId); if (trigger) { - const auth = await this.getAuthForSessionToken(res.sessionToken); - res.user = auth.user; + const auth = await this.getAuthFromClient(client, requestId); + if (auth && auth.user) { + res.user = auth.user; + } if (res.object) { res.object = Parse.Object.fromJSON(res.object); } @@ -317,8 +319,10 @@ class ParseLiveQueryServer { if (res.original) { res.original = Parse.Object.fromJSON(res.original); } - const auth = await this.getAuthForSessionToken(res.sessionToken); - res.user = auth.user; + const auth = await this.getAuthFromClient(client, requestId); + if (auth && auth.user) { + res.user = auth.user; + } await runTrigger(trigger, `afterEvent.${className}`, res, auth); } if (!res.sendEvent) { @@ -579,6 +583,24 @@ class ParseLiveQueryServer { }); } + async getAuthFromClient(client: any, requestId: number, sessionToken: string) { + const getSessionFromClient = () => { + const subscriptionInfo = client.getSubscriptionInfo(requestId); + if (typeof subscriptionInfo === 'undefined') { + return client.sessionToken; + } + return subscriptionInfo.sessionToken || client.sessionToken; + }; + if (!sessionToken) { + sessionToken = getSessionFromClient(); + } + if (!sessionToken) { + return; + } + const { auth } = await this.getAuthForSessionToken(sessionToken); + return auth; + } + async _matchesACL(acl: any, client: any, requestId: number): Promise { // Return true directly if ACL isn't present, ACL is public read, or client has master key if (!acl || acl.getPublicReadAccess() || client.hasMasterKey) { @@ -631,8 +653,10 @@ class ParseLiveQueryServer { }; const trigger = getTrigger('@Connect', 'beforeConnect', Parse.applicationId); if (trigger) { - const auth = await this.getAuthForSessionToken(req.sessionToken); - req.user = auth.user; + const auth = await this.getAuthFromClient(client, request.requestId, req.sessionToken); + if (auth && auth.user) { + req.user = auth.user; + } await runTrigger(trigger, `beforeConnect.@Connect`, req, auth); } parseWebsocket.clientId = clientId; @@ -690,8 +714,10 @@ class ParseLiveQueryServer { try { const trigger = getTrigger(className, 'beforeSubscribe', Parse.applicationId); if (trigger) { - const auth = await this.getAuthForSessionToken(request.sessionToken); - request.user = auth.user; + const auth = await this.getAuthFromClient(client, request.requestId, request.sessionToken); + if (auth && auth.user) { + request.user = auth.user; + } const parseQuery = new Parse.Query(className); parseQuery.withJSON(request.query);