Firebase rules: using parent values to validate? - firebase

I have this set of rules:
{
"rules": {
"facebook_users": {
"$user": {
".read": "$user == auth.id",
".write": "$user == auth.id",
"userData": {
"maxProjects": {
".validate": false
},
"userProjects": {
".validate": ???
}
}
}
}
}
}
I'd like to let an user not being able to add a children to the userProjects array if userProjects.length > userData.maxProjects. The user is denied writing in the maxProjects already, due to the ".validate": false rule. How can I compare userProjects' length with maxProjects?
If it's not possible, what is a correct way to do this?

You can use the root special variable along with child() to do this comparison:
{
"rules": {
"facebook_users": {
"$user": {
".read": "$user == auth.id",
".write": "$user == auth.id",
"userData": {
"maxProjects": {
".validate": false
},
"userProjects": {
".validate": "data.val().length < root.child('facebook_users').child($user).child('userData/maxProjects').val()"
}
}
}
}
}
}

Have you read this?
parent()
Gets a RuleDataSnapshot for the parent location.
Return Value: RuleDataSnapshot - The RuleDataSnapshot for the parent location.

Related

Firebase database rules "hasChildren"

I was writing security rules in my database but I do not understand why the validation does not pass it ..
I just want people to be able to type in "Extra" if the key says "nombre".
In case it's not the key "nombre", don't let it.
the rules:
"rules": {
"Users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid && root.child('Users').child(auth.uid).exists() === false || newData.hasChild('Extra')",
".validate": "newData.hasChildren(['nombre'])",
"Extra":{
}
}
}
}
Is the writing rule wrong? Does someone explain to me why?
TEST1 wrong
TEST2
You're writing to location /Users/$uid/Extra, so the nombre property ends up in /Users/$uid/Extra/nombre. To test the rule, you'll want to write to /Users/$uid.
If instead you want to allow the JSON like this:
Users: {
myUserId: {
Extra: {
nombre: "MT Designer"
}
}
}
Then your rules currently don't work, because you're validating that nombre exissts under myUserId. It should be:
{
"rules": {
"Users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid && root.child('Users').child(auth.uid).exists() === false || newData.hasChild('Extra')",
"Extra":{
".validate": "newData.hasChildren(['nombre'])",
}
}
}
}
}
Update: 2020-07-10
From the new screenshots it seems that yyou haven't applied the change from above yet, so I'd first recommend doing that. But if you want to reject other child nodes in Extra, you can do that by changing the rules to:
"Extra":{
"nombre": {
".validate": "data.isString()"
},
"$other": {
".validate": false
},
}
So this validates that the name is a string, and rejects all other child nodes.
From comments, apparently this is what OP ended up with:
"Users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid && root.child('Users').child(auth.uid).exists() === false || newData.hasChild('Extra')",
"$othernode": {
".validate": false
},
"Extra": {
"nombre": {
".validate": "newData.isString()"
},
"$other": {
".validate": false
},
}
}
},

Firebase how to apply update roles on custom child

how to allow non authenticated user to update only highlighted child and only read other child
current roles is
{
"rules": {
".read": true,
".write":"auth != null"
}
}
I have got the answer
{
"rules": {
".read": true,
".write":"auth != null",
"$product": {
"$id": {
"showen":
{
".write": true
}
}
}
}
}

Firebase Database rule - update only specific fields

I have a structure like this :
posts: {
group:{
postId: {
nbLikes: ..,
nbComments: ...,
updatedAt: ...,
text: ...
}
}
}
and I would like to allow the author to remove it, and everyone else to update everything except the text.
I have tried with this:
"posts": {
"$group": {
"$post": {
".write": "(data.exists() && !newData.exists() && data.child('userId').val() === auth.uid)
|| (data.exists() && newData.exists() && auth.uid != null)
|| (!data.exists() && newData.child('userId').val() === auth.uid)",
"text": {
".write": false
}
},
}
},
but unfortunately it does not work.
Moreover, when I try doing,
"posts": {
"$group": {
"$post": {
"text": {
".write": false
},
"nbLikes": {
".write": true
},
"nbComments": {
".write": true
}
....
},
}
},
it doesn't work either
Thanks for your help !

Dynamic security rules for "endless" children in Firebase?

Hey so I have this Firebase layout where I have files and every file can have children and all the children can have children, etc. How would I set up my security rules to dynamically work for the children (32 max if I'm remembering it correctly?). It kind of has to work with different read/write permissions depending on the user etc.
This is how it would work in a perfect world:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
"files": {
"$file": {
// permissions ...
"children": {
"$file": {
// permissions ...
"children": {
// etc ...
}
}
}
}
}
}
}
}
}

What is the scope of Firebase security rules variables?

Is that ok in Firebase to use the same variable name multiple times, e.g. $itemId here:
{
"rules": {
"items": {
"$itemId": { // first time
".write": "$itemId == 1"
}
},
"users": {
"$userId": {
"items": {
"$itemId": { // second time
".write": "$itemId == 2"
}
}
}
}
}
}
Do variables have scope?
In general, security rules cascade. The variables only apply to the block {...} under which they are declared. They are applicable to all of the children of that block.
{
"rules": {
"$level1": {
"$level2": {
"bar": {
".validate": "..." // $level1, $level2 are both usable here
}
}
}
"pathb": {
".validate": "..." // here $level1 is undefined
}
}
}

Resources