@@ -195,12 +195,73 @@ const filterSensitiveData = (
195195 isMaster : boolean ,
196196 aclGroup : any [ ] ,
197197 auth : any ,
198+ operation : any ,
199+ schema : SchemaController . SchemaController ,
198200 className : string ,
199201 protectedFields : null | Array < any > ,
200202 object : any
201203) => {
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+
202260 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 ) )
204265 protectedFields && protectedFields . forEach ( k => delete object [ k ] ) ;
205266
206267 if ( ! isUserClass ) {
@@ -1318,8 +1379,9 @@ class DatabaseController {
13181379 query ,
13191380 aclGroup
13201381 ) ;
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. */
13231385 protectedFields = this . addProtectedFields (
13241386 schemaController ,
13251387 className ,
@@ -1389,6 +1451,8 @@ class DatabaseController {
13891451 isMaster ,
13901452 aclGroup ,
13911453 auth ,
1454+ op ,
1455+ schemaController ,
13921456 className ,
13931457 protectedFields ,
13941458 object
0 commit comments