Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse Pointer Permissions don't allow create

I've followed every step of this walkthrough, but when I try to create a new row, I get a 403:

code: 119

message: "This user is not allowed to perform the create operation on Messages. You can change this setting in the Data Browser."

My code:

Messages = Parse.Object.extend("Messages")
var message = new Messages();
message.set("sender", Parse.User.current());
message.set("receiver", *anotherUser*);
message.set("subject", "foo")
message.set("body", "bar")
message.save()
.then(
  function(message){
    console.log("success!")
  },function(error){
    console.log("error: ", error);
});

My CLPs are set as follows: enter image description here enter image description here

It looks like someone else posted the same issue in a google group. What are we missing?

like image 397
adamdport Avatar asked Oct 23 '15 16:10

adamdport


3 Answers

That has been a bug since the launch of Pointer Permissions, which effectively makes them useless. My impression is they built this with the idea of letting developers secure existing schemas in one go, but of course you need it to work for future creation.

One workaround would involve combining the older Class Level Permissions and per-row ACL's while being careful to not disable your Data Browser. Let's assume you have classes "Puppy" and "Cat" and both have a field called "owner".

  1. In your Data Browser, for each class where it makes sense to have an owner field, you set its Class Level Permissions for Puppy and Cat each to:

Public - Read: Yes or No, depends on your use case, Write: Yes

Add a Pointer Permission for "owner" - Read: Yes, Write: Yes (can skip this for now, see below)

  1. Then in your cloud/main.js, you can use the following as a starting point (which I often call "types" below, sorry).

  2. When Parse fixes the creation issue, you remove the Public Write Class Level permission (above), leave the Pointer Permission one, and get rid of the workaround code below.

--

var validateAndUpdateOwnerWritePerms = function(request){
    var object = request.object;
    var error = null;
    var owner = object.get('owner');

    if (!Parse.User.current()) {
        error = 'User session required to create or modify object.';
    } else if (!owner) {
        error = 'Owner expected, but not found.';
    } else if (owner && owner.id != Parse.User.current().id && !object.existed()) {
        error = 'User session must match the owner field in the new object.';
    }

    if (request.master) {
        error = null;
    }

    if (error) {
        return error;
    }

    if (object.existed()) {
        return null;
    }

    var acl = new Parse.ACL();
    acl.setReadAccess(owner, true);
    acl.setWriteAccess(owner, true);

    object.setACL(acl);

    return null;
}

// Wrapper that makes beforeSave, beforeDelete, etc. respect master-key calls.
// If you use one of those hooks directly, your tests or admin
// console may not work.
var adminWriteHook = function(cloudHook, dataType, callback) {
    cloudHook(dataType, function(request, response) {
        if (request.master) {
            Parse.Cloud.useMasterKey();
        } else {
            var noUserAllowed = false;
            if (cloudHook == Parse.Cloud.beforeSave &&
                (dataType == Parse.Installation || dataType == Parse.User)) {
                    noUserAllowed = true;
            }
            if (!noUserAllowed && !Parse.User.current()) {
                response.error('Neither user session, nor master key was found.');
                return null;
            }
        }

        return callback(request, response);
    });
};

// Set hooks for permission checks to run on delete and save.
var beforeOwnedTypeWriteHook = function(type) {
    var callback = function (request, response) {
        var error = validateAndUpdateOwnerWritePerms(request);
        if (error) {
            response.error(error);
            return;
        }
        response.success();
    };
    return adminWriteHook(Parse.Cloud.beforeSave, type, callback);
    return adminWriteHook(Parse.Cloud.beforeDelete, type, callback);
};

beforeOwnedTypeWriteHook('Puppy');
beforeOwnedTypeWriteHook('Cat');
like image 32
Nikolay Valtchanov Avatar answered Nov 04 '22 22:11

Nikolay Valtchanov


I've submitted this as a bug to Parse (Facebook), and they replied:

We have managed to reproduce this issue and it appears to be a valid bug. We are assigning this to the appropriate team.

I will update this answer once the issue has been resolved. If this issue is impacting you, please subscribe to the bug, as this will help prioritize the fix.

UPDATE

Facebook replied:

Turns out that this is actually by design. To create an object, the class should have public create permissions on it

Unfortunately, with this solution, I can create a message "from" any other user (another user set as the sender). This is unacceptable and unusable IMHO.

like image 183
adamdport Avatar answered Nov 04 '22 22:11

adamdport


Unfortunately it seems that Parse Pointer Permissions do not work as you expect it on Create. The quick fix would be to allow Create permission to Public. Then to ensure that the user who is creating a record is the same as the sender. So you need to perform a manual check in the beforeSave trigger for Messages class in cloud code and if that check fails, reject the record being created.

like image 2
Mo Nazemi Avatar answered Nov 05 '22 00:11

Mo Nazemi