Getting .read and .write Security Rules To Work For Groups - firebase

I am​ having difficulty writing the security rules for​ building a team based collaboration platform.
​​When a user registers they should be able to create a team and invite users to that team.
Projects should be owned by the team​.​
​Only users in that team should be able to view ​that project.​
​Users should only see the teams they are a member of​.
How do I write​ .read​ security rules so the ​users only see info from teams they're in?
I should only get two teams listed because I belong to them github:8272012​.​
​Current Security Rules: ​
{
"rules": {
".read": true,
"users": {
"$user": {
//can add a message if authenticated
".write": "auth.uid === $user"
}
},
"teams": {
"$team": {
"users": {
// can write to the users list only if ADMINISTRATOR
"$user": {
".write":"newData.parent().child(auth.uid).val() === 99"
}
}
}
},
"projects": {
"$team": {
"$project": {
//can add a message if they are a MEMBER
".write": "(!data.exists() && newData.exists() && root.child('teams/' + $team + '/users/' + auth.uid).val() >= 10)"
}
}
}
}
}
I should only get two teams listed because I belong to them github:8272012.

The following security rules would give read and write access for a project only to users who are in that project's team (assuming you add a /projects node for each user to indicate which projects that user has access to):
"rules": {
"projects": {
"$project": {
".read": "root.child('users').child(auth.uid).child('projects').val().child($project).exists()" ,
".write": "root.child('users').child(auth.uid).child('projects').val().child($project).exists()"
}
}
}
I can't see what data you're storing for each project, but if you store a reference to the project's team you could also use that in your security rules.

Related

Firebase Rules: Allow user to read data only if user is included in a child node

I am attempting to rewrite my database rules to only allow members of a specific 'collection' to access that collection only if that member is included in the teams list. Referring to the image attached below, this is what my rule currently looks like:
{
"rules": {
"collection": {
"$collection_id": {
"$teams" : {
".read": "data.child('id').val() === auth.uid"
}
}
}
}
}
However this doesn't seem to work and I believe it's incomplete. How can I update my rules to match this design structure? If any change in my structure is necessary to support this, do pitch that and I will attempt to update the current production data.
You could reach into the teams node like this:
{
"rules": {
"collection": {
"$collection_id": {
".read": "data.child('teams').child(auth.uid).child('id').val() === auth.uid"
}
}
}
}
Right now you have unnecessary redundancy in the teams node. The id of the child node is repeated in its own child id. You can simplify your database and rules if you simply set teams/{teamId} = true in the database, your rule could look like this instead to allow only users listed under teams to read the entire collection:
{
"rules": {
"collection": {
"$collection_id": {
".read": "data.child(auth.uid).val() === true"
}
}
}
}

Firebase Database Rules: can't write to database

I tried to set some important write persmissions but I can't solve my problem. I got told that, if I add a write-rule to room, then I overwrite my room/$roomID/ingame rule.
What I'm trying to do is
Creating a room by auth users.
Set/update ingame of a room only by the creator of the room. (That works)
Rules:
{
"rules": {
".read": true,
"user": {
".indexOn": "displayname"
},
"room": {
"$roomID": {
"ingame":{
".write": "data.parent().child('creatorUid').val() == auth.uid"
}
}
}
}
}
How I call to create a new room:
let user = firebase.auth().currentUser
dbRoomRef.push().then((room) => {
room.set({
creatorUid: user.uid,
ingame: false,
})
}).catch(function(err) {
console.log(err.message)
}
)
Error message (as expected):
FIREBASE WARNING: set at /room/-L572bnuRv0_vntko-Bd failed: permission_denied
Thank you.
The error messages says that you're trying to write /room/-L572bnuRv0_vntko-Bd and have no permission to write there. That is correct, since your rules only give permission to write to /room/-L572bnuRv0_vntko-Bd/ingame.
If creatorUid is already set when you create the room, you don't have to include it in your write statement and can just do:
room.child("ingame").set(false);
If you're trying to allow everyone to create a new room (or write to an existing room) as long as they are the owner, you need to set your rules one level higher:
"room": {
"$roomID": {
".write": "newData.child('creatorUid').val() == auth.uid"
}
}

How to add index rules for Firebase database?

