Firebase database rules for particular field [duplicate] - swift

This question already has an answer here:
Firebase: Allow Read of property names, but not content
(1 answer)
Closed 17 days ago.
I have a Firebase database JSON in a format
global_records
field1:
private_records
field_A:
field_B
And I have rules set as
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
When I call observeSingleEventOfType to get globar_records I get the error permission_denied. This works when Sign In.
How do I only allow access to global_records to all the users and need to authenticate to access private_records?

you can add rules for your nodes separately.
{
"rules": {
"global_records": {
".read": true
".write": true
},
"private_records": {
".read": "auth != null"
".write": "auth != null"
},
}
}

Related

Firebase says that my rules are insecure, why?

I have received an email from Firebase advising me that my security rules are insecure citing: Any user can read/write to your database.
How can this be, I have specified .read and .write rules below. What am I missing? any help would be much appreciated.
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"venues-location": {
".indexOn": "g"
},
"users-compliments": {
"$uid":{
"$uid":{
".indexOn": ".value"
}
}
},
"users-invites": {
"$uid":{
"$uid":{
".indexOn": ".value"
}
}
},
"users-location": {
".indexOn": "g"
}
}
}
".read": "auth != null",
".write": "auth != null",
These above rules are default rules. According to firebase documentation They allow full read and write access to authenticated users of your app. They are useful if you want data open to all users of your app but don't want it open to the world
It is essential that you configure these rules correctly before launching your app to ensure that your users can only access the data that they are supposed to.
{
"rules": {
"foo": {
".read": true,
".write": false
}
}
}
Here's an example of a rule that grants write access for authenticated users to /users//, where is the ID of the user obtained through Firebase Authentication.
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}
}
"auth != null" is not enough. It means anyone who is authenticated can read/write to another user's data. You probably want to add something like:
".write": "auth.uid == $uid" under the $uid nodes.
to only allow the authenticated user to access their own data and not another user's.

firebase Error Consider adding ".indexOn":

I am using firebase in swift to read some data from firebase realtime database. When I had one project in firebase panel its work fine, but after adding another project today I got error like this
2017-09-23 00:15:18.360 AfgDate[2816] [Firebase/Database][I-RDB034028] Using an unspecified index. Your data will be downloaded and filtered on the client. Consider adding ".indexOn": "date" at /data to your security rules for better performance
This is my database structure
my role was
{
"rules": {
".read": true,
".write": true,
}
}
after that i changed my roles to this one
{
"rules": {
"data": {
".indexOn": "date",
".read": true,
".write": true
}
}
}
in this time also i cant read data and and i didn't see any error in console
this is my code in swift
ref = Database.database().reference()
ref.child("data").queryOrdered(byChild: "date").queryEqual(toValue: "1396/06/05").observeSingleEvent(of: .value, with: { (snapShot) in
if let snapDict = snapShot.value as? [String:AnyObject]{
for each in snapDict{
let key = each.key as String
let date = each.value["date"] as!String
let name = each.value["text"] as! String
print(key)
print(name)
self.lblshow.text = name
}
}
}, withCancel: {(Err) in
print(Err.localizedDescription)
})
how
*Please, study the comments to know how the problem was actually solved.
Try this, and with the same Data(with capital "D") in rules as well as in your query like Jen suggested .
{
"rules": {
".read": true,
".write": true,
"Data" : {
".indexOn": "date"
}
}
}
And try this
var ref: FIRDatabaseReference!
ref = FIRDatabase.database().reference()
instead of
ref = Database.database().reference()
The image of your database shows Data as capitalized, but your .indexOn data isn't. You want your rules to be like this:
{
"rules": {
"Data": {
".indexOn": "date",
".read": true,
".write": true
}
}
}
I tested a couple rules myself just now and found out that they are case sensitive.

How to forbid rewriting data if it exists

