Skip to content

Instantly share code, notes, and snippets.

@katowulf
Last active April 11, 2024 12:07
Show Gist options
  • Star 58 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save katowulf/4741111 to your computer and use it in GitHub Desktop.
Save katowulf/4741111 to your computer and use it in GitHub Desktop.
Firebase security rules for a simple chat room model
{
"chat": {
// the list of chats may not be listed (no .read permissions here)
// a chat conversation
"$key": {
// if the chat hasn't been created yet, we allow read so there is a way
// to check this and create it; if it already exists, then authenticated
// user (specified by auth.id) must be in $key/users
".read": "auth != null && (!data.exists() || data.child('users').hasChild(auth.id))",
// list of users authorized to participate in chat
"users": {
// if the list doesn't exist, anybody can create it
// if it already exists, only users already in the list may modify it
".write": "!data.exists() || data.hasChild(auth.id)",
"$acc": {
// for now the value is just a 1, later it could be a read/write/super privilege
".validate": "newData.isNumber()"
}
},
// timestamps recording last time each user has read this chat
"last": {
"$acc": {
// may only written by the authenticated user and if user is in $key/users
".write": "$acc === auth.id && root.child('chat/'+$key+'/users').hasChild($acc)",
".validate": "newData.isNumber()"
}
},
"messages": {
"$msg": {
// to write a message, it must have all three fields (usr, ts, and msg)
// and the person writing must be in $key/users
".write": "root.child('chat/'+$key+'/users').hasChild(auth.id)",
".validate":"newData.hasChildren(['ts', 'usr', 'msg'])",
"usr": {
// may only create messages from myself
".validate": "newData.val() === auth.id"
},
"msg": {
".validate": "newData.isString()"
},
"ts": {
".validate": "newData.isNumber()"
}
}
}
}
}
}
@quantuminformation
Copy link

We decided on hashing users uid's, which means you can look up any existing conversation if you know the other persons uid's.

Each conversation also stores a list of the uids for their security rules, so even if you can guess the hash, you are protected.

@quantuminformation
Copy link

quantuminformation commented Oct 26, 2020

I would also recommend creating all timestamps with cloud functions to account for differences in time zones and computer clocks. Also if the user updates his last read value, that should also be server updated

@quantuminformation
Copy link

Please also note, that when writing to users you need to use update not set as this gotcha:

https://stackoverflow.com/questions/64544925/fireplace-update-allowed-but-set-fails-with-simulated-set-denied/64549981#64549981

@quantuminformation
Copy link

Also note

".write": "!data.exists() || data.hasChild(auth.id)",

should be

       ".write": "!data.exists() || data.hasChild(auth.uid)",

thank me later

@quantuminformation
Copy link

quantuminformation commented Oct 28, 2020

The only thing I would like to add to this is a way for any user in the chat to delete the entire conversation which is not possible as they would have to have had access to the whole conversation, which would break the more granular write rules.

Probably needs a cloud function with a custom token, if anyone has an idea how to do that.

@Carlos-ag
Copy link

How do you include a list of users in realtime database?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment