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"
}
}
}
Related
How to set security rules for Firebase realtime database structure as below:
users: {
...
...
...
},
books: {
...
...
...
},
sales: {
...
...
...
}
Condition: Firebase auth is set to email/password and only user logged-in with emails ending with domain [mydomain.co.in] must be able to read or write to parent node. Without using custom claims.
Adding below security rules is applied/working only for the the first parent node [users] and not to all, what is a miss here?
{
"rules": {
".read": false,
".write": false,
"users": {
".read": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".write": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".indexOn": "name"
},
"books": {
".read": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".write": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".indexOn": "title"
},
"sales": {
".read": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".write": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".indexOn": "price"
},
}
}
Try below enclosed within uid field?
Reference https://firebase.google.com/docs/reference/security/database
same code works with auth.token.email.matches(/.*#mydomain.co.in$/)
{
"rules":{
".read": "false",
".write": "false",
"users":{
"$uid":{
".read":" auth.token.email.endsWith('#mydomain.co.in')",
".write":" auth.token.email.endsWith('#mydomain.co.in')",
".indexOn":"name"
}
},
"books":{
"$uid":{
".read":" auth.token.email.endsWith('#mydomain.co.in')",
".write":" auth.token.email.endsWith('#mydomain.co.in')",
".indexOn":"title"
}
},
"sales":{
"$uid":{
".read":" auth.token.email.endsWith('#mydomain.co.in')",
".write":" auth.token.email.endsWith('#mydomain.co.in')",
".indexOn":"price"
}
}
}
}
Auth Token payload
{
"token":{
"email": "test#mydomain.co.in"
}
}
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()",
}
},
This question already has an answer here:
Firebase: How to structure public/private user data
(1 answer)
Closed 4 years ago.
I can't figure out how to filter data using Firebase database. I've read that rules can't be used for filters. But then how?
I'd like a datastructure somewhat like the one below. i.e. a list of posts created by different users due for a specified time (user-id is not included in the layout below as I'm not sure where to put it)
posts: {
"-LKwbZsfy55d24kwX4t1" : {
when: {
from: "2019-01-01 10:00",
to: "2019-01-01 11:00"
content: {
text: "Hello"
}
},
"-LKwbZsfy55d24kwX4t2" : {
when: {
from: "2019-01-02 10:00",
to: "2019-01-02 11:00"
content: {
text: "Another hello"
}
}
}
I would like everyone to be able to read all posts so my sync path is '/posts'
BUT only the user that created the post should be able to see the 'content'. So I somehow need to say that posts has ".read" : true, and content has ".read": $uid == auth.uid (which is not possible since access cannot be revoked by a child path)
If your current data structure makes it impossible to secure the data to your needs, considered restructuring it so that security rules become possible. In other words, don't nest protected data under public data. Put protected data in its own top-level child.
"posts-public": {
"-LKwbZsfy55d24kwX4t1": {
// public data here
}
},
"posts-private": {
"-LKwbZsfy55d24kwX4t1": {
// private data here
}
}
Now you can write security rules to protect them independently from each other.
".read": "true", gives everyone to read data
And it should be looks like this (just for example):
"posts": {
".read": "true",
"$postId": {
".read": "true",
".validate": "root.child('posts/'+$postId).exists()",
"$contentId": {
".read": "auth !=null",
".write": "auth != null",
".validate": "(newData.hasChildren(['content']))",
"content": {
".validate": "newData.val().length > 0"
},
"user": {
".validate": "newData.hasChildren(['id', 'name', 'avatar'])"
}
}
}
},
"privatePost": {
"$uid1": {
"$uid2": {
".read": "auth != null && ($uid1 === auth.uid || $uid2 === auth.uid)",
"$postId": {
".write": "auth != null",
".validate": "(newData.hasChildren(['content']))",
"content": {
".validate": "newData.val().length > 0"
},
"user": {
".validate": "newData.hasChildren(['id', 'name', 'avatar'])"
}
}
}
}
My firebase structure looking like that:
{
"post": {
"uid": {
"text": "Name";
}
},
"games": {
"id": {
"title": "buttons",
"text": "(user id string)"
},
"id": {
"title": "navbars",
"text": "(id string)"
}
},
"guides": {
"1": {
"title": "guide",
"text": "unwriteable string"
}
}
}
(The value doesn't matter..)
I want to allow read and write on everynode, execpt the guides node,
so I tried the following rules:
{
"rules": {
".read": "auth == null",
".write": "auth == null",
"guides": {
".write": false
}
}
}
But. unfortunately, because of the 'father' allowance, firebase doesn't care about the guides specific rule,
Any idea how to achive my goal?
Bacause firebase security rules cascade you can't say someone has permission to write everywhere and later say but not here.
So in you case you would have to add rules for your other paths like this:
{
"rules": {
".read": "auth == null",
"guides": {
".write": false
},
"games": {
".write": "auth == null"
},
"post": {
".write": "auth == null"
}
}
}
As Kato stated this can also be done with the following rule:
{
"rules": {
".read": "auth == null",
".write": "auth == null && !newData.hasChild('guides')"
}
}
The first example will allow you to write only in the games and post nodes whereas the second example will allow you to write everywhere except for the guides node.
My firebase data looks like this-
My security rules are-
{
"rules": {
"users": {
"fred": {
".read": true,
".write": true
},
"wilma": {
".read": "auth.id == '1'",
".write":true
},
"$other": {
"name": {
".read": true,
".write": true
}
}
}
}
}
First click on Authenticate button.
Path you should enter is /users/wilma