Skip to content

request.user is undefined in hooks when setting useMasterKey: true, even when sessionToken is set #6512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jonas-db opened this issue Mar 15, 2020 · 16 comments

Comments

@jonas-db
Copy link

jonas-db commented Mar 15, 2020

Is your feature request related to a problem? Please describe.

Given the following code:

var object = new Object();
object.set('someField', true);
const result = await object.save(null, { sessionToken: user.get('sessionToken'), useMasterKey : true}).catch(e => e);

and the following beforeSave hook:

Parse.Cloud.beforeSave('Object', async (request) => 
{
	const user = request.user;
	const isMaster = request.master;
	const object = request.object;

	console.log('Ask/BeforeSave')
	debug(user) // undefined
	debug(isMaster) // true

})

Saving the object triggers the beforeSave hook, but the request.user is undefined when using useMasterKey. The problem occurs when Object creation is not allowed by the client, thus I can only create Object with the masterKey. As a result, I don't have access anymore to request.user in beforeSave and afterSave and thus I don't know for which user this object was saved. I need this information (ie user id) to execute other side effects.

Describe the solution you'd like
Given that both useMasterKey and sessionToken are set, request.user should always include the user on which behalf this request was executed.

Describe alternatives you've considered
I haven't found any other solution, besides ticket #6459 .

Additional context
using "parse-server": "^3.9.0",
I will need this feature for an upcoming application, so unless there is a workaround, i'll be open to write a solution if you can give me some pointers.

@jonas-db jonas-db changed the title request.user is undefined when setting useMasterKey: true, even when sessionToken is set request.user is undefined in hooks when setting useMasterKey: true, even when sessionToken is set Mar 15, 2020
@dplewis
Copy link
Member

dplewis commented Mar 29, 2020

Can you write a test case? I think this maybe an issue with subsclassing and beforeSave.

@uzaysan
Copy link

uzaysan commented Apr 15, 2020

I have the same issue. When I try to save object with both MasterKey and User SessionToken in cloud code, masterKey works but sessionToken is ignored. When I use only sessionToken It works but I cant save object because All Class Level Permissions are disabled and object creation is only allowed with masterKey.

Here is the simple use case:

I have a beforeFileSave trigger and in that trigger I replace file name with user id.

Parse.Cloud.beforeSaveFile(async (request) => {
  const file = request.file;


  const fileData = await file.getData();
  //I change file name to user id.
  const newFile = new Parse.File(request.user.id, { base64: fileData });
  return newFile;

});

And in my cloud code I create and image thumbnail(base64 string) and save that file.

Parse.Cloud.define("sharePostImage", async (request) => {

  const user = request.user;
  
  const media = request.params.media;
  //media is a parse file.
  
  const mediaData = await media.getData();



  const tempMedia = Buffer.from(mediaData, 'base64');
  
  let options = { percentage: 5, responseType: 'base64' };
  //I create a thumbnail of media(Image)
  const thumbnail = await imageThumbnail(tempMedia, options);
    
  const MyClass = Parse.Object.extend("MyClass");


  /*All Class Level Permissions for MyClass is disabled and only
  way to create object is using master key*/
  const myClass = new MyClass();
  myClass.set("mainmedia",media);
  
  var thumbfile = new Parse.File("thumbMedia.jpg", { base64: thumbnail });
  myClass.set("thumbmedia",thumbfile);


  const myClass2 = await myClass.save(null,{useMasterKey:true,sessionToken:user.getSessionToken()});
  return myClass2;
    

});

@davimacedo
Copy link
Member

It does not make sense to send both master key and session token in the same request. You need to choose if you either want to run this request as an user or as the master. What do you want to achieve with myClass.save(null,{useMasterKey:true,sessionToken:user.getSessionToken()})?

@uzaysan
Copy link

uzaysan commented Apr 15, 2020

@davimacedo I change file name with user id in beforeSaveFileTrigger. And since I disabled all CLPs for MyClass, I need master key to create that myClass object and I need session token for File trigger. Because I replace file name with user id.

This is Why I need it. Both parse File and Parse object saves to database with same save function.

var thumbfile = new Parse.File("thumbMedia.jpg", { base64: thumbnail });
  myClass.set("thumbmedia",thumbfile);
  const myClass2 = await myClass.save(null,{useMasterKey:true,sessionToken:user.getSessionToken()});