I add user in table "users" after authorization. Also I will add to this user some values, which I don't want to be overrided.
ref.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).setValue(["username": "MyName"])
Rules
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"users": {
".write": "!root.child('users/'+auth.uid).exists()",
".read":true,
"positive": {
".read": true,
".write":false,
},
"negative": {
".read": true,
".write":false,
},
}
}
}
removes old data and put a new.
I want to write rule on server side, which will ignore setting value if it already exists.
If you call updateChildValues(), the properties you specify will be updated:
ref.child("users")
.child((FIRAuth.auth()?.currentUser?.uid)!)
.updateChildValues(["username": "MyName"])
See the Firebase documentation on updating specific fields.
Your rules will not work, since you cannot take away a permission that you've given on a higher level in the tree. See the Firebase documentation on the cascading of permissions.
To ensure a user always has certain properties, use a rule on the user's node:
"users": {
"$uid": {
".write": "newData.hasChildren(['certain', 'properties])",

Firebase Security for their recommended chat structure implementing lastMessage

So I've come across this thread.
Structuring data for chat app in Firebase
I would just like to give a sample for my firebase db structure ( similar in firebase docs).
{
"chatMetadata": {
"chatroom_id_1": {
"title": "Some Chatroom Title",
"lastMessage": "Some Message",
"timestamp": 1459361875666
"users": {
"uid_1": true,
"uid_3": true
}
},
"chatroom_id_2": { ... }
},
"users": {
"uid_1": {
"chatRooms": {
"chatroom_id_1": true,
"chatroom_id_2": true
},
},
"uid_3": { ... }
},
"chatrooms": {
"chatroom_id_1": {
"m1": {
"name": "uid_1",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... }
},
"chatroom_id_2": { ... }
}
}
For me to implement like a recent chat messages. I'll probably need the "/chatMetadata/" data since it has the lastMessage
To query it in client we need the answer in the link above to get it in one reference alone.
//chatMetaDataRef = root of "chatMetadata"
chatMetaDataRef.queryOrderedByChild("users/uid_3").queryEqualToValue(true)
.observeSingleEventOfType(.Value, withBlock: { snapshot in
// Do something here
})
Problem with this is all users should have read access to "/chatMetadata" node for that to work.
Here is my security rule for it
{
"rules": {
".read": "auth.uid === 'someServiceWorker'",
".write": "auth.uid === 'someServiceWorker'",
"chatMetadata": {
"$chatroomId":{
".read": "data.child('users/'+auth.uid).exists()"
},
".read": "auth != null"
},
"chatrooms": {
"$chatroomId": {
".read": "root.child('chatMetadata/'+ $chatroomId + '/users/'+auth.uid).exists()",
}
},
"users": {
"$userId": {
".read": "auth.uid === $userId"
}
}
}
}
Now my question is how should we implement the security rule for this one such that users shall not have access to all chatMetadata(because if i remove "auth!=null", my query above will not work. Or if it is not possible how should we restructure the data such that we can query it with one reference alone?
P.S.
Reason for the question is I didn't like the idea that I will loop over "users/$uid/chatrooms" and query each reference I receive from it. Like the 2nd answer in the link above.
for chat in listOfChatsUserIsIn
ref.child("chatMetadata").child("\(chat)").child("lastMessage").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
lastMessage = snapshot
// do something here
}

firebase swift -- users query

I am trying to find a way I could have a query for the users in my application. For example, if my user want to search for a user to add him as a friend. I think I can save all the users in the Firebase database, and then perform a query in the database, but it look very inefficient(and there must be a easier built in method to do it).
".indexOn" is the solution for you!!
If you structure you date like below you would be able to query user!! Here you are able to query user on full_name and reversed_full_name. You can provide whichever child you want to query on. For instance, you can add email field under people and then add "email" in ".indexOn"!!!
"people": {
".indexOn": ["_search_index/full_name", "_search_index/reversed_full_name"],
".read": true,
"$uid": {
".write": "auth.uid === $uid",
"full_name": {
".validate": "newData.isString()"
},
"profile_picture": {
".validate": "newData.isString()"
},
"posts": {
"$postId": {
".validate": "newData.val() === true && newData.parent().parent().parent().parent().child('posts').child($postId).exists()"
}
},
"_search_index": {
"full_name": {
".validate": "newData.isString()"
},
"reversed_full_name": {
".validate": "newData.isString()"
}
},
"following": {
"$followedUid": {
".validate": "newData.parent().parent().parent().parent().child('followers').child($followedUid).child($uid).val() === true" // Makes sure /followers is in sync
}
}
}
Hope this helps. Here's the link to whole security rules, which is provided from Firebase https://github.com/firebase/friendlypix/blob/master/web/database-rules.json