I have this Firebase DB which could be changed if necessary:
The JSON of that DB is:
{
"groups": {
"1": {
"name": "G1",
"points": {
"1": {
"name": "p1"
}
},
"visits": {
"1": {
"name": "v1"
}
},
"areas": {
"1": {
"name": "a1"
}
},
"waypoints": {
"1": {
"name": "w1"
}
},
"interests": {
"1": {
"name": "i1"
}
}
},
"2": {
"name": "G2",
"points": {
"2": {
"name": "p2"
}
},
"visits": {
"2": {
"name": "v2"
}
},
"areas": {
"2": {
"name": "a2"
}
},
"waypoints": {
"2": {
"name": "w2"
}
},
"interests": {
"2": {
"name": "i2"
}
}
}
},
"users": {
"qdRw1khg1ZO1s52YioYCdM4WrD02": {
"firstName": "AAAA",
"lastName": "BBB",
"email": "[email protected]"
},
"h3KYDXkPQrY246w6Y6NXIanVoNS2": {
"firstName": "FF",
"lastName": "RR",
"email": "[email protected]"
}
},
"userGroups": {
"qdRw1khg1ZO1s52YioYCdM4WrD02": {
"1": "admin",
"2": "readwrite"
},
"h3KYDXkPQrY246w6Y6NXIanVoNS2": {
"1": "admin",
"2": "readonly"
}
}
}
I want to define rules to accomplish the following:
I have:
"groups": {
"$groupId": {
".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
".write": "! root.child('userGroups').child(auth.uid).child($groupId).exists() ||
(data.parent().val() === 'points' && root.child('userGroups').child(auth.uid).child($groupId).val() != 'readonly') ||
(data.parent().val() === 'visits' && root.child('userGroups').child(auth.uid).child($groupId).val() === 'readonly') ||
(data.parent().val() != 'points' && data.parent().val() != 'visits' && root.child('userGroups').child(auth.uid).child($groupId).val() === 'admin')"
}
},
"users": {
"$userId": {
".read": "auth != null",
".write": "auth != null &&
$userId === auth.uid &&
newData.val() != null"
}
},
"userGroups": {
"$userId": {
".read": "auth != null",
".write": "auth != null &&
data.child(auth.uid).val() === 'admin' &&
newData.val() != null"
}
}
But that does not work since
data.parent().val()
does not return the parent's name string. So I can't do
data.parent().val() != 'points'
How to solve this? The problem is writing data to groups according to the rules specified.
Firebaser here. Expect this answer to be updated as I go along.
My first step is to move the rules for the specific child nodes into that specific child node. That removes the parent()
problem you've been having. First iteration is:
"groups": {
"$groupId": {
".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
"points": {
".write": "root.child('userGroups').child(auth.uid).child($groupId).val() !== 'readonly'"
}
}
},
This allows user h3KYDXkPQrY246w6Y6NXIanVoNS2
to write to /groups/1/points
(of which the user is an admin), but not to /groups/2/points
(to which the user only has readonly access).
A next step is to make the rule more generic. To do this I introduce a $child
variable, which matches any node under the group:
"groups": {
"$groupId": {
".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
"$child": {
".write": "root.child('userGroups').child(auth.uid).child($groupId).val() !== 'readonly'
|| ($child !== 'points' && $child !== 'visits')"
}
}
This allows user h3KYDXkPQrY246w6Y6NXIanVoNS2
to write to /groups/2/name
(which is writeable by any group member), but not to /groups/2/points
(to which the user only has readonly access).
Update: apparently I inverted your logic above, so here's my final take:
"groups": {
"$groupId": {
".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
".write": "root.child('userGroups').child(auth.uid).child($groupId).val() == 'admin'",
"$child": {
".write": "root.child('userGroups').child(auth.uid).child($groupId).val() === 'readwrite'
&& ($child !== 'points' || $child !== 'visits')"
}
}
With this user h3KYDXkPQrY246w6Y6NXIanVoNS2
:
/groups/1/name
because they're admin of group 1/groups/2/points
because they're admin of group 1/groups/2/name
because they're not an admin of group 2/groups/2/points
because they're a readwrite member of group 2If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With