@@ -195,12 +195,73 @@ const filterSensitiveData = (
195
195
isMaster : boolean ,
196
196
aclGroup : any [ ] ,
197
197
auth : any ,
198
+ operation : any ,
199
+ schema : SchemaController . SchemaController ,
198
200
className : string ,
199
201
protectedFields : null | Array < any > ,
200
202
object : any
201
203
) => {
204
+ let userId = null ;
205
+ if ( auth && auth . user ) userId = auth . user . id ;
206
+
207
+ // replace protectedFields when using pointer-permissions
208
+ const perms = schema . getClassLevelPermissions ( className ) ;
209
+ if ( perms ) {
210
+ const field =
211
+ [ 'get' , 'find' ] . indexOf ( operation ) > - 1
212
+ ? 'readUserFields'
213
+ : 'writeUserFields' ;
214
+ const fieldKeys : string [ ] = perms [ field ] ;
215
+
216
+ if (
217
+ field === 'readUserFields' &&
218
+ fieldKeys &&
219
+ fieldKeys . length > 0 &&
220
+ perms . protectedFields
221
+ ) {
222
+ // extract protectedFields added with the pointer-permission prefix
223
+ const protectedFieldsPointerPerm = Object . keys ( perms . protectedFields )
224
+ . filter ( key => key . startsWith ( 'readUserFields:' ) )
225
+ . map ( key => {
226
+ return { key : key . substring ( 15 ) , value : perms . protectedFields [ key ] } ;
227
+ } ) ;
228
+
229
+ const newProtectedFields : Array < string > = [];
230
+ let overrideProtectedFields = false;
231
+
232
+ // check if the object grants the current user access based on the extracted fields
233
+ protectedFieldsPointerPerm.forEach(pointerPerm => {
234
+ if ( ! fieldKeys . includes ( pointerPerm . key ) ) return ;
235
+ let pointerPermIncludesUser = false ;
236
+ const readUserFieldValue = object [ pointerPerm . key ] ;
237
+ if ( readUserFieldValue ) {
238
+ if ( Array . isArray ( readUserFieldValue ) ) {
239
+ pointerPermIncludesUser = readUserFieldValue . some (
240
+ user => user . objectId && user . objectId === userId
241
+ ) ;
242
+ } else {
243
+ pointerPermIncludesUser =
244
+ readUserFieldValue . objectId &&
245
+ readUserFieldValue . objectId === userId ;
246
+ }
247
+ }
248
+
249
+ if ( pointerPermIncludesUser ) {
250
+ overrideProtectedFields = true ;
251
+ newProtectedFields . push ( ...pointerPerm . value ) ;
252
+ }
253
+ } ) ;
254
+
255
+ // if atleast one pointer-permission affected the current user override the protectedFields
256
+ if ( overrideProtectedFields ) protectedFields = newProtectedFields ;
257
+ }
258
+ }
259
+
202
260
const isUserClass = className === '_User' ;
203
- if ( ! isUserClass || ! auth || ! auth . user || object . objectId !== auth . user . id )
261
+
262
+ /* special treat for the user class: don't filter protectedFields if currently loggedin user is
263
+ the retrieved user */
264
+ if ( ! ( isUserClass && userId && object . objectId === userId ) )
204
265
protectedFields && protectedFields . forEach ( k => delete object [ k ] ) ;
205
266
206
267
if ( ! isUserClass ) {
@@ -1318,8 +1379,9 @@ class DatabaseController {
1318
1379
query ,
1319
1380
aclGroup
1320
1381
) ;
1321
- // ProtectedFields is generated before executing the query so we
1322
- // can optimize the query using Mongo Projection at a later stage.
1382
+ /* Don't use projections to optimize the protectedFields since the protectedFields
1383
+ based on pointer-permissions are determined after querying. The filtering can
1384
+ overwrite the protected fields. */
1323
1385
protectedFields = this . addProtectedFields (
1324
1386
schemaController ,
1325
1387
className ,
@@ -1389,6 +1451,8 @@ class DatabaseController {
1389
1451
isMaster ,
1390
1452
aclGroup ,
1391
1453
auth ,
1454
+ op ,
1455
+ schemaController ,
1392
1456
className ,
1393
1457
protectedFields ,
1394
1458
object
0 commit comments