Since the inception of Pointer Permissions, a persistent bug has rendered them essentially useless. It seems like the intention was to allow developers to secure existing schemas all at once, but in reality, it needs to work for future creations as well.
To work around this issue, one option is to combine older Class Level Permissions with per-row ACLs, being cautious not to disable your Data Browser. For instance, if you have classes named "Puppy" and "Cat" both containing an "owner" field.
- In the Data Browser, adjust the Class Level Permissions for Puppy and Cat by setting the owner field permissions to:
Public - Read: Yes or No (depends on use case), Write: Yes
Add a Pointer Permission for "owner" - Read: Yes, Write: Yes (optional for now, see below)
Then, in your cloud/main.js file, consider using this initial structure (referred to as "types" below):
Once Parse resolves the creation issue, remove the Public Write Class Level permission (mentioned above), retain the Pointer Permission, and discard 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');