@@ -8,6 +8,7 @@ import RequestSchema from './RequestSchema';
8
8
import { matchesQuery , queryHash } from './QueryTools' ;
9
9
import { ParsePubSub } from './ParsePubSub' ;
10
10
import { SessionTokenCache } from './SessionTokenCache' ;
11
+ import SchemaController from '../Controllers/SchemaController' ;
11
12
import _ from 'lodash' ;
12
13
import uuid from 'uuid' ;
13
14
import { runLiveQueryEventHandlers } from '../triggers' ;
@@ -107,6 +108,7 @@ class ParseLiveQueryServer {
107
108
logger . verbose ( Parse . applicationId + 'afterDelete is triggered' ) ;
108
109
109
110
const deletedParseObject = message . currentParseObject . toJSON ( ) ;
111
+ const classLevelPermissions = message . classLevelPermissions ;
110
112
const className = deletedParseObject . className ;
111
113
logger . verbose ( 'ClassName: %j | ObjectId: %s' , className , deletedParseObject . id ) ;
112
114
logger . verbose ( 'Current client number : %d' , this . clients . size ) ;
@@ -128,13 +130,17 @@ class ParseLiveQueryServer {
128
130
}
129
131
for ( const requestId of requestIds ) {
130
132
const acl = message . currentParseObject . getACL ( ) ;
131
- // Check ACL
132
- this . _matchesACL ( acl , client , requestId ) . then ( ( isMatched ) => {
133
+ // Check CLP
134
+ const op = this . _getCLPOperation ( subscription . query ) ;
135
+ this . _matchesCLP ( classLevelPermissions , message . currentParseObject , client , requestId , op ) . then ( ( ) => {
136
+ // Check ACL
137
+ return this . _matchesACL ( acl , client , requestId )
138
+ } ) . then ( ( isMatched ) => {
133
139
if ( ! isMatched ) {
134
140
return null ;
135
141
}
136
142
client . pushDelete ( requestId , deletedParseObject ) ;
137
- } , ( error ) => {
143
+ } ) . catch ( ( error ) => {
138
144
logger . error ( 'Matching ACL error : ' , error ) ;
139
145
} ) ;
140
146
}
@@ -151,6 +157,7 @@ class ParseLiveQueryServer {
151
157
if ( message . originalParseObject ) {
152
158
originalParseObject = message . originalParseObject . toJSON ( ) ;
153
159
}
160
+ const classLevelPermissions = message . classLevelPermissions ;
154
161
const currentParseObject = message . currentParseObject . toJSON ( ) ;
155
162
const className = currentParseObject . className ;
156
163
logger . verbose ( 'ClassName: %s | ObjectId: %s' , className , currentParseObject . id ) ;
@@ -191,11 +198,13 @@ class ParseLiveQueryServer {
191
198
const currentACL = message . currentParseObject . getACL ( ) ;
192
199
currentACLCheckingPromise = this . _matchesACL ( currentACL , client , requestId ) ;
193
200
}
194
-
195
- Parse . Promise . when (
196
- originalACLCheckingPromise ,
197
- currentACLCheckingPromise
198
- ) . then ( ( isOriginalMatched , isCurrentMatched ) => {
201
+ const op = this . _getCLPOperation ( subscription . query ) ;
202
+ this . _matchesCLP ( classLevelPermissions , message . currentParseObject , client , requestId , op ) . then ( ( ) => {
203
+ return Parse . Promise . when (
204
+ originalACLCheckingPromise ,
205
+ currentACLCheckingPromise
206
+ ) ;
207
+ } ) . then ( ( isOriginalMatched , isCurrentMatched ) => {
199
208
logger . verbose ( 'Original %j | Current %j | Match: %s, %s, %s, %s | Query: %s' ,
200
209
originalParseObject ,
201
210
currentParseObject ,
@@ -327,6 +336,52 @@ class ParseLiveQueryServer {
327
336
return matchesQuery ( parseObject , subscription . query ) ;
328
337
}
329
338
339
+ _matchesCLP ( classLevelPermissions : ?any , object : any , client : any , requestId : number , op : string ) : any {
340
+ return Parse . Promise . as ( ) . then ( ( ) => {
341
+ // try to match on user first, less expensive than with roles
342
+ const subscriptionInfo = client . getSubscriptionInfo ( requestId ) ;
343
+ if ( typeof subscriptionInfo === 'undefined' ) {
344
+ return Parse . Promise . as ( [ '*' ] ) ;
345
+ }
346
+ let foundUserId ;
347
+ const subscriptionSessionToken = subscriptionInfo . sessionToken ;
348
+ return this . sessionTokenCache . getUserId ( subscriptionSessionToken ) . then ( ( userId ) => {
349
+ foundUserId = userId ;
350
+ if ( userId ) {
351
+ return Parse . Promise . as ( [ '*' , userId ] ) ;
352
+ }
353
+ return Parse . Promise . as ( [ '*' ] ) ;
354
+ } ) . then ( ( aclGroup ) => {
355
+ console . log ( aclGroup ) ; // eslint-disable-line
356
+ try {
357
+ return SchemaController . validatePermission ( classLevelPermissions , object . className , aclGroup , op ) . then ( ( ) => {
358
+ return Parse . Promise . as ( true ) ;
359
+ } ) ;
360
+ } catch ( e ) {
361
+ logger . verbose ( `Failed matching CLP for ${ object . id } ${ foundUserId } ${ e } ` ) ;
362
+ return Parse . Promise . as ( false ) ;
363
+ }
364
+ // TODO: handle roles permissions
365
+ // Object.keys(classLevelPermissions).forEach((key) => {
366
+ // const perm = classLevelPermissions[key];
367
+ // Object.keys(perm).forEach((key) => {
368
+ // if (key.indexOf('role'))
369
+ // });
370
+ // })
371
+ // // it's rejected here, check the roles
372
+ // var rolesQuery = new Parse.Query(Parse.Role);
373
+ // rolesQuery.equalTo("users", user);
374
+ // return rolesQuery.find({useMasterKey:true});
375
+ } ) ;
376
+ } )
377
+ }
378
+
379
+ _getCLPOperation ( query : any ) {
380
+ return typeof query == 'object'
381
+ && Object . keys ( query ) . length == 1
382
+ && typeof query . objectId === 'string' ? 'get' : 'find' ;
383
+ }
384
+
330
385
_matchesACL ( acl : any , client : any , requestId : number ) : any {
331
386
// Return true directly if ACL isn't present, ACL is public read, or client has master key
332
387
if ( ! acl || acl . getPublicReadAccess ( ) || client . hasMasterKey ) {
0 commit comments