I am trying to push data to my database and I want to check if the pushed data's owner id is the same as the uid of the person pushing it. I get permission denied . I don't know how to write security rules for pushing data, and I can't find anything about it. The data structure looks like this:
Shops{
"Shop1PushId" : {
"ShopCredentials" : {
"Owner" : "ownerUID"
}
}
"Shop2PushId" : {
...
}
This is the object I am pushing.
{
"ShopCredentials" : {
"Owner" : "owner_id",
"Another" : "another thing"
}
}
This is my firebase rule:
"Shops" : {
".read" : true,
".write" : "newData.child('ShopCredentials').child('Owner').val() === auth.uid"
}
Code in android studio:
DatabaseReference shopsRef = database.getReference("Shops");
shopsRef.push().child("ShopCredentials").child("Owner").setValue(shopData.getShopOwner());
Right now you're enforcing the rules on /Shops itself. But that is a list of shops. You're looking to enforce the rules on a specific shop, not on the list. To do that you add a so-called $ variable to the rules, which indicates that the rules below it apply to each child node:
"Shops" : {
".read" : true,
"$shopid": {
".write" : "newData.child('ShopCredentials').child('Owner').val() === auth.uid"
}
}
Now anyone can read all of the shops (even when they don't know the specific show ID), but someone can only write the shop if they know its specific ID and specify themselves as the owner of the new shop.
I'm not sure what you're exactly trying to secure here. If you are looking to bootstrap the process, so that people can only create new shops that have themselves as the owner, realize that with these rules anyone can still claim ownership of any shop they know the ID of. If you want to prevent that, and only want to allow claiming of ownership when the shop is created, use something like this:
"Shops" : {
".read" : true,
"$shopid": {
"ShopCredentials": {
"Owner": {
".write" : "!data.exists() && newData.val() === auth.uid"
}
}
}
}
Related
I'm trying to create admins for an app by manually entering them in Firebase based on their Twitter login generated uid. I'm wondering how I can search all of the children under a node for a specific uid to specify r/w access.
I have the following
{
"GRP1" : {
"ORG1" : {
"CONF1" : {
"TEAM1" : {
"ADMINS" : {
"Name1" : {
"uid" : "abcd1239"
},
"Name2" : {
"uid" : "abcf1234"
}
},
"FEED" : {
"Store1" : {
"info1" : "some text"
},
"Store2" : {
"info2" : "some other text"
}
}
}
}
}
}
}
I want to provide r/w access to FEED based on if the uid exists in ADMINS. This rules works:
".read" : "root.child('GRP1').child('ORG1').child('CONF1').child('TEAM1').child('ADMINS').child('Name1').child('uid').val() === auth.uid"
But if I have variable number of ADMINS, how do I search through all of the 'uid'? I have tried entering the child name as the uid, then searching to see if it exists but the read would not work:
".read" : "root.child('GRP1').child('ORG1').child('CONF1').child('TEAM1').child('ADMINS').child(auth.uid).exists()"
You can't search across nodes in security rules, as that would not scale. This means that if you want to check whether the UID exists in a certain place in your JSON, you must have that UID as the key of the node.
So your JSON would be:
{
"GRP1" : {
"ORG1" : {
"CONF1" : {
"TEAM1" : {
"ADMINUIDS" : {
"abcd1239": "Name1",
"abcf1234": "Name2"
}
Now you can check for the existence of the UID with:
".read" : "root.child('GRP1/ORG1/CONF1/TEAM1/ADMINUIDS').child(auth.uid).exists()"
I'm trying to make a database that has posts posted by a user and only persons subscribed to this person can see the post .
the problem here is that I add an event listener on parent node on hope that it returns child nodes that only apply to the read rule written inside the children , I do know about the "Rules are not filters" section in the documentation of fire-base and I can't reach a good time/memory efficient design where I only retrieve posts that apply to my rules.
That's my database
{
"Users" : { // ids of users using the app
"6Ya6nxqRy1fKt4BUOOh1brCJzvi2" : true,
"Nxmo8Wlhlcg4GDvh7ZIAnmBbpS82" : true,
},
"followers" : {
"6Ya6nxqRy1fKt4BUOOh1brCJzvi2" : { //followers to the user with this id
"Nxmo8Wlhlcg4GDvh7ZIAnmBbpS82" : false,
"n9jTaFVPDNh6bJSSZZCT20UFA972" : true
},
"Nxmo8Wlhlcg4GDvh7ZIAnmBbpS82" : {
"6Ya6nxqRy1fKt4BUOOh1brCJzvi2" : true,
"n9jTaFVPDNh6bJSSZZCT20UFA972" : true
}
},
"posts" : {
"-M3YxODIv6frqFyGM4Nm" : { //post with a random generated Id
"img" : "cd4aaff5-cab9-44d6-b7d9-7587ed2f19fc",
"post" : "See this cool character !!",
"user" : "Nxmo8Wlhlcg4GDvh7ZIAnmBbpS82"
}
}
}
}
and that's what i want to apply
{
"rules": {
".write": true ,
"posts":{
"$pid":{
".read": "data.child('user').val()===auth.uid ||root.child('followers').child(auth.uid).child(data.child('user').val()).val()=== true "
}
},
"followers":{
".read": true
},
"Users":{
".read": true,
}
}
}
the problem arises when I want to add event listener on "posts" node but as it doesn't have read : true so it doesn't return anything.
the only solution I could think of was to make another tree on same level of posts which will contain all posts names and then i start making single event listener on each post node (replace child(posts) to child(posts + post[i] ))
Is there any better option because in case of 100 post I will make 100 single event task which I think of as time ,memory and Internet unnecessary consuming
I'm the Android app developer, and I'm using Firebase Realtime Database. I want to make an app that when users who want to use my app can save something like the text in their repository. But when I save the text in my app, other users who download my app can see my unique saved text. Firebase Realtime Database rules like this. But they didn't work. Please tell me how to use private node in Realtime Database.
{
"rules": {
"messages": {
"$user" : {
".read" : "$user === auth.uid",
".write" : "$user === auth.uid"
}
}
}
}
enter image description here
You also need to check if the auth rules are null. If yes, then not allow anyone to access the information. Also, you need to use a wildcard, instead of a static $uid value. So, put this inside the messages node. So, as you want people to write in the messages node, but only those who are owners to see the message, this is the code for it:
{
"rules": {
"messages": {
"${uid}": {
".read": "auth.uid != null",
".write": "auth.uid != null && auth.uid == uid"
}
}
}
}
I think the rules below do the trick. The codes snippet:auth.uid == $uid makes sure that only the owner of the node has writing rights while auth != null makes sure that only users logged in to your app can read from it.
{
"rules": {
"messages": {
"$uid" : {
".read" : "auth != null",
".write" : "auth.uid == $uid"
}
}
}
}
Another StackOverflow Question may also be useful for you if the situation becomes a little more complex.
I have database json structure as:
{
"notifications" : {
"approved" : {
"notification_1" : {..},
"notification_2" : {..},
"notification_4" : {..},
"notification_6" : {..}
},
"pending" : {
"notification_3" : {..},
"notification_5" : {..},
"notification_7" : {..},
"notification_8" : {..}
}
},
"users" : {
"some_user" : {
"sent_notifications" : {
"notification_1" : "notification_1",
"notification_2" : "notification_2",
"notification_4" : "notification_4",
"notification_6" : "notification_6"
}
}
}
Security rules are as:
{
"rules": {
"notifications": {
"approved": {
".read" : true,
".write" : "auth.uid === 'admin'"
},
"pending": {
".write" : "auth != null && (newData.child('by_user').val() === auth.uid || auth.uid === 'admin')",
"$id" : {
".read" : "data.child('by_user').val() == auth.uid || auth.uid == 'admin'"
}
}
},
"users" : {
"$user_id":{
".read" : "auth.uid === $user_id",
".write": "auth.uid === $user_id"
}
}
}
}
Here, 'sent_notifications' stores notification id's which were added by user. On client side(Android), I wish to get list of those objects from notifications/approved, and notifications/pending, whose keys are in 'sent_notifications'. When a user sends a notification, that notification data goes in 'pending' and the key of that notification is stored in 'sent_notification'. After moderation admin would then move the data from pending to approved node. With any method I find myself doing a lot of queries on server to get all the nodes one by one. I need a better way to do this.
I am a newbie to firebase database. This may not be the best way to implement the database structure. I needed notifications/approved to be visible to general public and notifications/pending/$id to be visible only to user who is sending notification. This is the reference for above structure. If there is better way to implement it, please help me with that as well.
One option would be as follows:
Have the master list of all notifications (all users, pending and approved) under /notifications/ and grant read access only to the individual notifications (/notifications/$id) so that you must know the ID in order to read the notification.
Have an /approved_notifications/ list that just contains the notification IDs of approved notifications (just use the ID as the key and set the value to true or similar).
Have a /users/$user_id/sent_notifications/ list that again just contains the notification IDs of approved notifications.
If necessary have a /pending_notifications/ list as well, that again just contains IDs of notifications.
Basically you have one master list of notifications and then several "light" lists that "point" into that master list. Since the master list requires you to know the ID in order to read an individual post, users can't just read the list directly (you could also redundantly store a pending / approved flag inside the notification and have further security rules based on that if you wanted).
I am Developing an App where you live in a flat and have roommates, now I'm trying to disable access for all users that don't live in that flat.
Here are my Rules:
{
"rules": {
// no access
".read": "false",
".write": "false",
"Users" : {
"$userID" : {
//read on User Folder for all Users
".read" : "auth != null",
//write only for the user itself
".write" : "$userID === auth.uid"
}
},
"Flat" : {
"$flatID" : {
//Flat (identified through flatID) can only be accessed, if you are a roommate
".read" : "$flatID === root.child('Users').child(auth.uid).child('flatID').val()",
".write" : "$flatID === root.child('Users').child(auth.uid).child('flatID').val()"
}
}
}
}
My Database looks somewhat like this:
root
.Users
..uID
...(data)
...flatID : number
.Flat
..flatID
...(data)
So the flatID of that User is stored in his "folder" at root/Users/uID/flatID, which I try to get here: root.child('Users').child(auth.uid).child('flatID').val() and then I check it with the "folder" flatID.
Now if I try to write any Data into the flat, I don't have the right permission, and I cannot find my error.
The Users/userID rule is working fine
Thanks in advance :)
Edit:
The Data looks like this:
root
_Flat
__1
___name : "asdf"
__2
___(more Flats, for the Problem we only need one)
_Users
__F8XpTmxfIzYzrEY92alBOnx5eTO2 (Auth ID)
___flatID : 1
__nextUserID
___NextUserData
My Java Code to edit the flatname is:
fref.child("Flat").child(flatID).child("name").setValue(flatNameInput.getText().toString())
The flatID is a variable with the flatID for that user