I'm trying to figure out how to do this correctly.
In Firebase I have certain user-generated content stored in /sites/{uid}/.... My security rules are set like that:
"sites": {
"$uid": {
".read": "auth !== null && auth.uid === $uid",
".write": "auth !== null && auth.uid === $uid"
}
}
This way each user can only access their own content. But I have an anonymous function that needs to access that content as well and update it.
What's the best way for me to give access to that function, other than making all the content public.
Thanks in advance!
Related
I am using firebase database in my app. I have set the rules to allow normal users to create new childs in the node but I found that it's refused.
this is the writing rules of the node :
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\" || ((newData.exists() && !data.exists()) || auth.token.email == data.child(\"userEmail\").val())",
I think that newData.exists() && !data.exists() should allow users to write in the database but this doesn't happened
this is the rules of the users node :
"users":{
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\" || ((newData.exists() && data.child(\"userEmail\").val() != null) || auth.token.email == data.child(\"userEmail\").val())",
".read": "auth != null"
}
The database strucutre is like that :
-users
-user1
-userName, userEmail ....
-user2
-userName, userEmail .....
when a new user sign up in the app he should be allowed to push his data in the database
this is the database structre :
Ok, I think you're creating extra validation steps that aren't needed.
First
With ".read": "auth != null" on your users root, each user is able to access other user's data, so we should address the access for each user individually.
Second
If you just want to allow users that are authenticated to write and read its own contents, you can remove these extra ((newData.exists() && !data.exists()) and auth.token.email == data.child(\"userEmail\").val()) steps.
Tip: this ((newData.exists() && !data.exists()) comparison means exactly: Write here if you're sending anything but there should be nothing written in this requested "path". You should reflect on the need of this, as I don't know your exact use cases.
Also, I would guess the hardcoded UID you're requesting is of an Admin you've created - I wouldn't recommend this, please read more about user roles on this answer.
To clarify, I think your rules structure should be something like this:
{
"rules": {
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\",
".read": "auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\",
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
So I'm delving into Firebase security rules and as far as I understand, rules that are specified higher up in the tree cascade further down into the tree.
So I'm wondering if there's a way to make a case work where I basically have a /bands subtree that I want writeable by anyone, however there are admins and members subtrees where I want only writeable, based on special conditions.
So far, this is kinda what I have going on:
{
"rules": {
".read": "auth != null",
"bands": {
"$bandId": {
".write": "auth !== null",
"$bandId": {
".write": "auth !== null && data.child('creator_id').val() === auth.uid"
}
}
}
}
}
When I go to test "writing", in the Firebase simulator, something like /bands/-KnLeIHM4zCspwBZjZP9 where the creator_id does NOT match the specified auth.uid I have provided, I still get a simulator write success, due to the /bands tree-level having the write access.
Is there any clever way to do allow anyone to "push" to /bands but then when it gets down to the actual /bands/$bandId level, it starts looking at these various conditions? Or am I going to have to rework my data and separate out the trees into even more trees? I have other instances where this kind of thing is necessary, but this is the most succinct version I am working with that I need to solve.
Any thoughts? Thanks in advance :)
{
"rules": {
"bands": {
".read": "auth != null",
".write": "!data.exists() && auth != null",
"$bandId": {
".write": "data.child('creator_id').val() === auth.uid"
}
}
}
}
".write": "!data.exists() && auth != null" will only allow authenticated users to write to paths within bands if they don't exist (creating new content).
Are these rules in correct format? When I put them in Database Rules, I see red dashed lines which may indicate an error/warning but when I hover over it, I receive no feedback.
{
"rules": {
"users": {
"$uid": {
// grants write access to the owner of this user account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in --&& auth.provider === 'password'
".read": "auth !== null"
}
},
"usernames": {
"$userName": {
// grants write access to the owner of this user account whose uid must exactly match the key ($uid)
".write": "root.child('usernames').child($userName).child('uid').val() == auth.uid || root.child('usernames').child($userName).child('uid').val() == null",
// grants read access to any user who is logged in --&& auth.provider === 'password'
".read": "auth !== null"
}
},
"following": {
"$uid": {
// grants write access to the owner of this user account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in --&& auth.provider === 'password'
".read": "auth !== null"
}
},
"followedBy": {
"$fid": {
"$uid": {
// grants write access to the owner of this user account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in --&& auth.provider === 'password'
".read": "auth !== null"
}
}
}
}
}
This is what I see:
To reformat your code rules and make it read able
Just copy your rules and then go to JS cleaner and click claen Js re copy and past into your database rules
I've seen those too. Pretty much as soon as I add an empty line.
I think the empty lines are just causing a false error indicator to show up.
Since nothing's failing (at least not for me as far as I can see), I wouldn't worry about them.
I'm working on a Firebase rule configuration to control read/write access to my database. I had more rules written originally, but I've pared things down during troubleshooting. Here is my current rule configuration:
{
"rules": {
"developers": {
"$dev": {
".write": "!data.exists() && auth != null",
".read": "auth.devBucket === $dev",
"$proj": {
".read": "auth.devBucket === $proj",
"shared": {
".write": "!data.exists() || (auth.devBucket === $dev && auth.projBucket === $proj)"
}
}
}
}
}
}
What I'm trying to do is allow users of the Firebase to create a $dev node, $proj node, and shared node as long as they don't already exist and the user is authenticated. Then, I want to allow a user to have free write access within the shared node as long as their auth token's devBucket matches the $dev node they're writing within and their auth token's projBucket matches the $proj node they're writing within. I'm using the Firebase custom auth system for Android and I've loaded my tokens with these devBucket and projBucket variables. Authentication is definitely working according the my logcat, but I'm definitely getting permission denied errors with my current rules. I've been pouring over the Firebase Rule documentation and questions here for days and I am still puzzled as to the nuances of how their rule system works.
According to the documentation rules carry through to lower levels of nesting in the JSON, I'm just having trouble understanding how I can write a rules that allows a node and it's children to be created once, but also allows any number of children to be written or overwritten under shared if you're properly authenticated.
Does anyone have any idea how I could write rules to accomplish what I'm trying to do?
EDIT: I think it's also worth mentioning that I'm getting permission denied errors when I try to point listeners to my nodes too.
I figured out a configuration that worked for me.
{
"rules": {
"developers": {
".write": "!data.exists() || auth != null",
".read": "auth != null",
"$dev": {
".write": "!data.exists() || (auth != null && auth.devBucket == $dev)",
".read": "auth != null && auth.devBucket == $dev",
"$proj": {
".write": "!data.exists() || (auth != null && auth.projBucket == $proj)",
".read": "auth != null && auth.projBucket == $proj"
}
}
}
}
}
Before in my app I was creating accounts successfully until I put some rules
{
"rules": {
"users": {
"$uid": {
// grants write access to the owner of this user
// account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in
// with an email and password
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
then, the accounts are created because I see those accounts in the dashboard. But once I try to create, I am getting this kind of errors
FIREBASE WARNING: set at /users/simplelogin:32 failed: permission_denied
Since you want the user to be able to create their own node initially, you'll need to explicitly allow the case where the location is new.
Based on the documentation on the auth parameter:
".write": "!data.exists() || auth.uid === $uid""
Note: I'm not entirely sure this will work, but felt it'd be more readable as in answer-format than as a "try this" comment.