I'm building a real-time messenger using Ionic/Angular and Firebase. I'm using Firebase Authentication to authenticate my users, and Firebase DB to store the messages and message threads.
My problem what security rules should I use in order for message threads to be private and viable and writable only to the 2 persons engaged in a given message thread.
My DB structure looks like this now:
-chats
--Message_thread_ID
---Unique_ID_generated_message by Firebase
----Message
----Sender ID
----Receiver ID
---Unique_ID_generated_message by Firebase
----Message
----Sender ID
----Receiver ID
--Message_thread_ID
---Unique_ID_generated_message by Firebase
----Message
----Sender ID
----Receiver ID
My current firebase security rules are:
{
"rules": {
".read": "auth != null",
".write": false,
"$messageThreadID": {
".write": "auth != null && !data.exists()",
".read": "auth != null"
}
}
}
This works fine, but this way any authenticated user will be able to read all messages between any user. Which is no what I want. I want to keep message threads private to only the two users in any given thread.
How should I restructure my DB for the best optimal solution?
PS: I have ways to do it using backend, or making two copies for each of the two users of their respective threads, but these solutions look really subprime.
Your current data model only stores the messages of the chat themselves. It doesn't store yet who are participants in each chat. Or well... it does store it somewhat in the messages themselves, but that's not explicit enough for your security rules to be able to read it.
So the first step is to add data to your model about who is a member of what yet:
members
Message_thread_ID1
member_uid_1: true
member_uid_2: true
Message_thread_ID2
member_uid_1: true
member_uid_3: true
Now we have all the information that is needed to update the security rules.
{
"rules": {
".read": "auth != null",
".write": false,
"$messageThreadID": {
".write": "root.child('members').child($messageThreadID).child(auth.uid).exists()",
}
}
}
Now a user can only write to a message thread if they are a member of that thread.
You'll typically end up with multiple of such lookup lists, for the various use-cases of your app. For example, it is likely that you want to show a list of message threads for a user when they log in. To do that efficiently, you'll likely add a list of "messages threads for each user", which is pretty much the inverse of the members
list above:
threads_per_user
member_uid_1: true
Message_thread_ID1
Message_thread_ID2
member_uid_2: true
Message_thread_ID1
member_uid_3: true
Message_thread_ID2
This sort of data structure initially feels very unnatural for developers coming from a relational/SQL background, but is actually quite common in NoSQL databases.
To learn more:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With