If I seperate file saving and ParseObject saving like below code problem would be solved but saving them together makes the problem.

var thumbfile = new Parse.File("thumbMedia.jpg", { base64: thumbnail });
await thumbfile.save(null,{sessionToken: user.getSessionToken()});
  myClass.set("thumbmedia",thumbfile);


  const myClass2 = await myClass.save(null,{useMasterKey:true,sessionToken:user.getSessionToken()});

You can say: " Then why dont you save them seperatly instead of saving them together". Well I will do that ıf I cant pass sessiontoken and master key together. But If there is a way I want to know

@davimacedo
Copy link
Member

davimacedo commented Apr 15, 2020

Why don't you set the file name with the current id from the beginning? You don't need a trigger for this:

var thumbfile = new Parse.File(user.id, { base64: thumbnail });
  myClass.set("thumbmedia",thumbfile);
  const myClass2 = await myClass.save(null,{useMasterKey:true});

That's what you need to do, right?

@uzaysan
Copy link

uzaysan commented Apr 15, 2020

That's not the only file I upload. Files can be uploaded from android SDK. I rename files in trigger to make some sort of verification. To know creator of file.

Edit: Actually It's not a big deal for me. I just seperated file save and ParseObject save. It works now.

@davimacedo
Copy link
Member

In the trigger you can do something like this:

Parse.Cloud.beforeSaveFile(async (request) => {
  if (request.isMaster) return;
  const file = request.file;


  const fileData = await file.getData();
  //I change file name to user id.
  const newFile = new Parse.File(request.user.id, { base64: fileData });
  return newFile;

});

@uzaysan
Copy link

uzaysan commented Apr 15, 2020

I never think this way. Looks cool. Thanks. I will use it.

@jonas-db
Copy link
Author

jonas-db commented Apr 15, 2020

It does not make sense to send both master key and session token in the same request. You need to choose if you either want to run this request as an user or as the master. What do you want to achieve with myClass.save(null,{useMasterKey:true,sessionToken:user.getSessionToken()})?

It does make sense in scenarios such as described above (ie when you need user information). Moreover, it makes sense if you have custom logic in triggers. Since class creation is disabled, only the master can effectively create these classes for the user, yet you have no idea in the triggers on who's behalf this object was created.

@davimacedo
Copy link
Member

If you are performing an operation by using the master key, your user is the master. Can you explain what you need to achieve with the code below?

Parse.Cloud.beforeSave('Object', async (request) => 
{
	const user = request.user;
	const isMaster = request.master;
	const object = request.object;

	console.log('Ask/BeforeSave')
	debug(user) // undefined
	debug(isMaster) // true

})

@jonas-db
Copy link
Author

jonas-db commented Apr 15, 2020

I want to have access to request.user when the request was made with both the session key and master key. Also, think transitively. I have many other triggers that are triggered by each other. Currently, these triggers return undefined for request.user since the master key is used, even though I explicitly say that this request should be done on behalf of the user whose session token I passed as well.

@davimacedo
Copy link
Member

Your user in this case is the master. request.user being null in this case is a consistent behavior. If you want to send the information about another user, you can send it in a field of the object that you are saving. If you provide a concrete example of what this trigger is supposed to do, I can help you to figure out the best way to achieve that.

@jonas-db
Copy link
Author

jonas-db commented Apr 15, 2020

I don't believe so. When a session token is set, it means this object is saved/updated/... on behalf of that user. Yes, a master user can override that behavior, but the scope is still for that user (eg even though class creation is disabled for clients, the object can now be saved since useMasterKey was explicitly set and overrides the creation behavior).

Also cluttering your objects with extra fields for context information is hacky and not clean as I don't need this information in my object itself. Therefore, I proposed #6459 as a solution. In that case, you can keep request.user null (as it is currently), but at least I can pass context information in a clean way (ie the user) even when masterkey is set.

@davimacedo
Copy link
Member

davimacedo commented Apr 15, 2020

#6459 is probably a better solution for what you may need to solve. Would you be willed to tackle it?

@jonas-db
Copy link
Author

I don't have experience with the internals of parse-server, so i'm not sure if I will be able to. I'll follow up in a month to see what I can do if nobody had a look at it already.

@stale
Copy link

stale bot commented May 31, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label May 31, 2020
@stale stale bot closed this as completed Jun 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants