Imagine a User Document which holds a property "restaurants" witch again holds keys for all restaurant he is responsible for. I want to implement a security rule which only allows updating the property "restaurants" if the changed restaurant-id in the update, references a restaurant owned by the user. Therefore in security rules i want to detect the changed-restaurant-id, load corresponding restaurant-doc and check if the field "owner" inside the restaurant-doc is equal the user-id.
I was already able to implement a rule to check only 1 Id was modified by implmenting something like this:
function hasSingleChange(){
let changedKeys = request.resource.data.diff(resource.data).affectedKeys()
return changedKeys.size() == 0;
}
Now I wanted to get the the specific Id that changed and use it for building the query for the restaurant:
function getChangedKeys() {
let changedKeys = request.resource.data.diff(resource.data).affectedKeys()
return changedKeys[0]
}
But unfortunately "return changedKeys[0]" will not work as affectedKeys returns a Set with limited operations available.
Is there an other way around to load a document in security-rules, based on changed property to be able to apply checks on this changed, referenced document?
Edit
Let me explain you what i actually want to solve with this.
I have a Domain consisting of graphs, nodes and users as shown here:
What I want to accomplish is that users can access read/update/delete a node if the node is in a at least one graph which the user is the owner for. In the example above the user should have acess to node "n1" but not to node "n2".
My idea was to check the permission on the node as following:
match /nodes/{nodeId} {
allow read: if resource.data.graphs.keys().hasAny(get(/databases/$(database)/documents/users/$(request.auth.uid)).data.graphs.keys());
I guess this would work (?). But I need somehow to protect the user-Document to allow only writes to the "graphs" field if the user is listed as owner in the graph. Thats why I want to add another security-rule, something like this:
match /users/{userId} {
allow update: if request.auth.uid == userId && hasSingleChange() && get(/databases/$(database)/documents/graphs/getChangedKey()).data.owner).keys().hasAny($(userId))
}
function hasSingleChange(){
let changedKeys = request.resource.data.diff(resource.data).affectedKeys()
return changedKeys.size() == 0;
}
//To get the id of the changed graph
function getChangedKey() {
let changedKeys = request.resource.data.diff(resource.data).affectedKeys()
return changedKeys[0];
}
But as mentioned this is not working as I am unable to extract the changed graph-Id to lookup the document (getChangedKey not working). Maybe there is another way arround to fullfill my requirements? What I try to avoid is to entitle the userId directly on the node, as I would have to update a lot of nodes if someone entitles a new user to a specific graph.