I'm creating a Google docs type of app where multiple users can edit a document in real-time.
These are my security rules:
{
"rules": {
"docs": {
"$doc_id": {
".read": "auth.token.doc_id === $doc_id",
".write": "auth.token.doc_id === $doc_id"
}
}
}
}
This is my Auth token payload (example)
{
"provider": "anonymous",
"uid": "e71afdf1-2b31-4c75-8f10-a9b0f916915e",
"token": {
"doc_id": 11
}
}
So when I try to read this path /docs/11/data I get a Simulated read denied error.
On the other hand when I put this rule instead
".read": "auth.token.doc_id === 11", (i.e. hard code $doc_id as 11)
The read passes.
But isn't $doc_id equal to 11 when I read /docs/11/data or am I misunderstanding something?
P.S. In case it matters, here is the data inside my database
{
"docs": {
"2": {
"data": {
"title": "test"
}
},
"11": {
"data": {
"title": "test"
}
}
}
}
Related
I'm building a private note app in Firebase realtime database, Android environment,
and now, I'd like to add authentificaion features with google sign-in in my app.
Until now, I tried several Rules in 'Rules playground', but it's not working well.
DB is like following:
{
"items" : {
"-MwtOrIBmhaoiGtSjzRl" : {
"key" : "-MwtOrIBmhaoiGtSjzRl",
"modifiedAt" : "2022-02-27 04:19:15.782677",
"string" : "test11"
},
"-MwvRBvCJ3hVJS3Qx1M3" : {
"key" : "-MwvRBvCJ3hVJS3Qx1M3",
"modifiedAt" : "2022-02-27 13:48:43.081140",
"string" : "Test2"
}
}
}
And the rules are like following:
{
"rules":{
"items": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
},
".indexOn": "modifiedAt"
}
}
}
In Rules playground, I tried 'get' simulation and the result is
'Simulated read denied'
{
"auth": {
"uid": "e41ac05f-6c93-40c8-add6-90bccf8ab80d",
"token": {
"sub": "e41ac05f-6c93-40c8-add6-90bccf8ab80d",
"firebase": {
"sign_in_provider": "google.com"
},
"email": "",
"email_verified": false,
"phone_number": "",
"name": ""
}
},
"resource": {
"key": "value"
},
"path": "/item",
"method": "get",
"time": "2022-02-27T14:44:13.766Z",
"isAdmin": false
}
Can I get some help?
One strange thing is that the follwing rules are not working well also.
{
"rules":{
"items": {
"$uid": {
".read": true,
".write": true,
},
".indexOn": "modifiedAt"
}
}
}
The key values you have under items are not Firebase Auth UIDs. They are push IDs randomly generated from your client app code. A push ID has nothing to do with the identity of the person who added that data.
To be clear, this value: "MwtOrIBmhaoiGtSjzRl" is not a UID. And it doesn't match the UID you're specifying here: "e41ac05f-6c93-40c8-add6-90bccf8ab80d".
If you want to use the user's UID as the key of the data to add to the database, don't use push(). You should instead build a path to the data using the user's UID in your code using setValue() as shown in the documentation.
I would like to add firebase database rule to allow anyone to increment the "count" inside the message object. Is it possible to do so? If so, how should I write the rule for updating the count? Thanks!
{
"messages": {
"message0": {
"content": "Hello",
"count": 5
},
"message1": {
"content": "Goodbye",
"count": 10
},
...
}
}
I tried below rule, but it doesn't seem to work:
{
"rules": {
"messages": {
"$message": {
"count": {
".read": true,
".write": true,
}
}
}
}
}
This is my firebase json data.
{
"Users": {
"MyData": {
"002ab7bUmab1CgQsw53abB3g1Ab1": { //UID
"-A3ABlabkflA_ABabABA": { //this is the databaseReference.child(DBHelper.FIREBASE_POSTS).push().getKey();
"display": "123",
"result": {
"format": "1",
"id": 1,
"numBits": 0,
"syncFirebaseId": "-A3ABlqmkflA_AVabABA",
"syncStatus": -1,
"text": "1234567",
"timestamp": 1514496903005
}
},
"-A2ABlabkf2A_ABabABA": { //this is the databaseReference.child(DBHelper.FIREBASE_POSTS).push().getKey();
"display": "123",
"result": {
"format": "1",
"id": 1,
"numBits": 0,
"syncFirebaseId": "-A3ABlqmkflA_AVabABA",
"syncStatus": -1,
"text": "1234567",
"timestamp": 1514496903005
}
}
}
}
}
}
Rules:
{
"rules": {
"Users": {
"MyData": {
"$uid": {
".read": "auth != null && auth.uid == $uid"
}
}
}
}
}
But when I simulate, read operation is denied. I want to allow only authenticated user to update data node that is relevant to his/her own. That user should not be able to edit other's data node (UID).
Here is the result of read simulation:
You're trying to read the root of your database. Since your rules grant nobody access to the entire database, the read is rejected. If you simulate reading from /Users/MyData/$theUidThatYouStruckOut it will be allowed.
I think auth.uid == $uid" should be auth.uid === $uid". For more information go through this
You have change Rules
{
"rules": {
"Users": { *** This Line
"MyData": {
"$uid": {
".read": "auth != null && auth.uid == $uid"
}
}
}
}
}
I have a firebase real-time database structured like this:
{
"USERS": {
"user-1": { ... },
"user-2": { ... }
}
"GROUPS": {
"group-1": {
"id": "group-1",
"AUTH": {
"user-1": true,
}
},
"group-2": {
"id": "group-2",
"AUTH": {
"user-2": true
}
},
"group-3": {
"id": "group-3",
"AUTH": {
"user-1": true,
"user-2": true
}
}
}
}
I know that I can give read permissions that would give read access to users that only belong to a specific group, like this:
{
"rules": {
"GROUPS": {
"$groupId": {
".write": false,
".read": "auth != null && data.child('AUTH').child(auth.uid).exists()"
}
}
}
}
I'm trying to find a query + rules combination that would return me all the groups that the logged in user belongs to.
For example:
A query and firebase rule change that for logged in 'user-1' returns a snapshot of:
{
"group-1": {
"id": "group-1",
"AUTH": {
"user-1": true,
}
},
"group-3": {
"id": "group-3",
"AUTH": {
"user-1": true,
"user-2": true
}
}
}
OR
[
{
"id": "group-1",
"AUTH": {
"user-1": true,
}
},
{
"id": "group-3",
"AUTH": {
"user-1": true,
"user-2": true
}
}
]
querying for the "GROUPS" reference now give me a 'permissions denied' error.
adding '.read=true' to the GROUPS:
{
"rules": {
"GROUPS": {
".read": true,
"$groupId": {
".write": false,
".read": "auth != null && data.child('AUTH').child(auth.uid).exists()"
}
}
}
}
or any combination for '.read' that passes the condition, gives everyone access to all the data.
Is there a way (in the current structure) to query the database and get from the "GROUPS" branch all the groups that I belong to by adding some restriction to the rules?
or do I need to maintain under each user the list of the group that he belongs to?
I am trying to prevent unwanted fields to be added to my user objects.
--> A user can have a phone and a username (but doesn't have to --> newData.hasChildren(['phone', 'username']) doesn't work here).
I first tried this:
"users": {
"$uid": {
"$other": {
".validate": "['phone', 'username'].indexOf($other) > -1"
}
}
}
I get an error because of the array :(
So then I thought about doing something like this but it's really not great if I have many potential fields
"$other": {
".validate": "$other === 'phone' || $other === 'username'"
}
Finally, I created a node in my Firebase called 'rules' and did this:
"rules": {
"users": {
"fields": {
"phone": true,
"username": true
}
}
}
And then my new validation rule in my user object is:
"$other": {
".validate": "root.child('rules/users/fields/'+$other).val() === true"
}
My question is: Is this a correct way to restrict field names ?
Thank you very much for your answer :) I am pretty new to Firebase but I am having a lot of fun trying it out!
To restrict an object in your Firebase to only have the specified keys, try using one additional wildcard child that will match any attributes not already specified, and reject the write if it contains one of these unmatched attributes:
"rules": {
"users": {
"$userid": {
".validate": "newData.hasChildren(['phone', 'username'])",
"phone": {
".validate": "newData.isNumber()"
},
"username": {
".validate": "newData.isString()"
},
"$other": {
".validate": false
}
}
}
}