Different rule behaviours for the same scheme on Realtime Database - ios

I have added new security rules for my Firebase database, here they are:
{
"rules": {
"Users" : {
"$uid" : {
".read" : "auth != null && auth.uid == $uid",
"numberOfConnections" : {
".write" : "(auth != null && auth.uid == $uid) && (newData.val() - data.val() == 1 || newData.val() == 0)",
},
"mail" : {
".write" : "auth != null && auth.uid == $uid",
},
"numberOfFeedBack" : {
".write" : "auth != null && auth.uid == $uid",
},
"username" : {
".write" : "auth != null && auth.uid == $uid",
}
}
},
"Feedback" : {
"$uid" : {
".read" : "auth != null && auth.uid == $uid",
".write" : "auth != null && auth.uid == $uid",
}
},
}
}
When I write with updateChildValues in FeedBack it works, but when I write in Users I get a denied permission.
Here is the code:
// This don't work -> Permission Denied
static func createNewUsersDb(userId : String, username : String, mail : String) {
let update : [String : Any] = [
"/Users/\(userId)/username" : username,
"/Users/\(userId)/mail" : mail,
"/Users/\(userId)/numberOfConnections" : 0,
"/Users/\(userId)/numberOfFeedBack" : 0
]
dbRef.updateChildValues(update)
}
//This work
private static func createNewFeedBackDb(_ informationForFeedback : String){
let now = DateFormatter()
now.dateStyle = .medium
now.timeStyle = .medium
now.locale = Locale(identifier: "EN-en")
let update : [String : Any] = [
"/Users/\(userId!)/numberOfFeedBack" : ServerValue.increment(NSNumber(value : 1)),
"/FeedBack/\(userId!)" : [
"date" : now.string(from: Date()),
"information" : informationForFeedback
]
]
dbRef.updateChildValues(update)
}
It seems that it's because I didn't write a ".write" rule for Users.uid but I don't understand why it's blocking since I don't write when in the child nodes for which I did set a ".write" rule.
Also, if I write a ".write" rule in Users.uid, Firebase's rule handling would cause my sub-rule for numberOfConnections to be ignored.
That's why I specified the same ".write" rule for all child nodes of Users.uid except numberOfConnections, it seems a bit overkill but it's the only way I found.

I'm not exactly sure why your write rules don't work, since you're only writing to allowed paths/values as far as I can see. However, I'd typically implement the case differently, which may solve your problem anyway:
"Users" : {
"$uid" : {
".read" : "auth != null && auth.uid == $uid",
".write" : "auth != null && auth.uid == $uid",
"numberOfConnections" : {
".validate" : "(newData.val() - data.val() == 1 || newData.val() == 0)",
},
"mail" : {
".validate" : true
},
"numberOfFeedBack" : {
".validate" : true
},
"username" : {
".validate" : true
},
"$other" : {
".validate" : false
}
}
So now you only check for authorization once (on /Users/$uid) and then use validation checks to:
Allow mail, numberOfFeedBack, and username.
Allow numberOfConnections based on the value written.
Reject any other child nodes - the $other rule matches all child nodes that are not matched by another/named rules already.

Related

Allow another user to read/write data Firebase Database

I have a database tree like so
users
-UID
--items
---all the data
I would like to add something under UID like shared:another-UID and allow the other UID to read and write everything under items.
For example:
users
-UID
--shared:different_UID
--items
---all the data
My current rules are like this
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}
How would I change my rules to allow this?
In that case your rules would become:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && (auth.uid == $uid || data.child('shared').val() === auth.uid)",
".write": "auth != null && (auth.uid == $uid || data.child('shared').val() === auth.uid)"
}
}
}
}
So in words: the user can read/write this data if the key is the same as their user ID, or if their user ID is stored in the shared property under the data.

firebase realtime database rules, give access to user to access another user data

i want to give access to users profile to specific users that are set by the users themselves
in this rules i want to let $userid to be able to access $user_id data
(if $user_id exist in allow_list/$userid/), i tried root.child('allow_list/'+auth.uid+'/$user_id').exists())" but its not working
this is my rules for now, not working
"users_private": {
"$user_id": {
".write": "auth != null && $user_id === auth.uid",
".read":"(auth != null) && ($user_id === auth.uid
|| root.child('allow_list/'+auth.uid+'/$user_id').exists())"
}
},
"allow_list":{
"$userid": {
//ignore these rules they are working
".read":"auth != null && $userid === auth.uid" ,
"$user_id": {
".write": "($userid == auth.uid || $user_id == auth.uid )&&
( $userid!=$user_id)",
}
}
},
I found out how, hope this help someone.
I added .child, so the rule will be like this:
|| root.child('allow_list/'+auth.uid+'/').child($user_id).exists())

Bad json for Firebase data rules?

