Additional File-Upload Security

Hello dear Parse-Community.
Imagine following scenario:
I want my clients to only allow them to upload a file if there is a corresponding spot for them in the dataset. For example you have the class “Profile” and within there is an attribute called “image”. And only if “image” is undefined users can upload a file and put it in their profile.

In the FileTriggerRequest there is no option to pass a corresponding location for the fileobject to look for so this is my approach (Android SDK):

Client Code

void addParseObject() 
{
    ParseObject obj = new ParseObject("Profile");
    //store some data in obj
    obj.saveInBackground(new SaveCallback() 
    {
        @Override
        public void done(ParseException e) 
        {
            if (e == null) 
            {
                setProfilePicture(obj, data);
            }
        }
    });
}

void setProfilePicture(ParseObject profile, byte[] data)
{
    // giving the file the objectIds name as a reference to the profile
    ParseFile picture = new ParseFile(profile.getObjectId() + ".jpg", data, "image/jpg");
    profile.put("image", picture);
    picture.saveInBackground(new SaveCallback() 
    {
        @Override
        public void done(ParseException e) 
        {
            if (e == null) 
            {
                // success
                profile.saveInBackground();
            }
        }
    });
}

Cloud Code:

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

    if (user == null) 
    {
        throw ("Please log in before uploading a file");
    }
    if (!file.name().endsWith(".jpg")) 
    {
      throw ("You're not allowed to upload non jpg files!");
    } 
    else
    {
      //search through all profiles to get the correct one
      const query = new Parse.Query("Profile");
      query.equalTo("user", user.getUsername());
      //remove file extension and get object id reference
      const objectId = file.name().substring(0, file.name().length - 4);
      query.equalTo("objectId", objectId);
      const foundProfile = await query.first({useMasterKey: true});
      //check if the profile and a picture exists and act accordingly
      if (foundProfile == null) 
      {
        throw ("Could not find a corresponding profile to your file");
      }
      else if (foundProfile.get("image") != undefined) 
      {
        throw("You have to delete your profile picture before uploading a new one.");
      }
    }
});

I have tried this solution and it works for me. Any suggestions & complaints? Because I can imagine a lag querying through all profiles to get the correct one.

Feel free to comment.

1 Like