@@ -56,17 +56,59 @@ const transformObjectACL = ({ ACL, ...result }) => {
5656 return result ;
5757} ;
5858
59- const specialQueryKeys = [ '$and' , '$or' , '$nor' , '_rperm' , '_wperm' ] ;
59+ // Query operators that always pass validation regardless of auth level.
60+ const queryOperators = [ '$and' , '$or' , '$nor' ] ;
61+
62+ // Registry of internal fields with access permissions.
63+ // Internal fields are never directly writable by clients, so clientWrite is omitted.
64+ // - clientRead: any client can use this field in queries
65+ // - masterRead: master key can use this field in queries
66+ // - masterWrite: master key can use this field in updates
67+ const internalFields = {
68+ _rperm : { clientRead : true , masterRead : true , masterWrite : true } ,
69+ _wperm : { clientRead : true , masterRead : true , masterWrite : true } ,
70+ _hashed_password : { clientRead : false , masterRead : false , masterWrite : true } ,
71+ _email_verify_token : { clientRead : false , masterRead : true , masterWrite : true } ,
72+ _perishable_token : { clientRead : false , masterRead : true , masterWrite : true } ,
73+ _perishable_token_expires_at : { clientRead : false , masterRead : true , masterWrite : true } ,
74+ _email_verify_token_expires_at : { clientRead : false , masterRead : true , masterWrite : true } ,
75+ _failed_login_count : { clientRead : false , masterRead : true , masterWrite : true } ,
76+ _account_lockout_expires_at : { clientRead : false , masterRead : true , masterWrite : true } ,
77+ _password_changed_at : { clientRead : false , masterRead : true , masterWrite : true } ,
78+ _password_history : { clientRead : false , masterRead : true , masterWrite : true } ,
79+ _tombstone : { clientRead : false , masterRead : true , masterWrite : false } ,
80+ _session_token : { clientRead : false , masterRead : true , masterWrite : false } ,
81+ /////////////////////////////////////////////////////////////////////////////////////////////
82+ // The following fields are not accessed by their _-prefixed name through the API;
83+ // they are mapped to REST-level names in the adapter layer or handled through
84+ // separate code paths.
85+ /////////////////////////////////////////////////////////////////////////////////////////////
86+ // System fields (mapped to REST-level names):
87+ // _id (objectId)
88+ // _created_at (createdAt)
89+ // _updated_at (updatedAt)
90+ // _last_used (lastUsed)
91+ // _expiresAt (expiresAt)
92+ /////////////////////////////////////////////////////////////////////////////////////////////
93+ // Legacy ACL format: mapped to/from _rperm/_wperm
94+ // _acl
95+ /////////////////////////////////////////////////////////////////////////////////////////////
96+ // Schema metadata: not data fields, used only for schema configuration
97+ // _metadata
98+ // _client_permissions
99+ /////////////////////////////////////////////////////////////////////////////////////////////
100+ // Dynamic auth data fields: used only in projections and updates, not in queries
101+ // _auth_data_<provider>
102+ } ;
103+
104+ // Derived access lists
105+ const specialQueryKeys = [
106+ ...queryOperators ,
107+ ...Object . keys ( internalFields ) . filter ( k => internalFields [ k ] . clientRead ) ,
108+ ] ;
60109const specialMasterQueryKeys = [
61- ...specialQueryKeys ,
62- '_email_verify_token' ,
63- '_perishable_token' ,
64- '_tombstone' ,
65- '_email_verify_token_expires_at' ,
66- '_failed_login_count' ,
67- '_account_lockout_expires_at' ,
68- '_password_changed_at' ,
69- '_password_history' ,
110+ ...queryOperators ,
111+ ...Object . keys ( internalFields ) . filter ( k => internalFields [ k ] . masterRead ) ,
70112] ;
71113
72114const validateQuery = (
@@ -250,17 +292,7 @@ const filterSensitiveData = (
250292// acl: a list of strings. If the object to be updated has an ACL,
251293// one of the provided strings must provide the caller with
252294// write permissions.
253- const specialKeysForUpdate = [
254- '_hashed_password' ,
255- '_perishable_token' ,
256- '_email_verify_token' ,
257- '_email_verify_token_expires_at' ,
258- '_account_lockout_expires_at' ,
259- '_failed_login_count' ,
260- '_perishable_token_expires_at' ,
261- '_password_changed_at' ,
262- '_password_history' ,
263- ] ;
295+ const specialKeysForUpdate = Object . keys ( internalFields ) . filter ( k => internalFields [ k ] . masterWrite ) ;
264296
265297const isSpecialUpdateKey = key => {
266298 return specialKeysForUpdate . indexOf ( key ) >= 0 ;
0 commit comments