What's wrong with this? It says
Error saving rules - Line 12: Expected '{'.
Which regards the .body line, right after the :
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"v1": {
"v2": {
"$v3": {
"v4": {
"$v5": {
".body": "newData.isString() && newData.val().length > 0 && newData.val().length < 10"  
}  
}  
}  
}  
}
}
}
I got it.
The last part should have been
"body": {
".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 10"
}

Can not get value for top node by observing database reference in Firebase

I am trying to get the list of branches from Firebase database(in this example [branch1,branch2]) in Swift language,
when I observe the top node ("branches") it returns nothing and even the first print function is not being called, but if I observe one of the branches like branch1 it works fine.
now how can I retrieve the list of branches ([branch1,branch2])
let ref = FIRDatabase.database().reference()
ref.child("branches").observe(.value, with: { snapshot in
print("+++++++++++++++++ ")
print("++++++++++++\(snapshot.hasChildren())")
for child in snapshot.children{
let branch = child as! FIRDataSnapshot
let branchName = branch.key as! String
print("\(branchName)")
}
}
enter image description here
{ "Users" : {
"6dICrkbVVJWzVZ00Vq4y9Fm2Qcg2" : {
"branches" : {
"branch1" : true
},
"isAdmin" : true
},
"M0C1XUyboPg5zbgQi24nh3SlJri1" : {
"branches" : {
"branch2" : true
}
} },"branches" : {
"branch1" : {
"address" : "NDG",
"campaigns" : {
"valentine's day" : true
},
"manager" : "y",
"rate" : {
"average" : 0,
"bad" : 0,
"good" : 0
},
"users" : {
"6dICrkbVVJWzVZ00Vq4y9Fm2Qcg2" : true,
"M0C1XUyboPg5zbgQi24nh3SlJri1" : {
"isAdmin" : true
}
}
},
"branch2" : {
"address" : "downtown montreal",
"manager" : "x",
"rate" : {
"average" : 0,
"bad" : 0,
"good" : 0
},
"users" : {
"M0C1XUyboPg5zbgQi24nh3SlJri1" : true,
"Z6b5WalkNWZLMVdwGPHi3vSvSRU2" : {
"isAdmin" : true
}
}
} }, "campaigns" : {
"valentine's day" : {
"branches" : {
"branch1" : true
}
} }}
and the working code for getting branch1 is :
ref.child("branches").child("branch1").observe(.value, with: { snapshot in
let address = snapshot.childSnapshot(forPath: "address").value
print("\(address)")
}
and it will print the right result (NDG)
security rules :
{ "rules": {
"Users":{
"$uid":{
".read":"auth.uid == $uid || root.child('Users').child(auth.uid).child('isAdmin').val()==true",
".write":"auth.uid == $uid || root.child('Users').child(auth.uid).child('isAdmin').val()==true"
}
}, "branches":{
"$branchId":{
".read" : "auth.uid == true || root.child('Users').child(auth.uid).child('isAdmin').val()==true || root.child('branches').child($branchId).child('users').child(auth.uid).exists()",
".write" : "auth.uid == true || root.child('Users').child(auth.uid).child('isAdmin').val()==true || root.child('branches').child($branchId).child('users').child(auth.uid).child('isAdmin').val()==true"
}}}}
Thanks to #vzsg I found out that the problem was with the permission and rules. so I changed the rules and I get the result easily
{ "rules": {
"Users":{
"$uid":{
".read":"auth.uid == $uid || root.child('Users').child(auth.uid).child('isAdmin').val()==true",
".write":"auth.uid == $uid || root.child('Users').child(auth.uid).child('isAdmin').val()==true"
}
}, "branches":{
".read": " root.child('Users').child(auth.uid).child('isAdmin').val()==true" ,
".write" : "root.child('Users').child(auth.uid).child('isAdmin').val()==true ",
"$branchId":{
".read": " root.child('branches').child($branchId).child('users').child(auth.uid).exists()",
".write" : "root.child('branches').child($branchId).child('users').child(auth.uid).child('isAdmin').val()==true"
}} }}

Firebase security not working

Need help understanding what wrong with the "Tracking" rule. I'm able to read that data even though it's marked as .read : false.
{
"rules": {
"User": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
},
"Purchase": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
},
"Parm": {
".read": true,
".write": false
},
"Tracking": {
".read": false,
".write": true
}
}
}
This is being done on an IOS app. Here’s the code:
Firebase *ref = [FBase referenceForTrackingDeviceId:sysparm.deviceId];
[ref observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
if (snapshot.exists) {
DLog(#"got it");
} else {
DLog(#"No data");
}
}];
From the debugger:
(lldb) po ref https://<My-Firebase>/Tracking/E8C0C8FB-DE20-4017-9C74-3A6DAD6D4DC7 (lldb) po snapshot.exists YES

Resources