'Securing Firebase RTDB with multiple databases for chat app
I am on the blaze plan and building a chat functionality in my app using Firebase realtime database.
I have 3 databases for now :
- Main instance that contains sharding information and users chats' info.
- The 2 other instances will contain the chats and messages.
The database structure for the main instance looks like this :
{
"shards" : {
"shard1" : {
"full" : false,
"name" : "shard1",
"num" : 1,
"url" : "shard1Url"
},
"shard2" : {
"full" : false,
"name" : "shard2",
"num" : 0,
"url" : "shard2Url"
}
}
}
And here is the data structure of one of the shard :
{
"users" : {
"user_id_1" : {
"chat_id_1" : true
},
"user_id_2" : {
"chat_id_1" : true
}
},
"chats" : {
"chat_id_1" : {
"created" : true,
"createdAt" : 1645888918717,
"members" : {
"user_id_1" : true,
"user_id_2" : true
},
"name" : "",
"uid" : "chat_id_1",
"updatedAt" : 1645895862214
}
},
"messages" : {
"chat_id_1" : {
"mess_id_1" : {
"content" : "Hello",
"chatID" : "chat_id_1",
"createdAt" : 1645895862214,
"senderID" : "user_id_1",
"uid" : "mess_id_1"
},
"mess_id_2" : {
"content" : "Bye",
"chatID" : "chat_id_1",
"createdAt" : 1645889441313,
"senderID" : "user_id_2",
"uid" : "mess_id_2"
}
}
}
}
I want the following rules to apply :
Reads :
- A user can listen for changes under
/users/$user_id/where$user_idisauth.uid - A user can get all the chats from the above IDs when he is in the
membermap (under/chats/$chat_id) - A user can read all the messages from a chat when he is a member (under
/messages/$chat_id)
Writes :
- A user can create a chat if there is no data under the
chat_idnode - A user can update a chat if he is a member under the
chat_id - A user can create a message if a
chat_idexists and if he is a member under thechat_idand if thesenderIDmatches theauth.uid - A user can delete a message if he is the sender of the message (not sure i can do this with security rules but only client side)
- A user can add only an item like
{"$chat_id": true}under any other user under/users/$user_id/
So far, here are my rules that are not working : -> Main shard :
{
"rules": {
"shards": {
".read": "auth.uid != null",
".indexOn": ["full"],
"$shardName": {
"num": {
".write": "auth.uid != null"
},
"$other": {
".write": false
}
}
},
}
}
-> For other shards :
{
"rules": {
"users": {
"$userID": {
".write": "auth.uid != null && !data.exists()",
".read": "auth.uid == $userID",
}
},
"chats": {
"$chat_id": {
".read": "data.child('members/'+auth.uid).exists()",
".write": "(!data.exists() && newData.hasChild('members')) || data.child('members/'+auth.uid).exists()",
}
},
"messages": {
"$chat_id": {
".read": "root.child('chats').child($chat_id).child('members').child(auth.uid).exists()",
".indexOn": ["createdAt"],
"$mess_id": {
".write": "(!data.exists() && newData.child('senderID').val() == auth.uid) || (data.exists() && data.child('senderID').val() == auth.uid)"
}
}
}
}
}
EDIT :
I have made many edit regarding the database structure.
I especially need help with reads rather than writes, as writes seem to be working fine now but i would like confirmation and / or changes if you see mistakes.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
