@@ -50,7 +50,7 @@ import {
5050} from '../../../lib/server/functions/checkUsernameAvailability' ;
5151import { deleteUser } from '../../../lib/server/functions/deleteUser' ;
5252import { getAvatarSuggestionForUser } from '../../../lib/server/functions/getAvatarSuggestionForUser' ;
53- import { getFullUserDataByIdOrUsernameOrImportId } from '../../../lib/server/functions/getFullUserData' ;
53+ import { getFullUserDataByIdOrUsernameOrImportId , defaultFields , fullFields } from '../../../lib/server/functions/getFullUserData' ;
5454import { generateUsernameSuggestion } from '../../../lib/server/functions/getUsernameSuggestion' ;
5555import { saveCustomFields } from '../../../lib/server/functions/saveCustomFields' ;
5656import { saveCustomFieldsWithoutValidation } from '../../../lib/server/functions/saveCustomFieldsWithoutValidation' ;
@@ -503,13 +503,18 @@ API.v1.addRoute(
503503 const { offset, count } = await getPaginationItems ( this . queryParams ) ;
504504 const { sort, fields, query } = await this . parseJsonQuery ( ) ;
505505
506- const nonEmptyQuery = getNonEmptyQuery ( query , await hasPermissionAsync ( this . userId , 'view-full-other-user-info' ) ) ;
507506 const nonEmptyFields = getNonEmptyFields ( fields ) ;
508507
509508 const inclusiveFields = getInclusiveFields ( nonEmptyFields ) ;
510509
511510 const inclusiveFieldsKeys = Object . keys ( inclusiveFields ) ;
512511
512+ const hasUserQuery = query && Object . keys ( query ) . length > 0 ;
513+
514+ const nonEmptyQuery = getNonEmptyQuery ( query , await hasPermissionAsync ( this . userId , 'view-full-other-user-info' ) ) ;
515+
516+ // if user provided a query, validate it with their allowed operators
517+ // otherwise we use the default query (with $regex and $options)
513518 if (
514519 ! isValidQuery (
515520 nonEmptyQuery ,
@@ -521,7 +526,7 @@ API.v1.addRoute(
521526 inclusiveFieldsKeys . includes ( 'type' ) && 'type.*' ,
522527 inclusiveFieldsKeys . includes ( 'customFields' ) && 'customFields.*' ,
523528 ] . filter ( Boolean ) as string [ ] ,
524- this . queryOperations ,
529+ hasUserQuery ? this . queryOperations : [ ... this . queryOperations , '$regex' , '$options' ] ,
525530 )
526531 ) {
527532 throw new Meteor . Error ( 'error-invalid-query' , isValidQuery . errors . join ( '\n' ) ) ;
@@ -1145,8 +1150,13 @@ API.v1.addRoute(
11451150 const selector : { exceptions : Required < IUser > [ 'username' ] [ ] ; conditions : Filter < IUser > ; term : string } = JSON . parse ( selectorRaw ) ;
11461151
11471152 try {
1148- if ( selector ?. conditions && ! isValidQuery ( selector . conditions , [ '*' ] , [ '$or' , '$and' ] ) ) {
1149- throw new Error ( 'error-invalid-query' ) ;
1153+ if ( selector ?. conditions ) {
1154+ const canViewFullInfo = await hasPermissionAsync ( this . userId , 'view-full-other-user-info' ) ;
1155+ const allowedFields = canViewFullInfo ? [ ...Object . keys ( defaultFields ) , ...Object . keys ( fullFields ) ] : Object . keys ( defaultFields ) ;
1156+
1157+ if ( ! isValidQuery ( selector . conditions , allowedFields , [ '$and' , '$ne' , '$exists' ] ) ) {
1158+ throw new Error ( 'error-invalid-query' ) ;
1159+ }
11501160 }
11511161 } catch ( e ) {
11521162 return API . v1 . failure ( e ) ;
0 commit comments