prevent deletion of existing data from firebase database - firebase

I want to allow read and write but not delete existing nodes.
these are the rules I have but is still allowing to delete (update)
"messages_test": {
".read": "true",
".write": "true",
"$message": {
".write": "false",
}
},
this is how I´m removing the node (succesffuly, but i should get permission denied instead)
firebase.database().ref('messages_test').child(id).remove()
.catch(error => console.log(error.message));
thanks for your help

I guess I found the way. restricting the write for existing data
"messages_test": {
".read": "true",
"$message": {
".write": "!data.exists() && newData.exists()",
}
},

"messages_test": {
".read": "true",
"$message": {
".write": "newData.exists()",
}
},

Related

How to add exclude data in Firebase rules on multiple levels?

I have my rules set. Normally, all data can only be read by the person who is auth to do so. However, I want to make exceptions. These are my rules:
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
"ForEveryone": {
".read": true,
".write": true
}
"NoWrite" : {
".read": true,
".write": false
}
}
}
So I let's say I have 3 string. String 1 is called private and can the auth person can read and write. String 2 is ForEveryone, so everyone can change and write data. String 3 is NoWrite, for everyone but you can not write to it.
I get an error, saying:Expecting a ; or " at the line NoWrite. So what am I doing wrong? Is it a wrong placed }? Thank you.
The approach you're taking to your rule structure won't work. Firebase security rules cascade, meaning that a permission given to any node will apply to any of its children and on down the tree. You cannot grant read or write access on a node and then revoke it further down. (But you can grant permissions not granted above.) See the docs on rule cascading.
In your case, you want to have some user data that be can written to by anyone and some that cannot. It's not clear from your example whether you want NoWrite to be written only by the authenticated user, or by nobody. Depending on how you will be reading this data, you will need to either separate these data into different collections, or make $uid inaccessible and define your rules only for ForEveryone and NoWrite.
The first approach might look like this:
"rules": {
"users-public": {
"$uid": {
".read": "true",
".write": "true",
},
"users-nowrite": {
"$uid": {
".read": "true",
".write": "$uid === auth.uid"
}
}
Or the second, like this:
"rules": {
"users": {
"$uid": {
"ForEveryone": {
".read": "true",
".write": "true"
},
"NoWrite" : {
".read": "true",
".write": "$uid === auth.uid"
}
}
}
As to your syntax error, you need a comma , after the closing brace before "NoWrite".
Here are your rules, properly spaced so you can see the relationship between the parent nodes and child nodes. It seems this is not what you want. So this isn't really an answer but will lead to a better question that we can answer. Will update once we know what the OP is after.
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
"ForEveryone": {
".read": true,
".write": true
},
"NoWrite" : {
".read": true,
".write": false
}
} //end uid
} //end users
} //end rules
} //outside closure

How to write firebase rules with unique ID

this is my problem :
WARN: FIREBASE WARNING: Using an unspecified index. Consider adding ".indexOn": "id_logement" at /images/-KNx2y3mAkJZ-Poa7R03 to your security rules for better performance
I'm not really a master in firebase and rules so it doesn't really mean something to me ... but i know there is an issue !
This is my data structure :
And this are my rules !
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"accounts" : {
".read": true,
".write": true,
".indexOn": ["userId", "email", "lat",]
},
"geofire" : {
".read": true,
".write": true,
".indexOn": ["g"]
},
"logements" : {
".read": true,
".write": true,
".indexOn": ["id_account"]
}
}
}
I think it's because i don't know how to write this Unique id in rules ! Can you please help me for this ? Thank you
Answering your question what you are looking for to use in your rules is the $id notation that is a wildcard to represent a branch key.
{
"rules": {
".read": "auth != null",
".write": "auth != null",
...
"images": {
"$imageId1": {
".indexOn": "id_logement"
}
}
}
}
But, keep in mind that you should not be storing your imagesUrl inside a two level deep keys. Work your code to have images/imageUniqueKey/imageData structure instead of images/imageUniqueKey1/imageUniqueKey2/imageData. Then you would have your rules as bellow.
"images": {
".indexOn": "id_logement"
}

Validate a Firebase Key is an integer

Here is the database schema:
Here are the rules:
"notifications": {
"$year": {
".read": "false",
".write": "!data.exists()",
"$month": {
".read": "false",
".write": "!data.exists()",
"$day": {
".read": "false",
".write": "!data.exists()",
"$hour": {
".read": "false",
".write": "!data.exists()",
"$minute": {
".read": "false",
".write": "!data.exists()",
"$data": {
".read": "false",
".write": "!data.exists()"
}
}
}
}
}
}
How can I validate (using ".validate" or ".write" rules) that the users can enter only integers into that tree? Or is there some workaround?
What I am trying to achieve is to create write only (no deletes, or updates) log that has some structure and will be processed later. I can change the structure for example to something like 2015-10-6-17-30 for the key, or something else. I just can't believe that Firebase does not have something for this situation.
Update:
This is not duplicate, I am searching for a workaround, or something else that will help me achieve what I am after.
To validate that a key is a number:
{
"$key": {
".validate": "$key.matches(/^[0-9]+$/)"
}
}
But please read about array-like behaviors in Firebase. Hint: probably use a prefix like "y2015", "m12", etc. to avoid some unexpected results with using numbers.
If using push IDs works for you, here's a security rule structure you could use.
{
"notifications": {
"$notification_id": {
".write": "!data.exists()",
".read": "false",
".validate": "newData.hasChildren(['time', 'state', 'message'])",
"time": {
".validate": "newData.val().matches(/YOUR REGEX/)"
},
"state": {
".validate": ""
},
"message": {
".validate": ""
}
}
}
}
Obviously you'll need to fill in the blanks. The main thing here is that you can use a regex to match the time field.
The actual data would look like:
{
"notifications": {
"-K-z5koYf8mYZu5OfSGR": {
"time": "2015-10-06-17-30",
"state": 1,
"message": "foo"
},
"-K-z5koYf8mYZwgwsfGx": {
"time": "2015-10-06-17-30",
"state": 1,
"message": "bar"
}
}
}

Is there a way to store a custom expression in Firebase Rules to be reused?

I would like to be able to reuse an expression in my Firebase Rules multiple times.
If I have the following rules:
{
"rules": {
".read": true,
".write": false,
"secretArea1": {
".read": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'"
},
"secretArea2": {
".read": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'"
}
}
}
Is there a way to store root.child('users').child(auth.uid).child('role').val() === 'admin' somewhere so it doesn't have to be repeated 4 times?
Something like:
{
"rules": {
".read": true,
".write": false,
"secretArea1": {
".read": "isAdmin",
".write": "isAdmin"
},
"secretArea2": {
".read": "isAdmin",
".write": "isAdmin"
}
}
}
Maybe I'm approaching this the wrong way. Any suggestions would be great!
I just discovered Blaze Compiler which was linked at Security & Rules Libraries. Not exactly what I was looking for and adds an extra compile step but seems to provide the functionality I was looking for. It would be nice if it was included as an option in the Firebase Dashboard.

How to allow users to write new content but not update/delete existing content

So I have this application where anonymous users are allowed to write but not read a specific path. They are posting data to a moderated message board kind of thing.
But with my current security rules, they are allowed to overwrite existing data as well. How can I disallow updates and allow only new posts.
My current security rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"inbox" : {
".write": true,
},
"moderated" : {
".read": true,
},
}
}
Use data.exists() to determine if the object they're trying to write already exists:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"inbox" : {
"$post" : {
".write": "!data.exists()",
}
},
"moderated" : {
".read": true,
},
}
}

Resources