How to make my Realtime database readable only by my users? - firebase-realtime-database

I am using the Firebase Realtime database only to know if I still have a connection to it like suggester here. So, there is nothing in it.
I thought the rules that I put was enough, but Google thinks it is not safe and I need to change it.
So, I went from:
{
"rules": {
".read": "auth != null",
".write": false
}
}
To this:
{
"rules": {
".read": false,
".write": false
}
}
That worked fine for my iOS app, but not with my Android app. Putting the 'read' to 'false' makes that solution not workable because of the solution suggested here.
What would you suggest me?

For those of you that had the same issue, here what Google tech support suggested me
You could modify this a bit like FirebaseDatabase.getInstance().getReference(“connect/” + (new Date()).toString()).keepSynced()
And in your Realtime Database rules, allow to read, write auth != null to this “connect” child.
It would look like this:
{
"rules": {
"connect":{
".read": "auth != null",
".write": "auth != null"
},
".write": false,
".read": false
}
}

Related

realtime-database rule validation is not working when updating data with null

When I try to update data in realtime-database with null, ".validate" in database.rules.json seems to be ignored.
I have a database.rules.json in the following format (not the exact same way, but this shows what I expect at least).
database.rules.json
"data": {
".read": "auth != null",
".write": "auth != null",
".validate": "newData.val() != null"
}
When I update realtime-database with
frontend.js
import { set } from 'firebase/database';
export class PublishService {
...
setWithData(value) {
// suppose dbReference has ref to "data"
// something like ref(this.database, "data")
set(this.dbReference, value);
}
}
where value == null,
I can still update realtime-database with null even though this isn't what I expect.
Is this how realtime-database is supposed to work?
If that's the case, is there any documentation that says that?
The .validate rule is not triggered for data deletions. From the documentation on .validate rules:
the validate definitions are ignored when data is deleted (that is, when the new value being written is null).
So you'll want to check for newData.exists() in the .write rule.

firebase rules allow only certain user to write key valus

i want to write firebase realtime database rule where certain user can only write cetain key
ex: user with UID underlined in red can write value of key franchise_active only
user with UID underlined in green can write value of key vendor_active only
both users can read
Sounds possible. Something like this should work:
{
"rules": {
"application_status": {
"$uid1": {
"$uid2": {
"franchise_active": {
".write": "auth.uid === $uid1"
},
"vendor_active": {
".write": "auth.uid === $uid2"
}
}
}
}
}
}

How can you observe a snapshot of a upper level child w/o overriding the lower child rules?

JSON
"users" : {
"02PdiNpmW3MMyJt3qPuRyTpHLaw2" : {
"Coordinates" : {
"latitude" : -24.809620667034363,
"longitude" : 28.321706241781342
},
"Education" : "6", ........./// here are 10 Childs further on same level as education
"Music"
The current rules
{
"rules": {
".read": false,
".write": false,
, "users": {
"$uid": {
"Education" :{
".read": "$uid == auth.uid",
".write": "$uid == auth.uid"
}
According to my understanding, if I make users read rule for authorized users, it will override the education rule. This below is where users read rule is needed
let artist = Database.database().reference().child("users").queryOrdered(byChild: "music").queryStarting(atValue:dateToday.timeIntervalSince1970*1000)
artist.observe(DataEventType.value, with: { snapshot in
Update: I had a typo "users" at the rules
In general indeed the rule is that if you grant somebody read (or write) access to a node, they have the same access to all data under that node. So you can't just say ".read": true on /people as that will them to read the entire node.
What you can do is specify what query is allowed in your security rules. So to allow every to read all nodes with the given music value, you could do:
"baskets": {
".read": "query.orderByChild == 'music' &&
query.equalTo > 1354867200000"
}
A few things to keep in mind here:
I hard-coded it here, but you will have to calculate the value for the filter in your rules somehow based on the now variable.
You can only filter on a single value, so you can't filter on both music and uid. You may be able to merge the two values into a single property and order/filter on that. For more on this see: Query based on multiple where clauses in Firebase

Firebase (Swift) runTransactionBlock: permission denied

May I ask what runTransactionBlock is doing behind the hood? When I run a simple setValue with the exact same rules it works, but not with runTransactionBlock. I suspect that behind the hood runTransactionBlock writes to paths outside of just the path I stated, which is causing my security rules to deny permission. Hence, I have to write a global ".write": "auth != null" and avoid doing stuff such as my wildcard ".validate": false.
My security rules are mapped out this way:
{
"rules": {
// NOTE: I NEED THIS GLOBAL WRITE ALLOW FOR TRANSACTION TO WORK
".write": "auth != null",
"real_db": {
// USERS
"users": {
"$user": {
".read": "auth != null",
"$other": {
// NOTE: I NEED TO COMMENT VALIDATE FOR OTHER FIELDS IN USER
// ".validate": false
},
"pushToken": {
".read": "auth != null",
".validate": "auth != null"
},
...
My runTransactionBlock is run on the path real_db/users/$uid and I am changing the value of pushToken. When setValue is run on this same path and modifying pushToken it works.

Firebase: How to enable users to decide on the privacy of their data?

Let's assume that users store some private data in /private/$userId which they can either share with others or not. The decision should be stored in /privacySettings/$userId/shareData which is of kind Bool. If the user sets its value to true others should be able to read the private data.
I have persistance enabled and tried to solve this with server rules:
"private": {
".read": false,
".write": false,
"$userId": {
".read": "auth != null && root.child('privacySettings/' + $userId + '/shareData').val() === true",
".write": "auth != null && auth.uid == $userId"
}
}
This works fine, but unfortunately a change in shareData does not raise an event when private/$userId is observed with .Value. So if the other user has observed this path before the change in the privacy, he will still see the data cached in the persistancy data store, which shouldn't be the case. When shareData is false all data should be hidden to others.
How to do this?
EDIT:
Just found out that once the data has been read, the observer will always return the cached data no matter if shareData has been set to false. This also happens when the app gets restarted.
EDIT 2:
After thinking more about it I came to the conclusion that this problem can easily be solved if the callback gave back a "permission denied" error.
I guess I found a reasonable workaround / solution for the problem:
Embedding the shareData in /private/$userId like so:
- private
- $userId
- shareData // Bool
- data // contains private data
Even if there is cached data, one can easily hide it according to the value of shareData without observing another node.
Server rules:
"private": {
".read": false,
".write": false,
"$userId": {
".read": "auth != null", //(*)
".write": false,
"shareData": {
".write": "auth != null && auth.uid == $userId",
".read": "auth != null",
},
"data": {
".read": "auth != null && root.child('private/' + $userId + '/shareData').val() === true",
".write": "auth != null && auth.uid == $userId",
}
}
}
EDIT:
Seems like the line marked with (*) overrides the child rules... Using "data.child('shareData').val() === true" there will cause the same effect as before: if there is cached data, it will be displayed.

Resources