I keep getting firebase messages on console regarding to add indexOn for user 4321 at chat rules. Below is my database.
And my rules in firebase is like:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"users": {
".indexOn": ["name", "email","uid"],
"$uid": {
".write": "$uid === auth.uid"
}
},
"chats": {
"$key": {
".indexOn": ["uid"]
}
}
}
}
I'm not sure why the indexing not working. And how can I improve indexing for overall database?
Your current data structure only allows to easily list all members of a chatroom, not the other way around. That may be the reason you get that message, because if you want to list all chats that user belongs to, you have to search through all /chats records.
You probably need to duplicate the chat room membership data both at /chat/<chat-id>/members and /users/<uid>/groups. Your case is almost identical to the one in the Firebase guide here -- read particularly the description below code in the section linked, but it's best to read the whole guide, it really helped me to understand how the database works.
Btw: your rule in chats: ".indexOn": ["uid"] doesn't do anything with the sample data you posted. It says to "index chat rooms by their uid attribute", but your chat rooms don't have an uid key inside (meaning uid: 'someid', not 'someid': true). See the indexing guide on more info how indexing works.
There are two types of indexing orderByValue: and orderByChild
Indexing with orderByValue::
{
"rules": {
"scores": {
".indexOn": ".value"
}
}
}
JSON Tree
{
"employee": {
<"employee1Key">: {
"empName": Rohit Sharma,
"Designation": SW Developer,
"empId": EMP776,
"branchDetails": {
"branch": Software,
branchLocation: Pune,
branchId: BR556
}
},
<"employee2Key>": {
"empName": Vira tKholi,
"Designation": Accountant,
"empId": EMP908,
"branchDetails": {
"branch": Finance,
branchLocation: Dheli,
branchId: BR557
}
},
<"employee3Key">: {
"empName": MS Dhoni,
"Designation": Sales Manager,
"empId": EMP909,
"branchDetails": {
"branch": Sales and Marketing,
branchLocation: Pune,
branchId: BR556
}
}
}
}
Indexing with orderByChild:
{
"rules": {
"employee": {
".indexOn": ["empName", "empId", "designation"]
}
}
}
Multilevel Indexing:
{
"rules": {
"employee": {
".indexOn": ["empName","empId","branchDetails/branch",
"branchDetails/branchLocation","branchDetails/branchId"]
}
}
}
You can also refer to this link for the Firebase Real-Time Database Data Indexing.
Firebase Real-Time Database Data Indexing

excluding children from a firebase node with read access

I'm creating a simple chat application using firebase and am running into some issues with the available security settings.
The data model for this application is very simple and is as follows
rooms:[
people:[
{
name: //string
status: // what the user is doing, typing, still connected etc.
secret: // the problem is with this
}
],
messages:[
{/* message to and payload*/}
]
]
the issue is that I only want the user that created the rooms[i].people[j] to be able to update the status of that person.
Being new to firebase I though I would be able to use the update function as follows
personRef.update({
'status': // newStatus
'secret': // used to authorize the update
})
the problem with this is I can't find any way to make the secret write only and give access to the people at the same time. That is I need anyone to be able to pull the data located at rooms[i].people - meaning rooms[i].people would have to have ".read":true (in firebases security rules). But this would give read access to every child and anyone in the room would be able to see any one else's update secret. I'm I thinking of this problem incorrectly?
Is there a way to give read access to a parent but exclude some of the children from the results?
Thanks!
It depends a bit on how you're using the secret to implement authorization, but I suspect denormalizing your data is going to do the trick. Try something like this:
people-secrets:[
<user's ID>: {
secret:
}, ...
],
rooms:[
people:[
{
name: //string
status: // what the user is doing, typing, still connected etc.
}
],
messages:[
{/* message to and payload*/}
]
]
That would allow you to segment the security rules:
{
"rules": {
"people-secrets": {
"$user_id": {
".read": "$user_id === auth.uid",
".write": "$user_id === auth.uid"
}
},
"rooms": {
"$room_id": {
"$user_id": {
".read": "auth.uid != null",
".write": "$user_id === auth.uid && root.child('people-secrets/' + auth.uid + "/secret") === <that token>"
}
}
}

Firebase Security Rules

I'm new to Firebase and really struggling with the security rules.
I'm trying to store data for anonymous user sessions that can only be accessed by that user but as soon as I tighten up the security rules I get permission denied and can't work out why.
The structure I have is:
/userSessions/$user/user_id
The application pushes to user sessions and writes the user_id as returned by the anonymous login.
I have the following security rules:
{
"rules": {
".read": true,
"userSessions": {
"$user": {
".write": "newData.child('user_id').val() == auth.id",
"user_id": {
".validate": "newData.isString()"
}
}
}
}
}
I'm sure I'm doing something silly, but can't work out how to use the security simulator either so don't know how to go about troubleshooting this
Any help greatly appreciated
EDIT -
Problem occurs when trying to create a new entry under userSessions after authenticating anonymously.
Code:
var userSessionsRef = new Firebase('https://xxxxxx.firebaseio.com/userSessions');
var userSession;
var auth = new FirebaseSimpleLogin( userSessionsRef, function(error,user) {
if (error) {
console.log(error);
} else if (user) {
userSessionsRef.child(user.id).set({
user_id: user.id,
provider: user.provider,
created: Firebase.ServerValue.TIMESTAMP
});
userSession = new Firebase('https://xxxxx.firebaseio.com/userSessions/'+user.id);
userSession.onDisconnect().remove();
}
The set() operation you've provided runs great; no errors; there must be another issue at play here that you haven't captured in your repro (did you enable anonymous auth in Forge?). Here's a fiddle running on your security rules, copied line-for-line (just moved down one child path): http://jsfiddle.net/katowulf/wxn5J/
On a related note, your current security rules will not allow the userSession.onDisconnect().remove(); op, since records can only be written if newData() contains a user_id value (i.e. it can't be null). A better way to structure these security rules would be as follows:
{
"rules": {
".read": true,
"userSessions": {
"$user": {
".write": "$user === auth.id", // delete allowed
"user_id": {
".validate": "newData.isString() && newData.val() === $user"
}
}
}
}
}

Resources