Prevent user from finding users that have blocked them Firebase - firebase

In my app, I don't want a user that has been blocked by another user, to find such user.
Let's say, user1 has blocked user2. When user2 then searches through all the users within the app, I want user2 to find every user except user1, because user1 has blocked user2. It's like with Instagram, when you block someone that someone cannot interact with you in any way. I have stored the users in the realtime database like so:
users
|-user2(uid)
|-blocks
|-user1(uid): 1
|-email: String
|-id: String(the uid)
|-fcm: String
|-name: String
|-profileImage: String
|-username: String
I am trying to prevent user2 from interacting with user1 with these Firebase rules:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && !(root.child('users').child(auth.uid).child('blocks').hasChild($uid) != true)",
".write": "auth != null"
}
},
"posts": {
"$postId": {
".read": "auth != null",
".write": "auth != null"
}
}
}
}
user2 cannot see user1 anymore when going through another user's followers list, although user1 is in that list. So the security rules work there. But now, none of the users within my app can look for any other user anymore, because as soon as the search is activated, my console says this:
[Firebase/Database][I-RDxx0xxxxx] Listener at /users failed: permission_denied
At every other "window" like feed or other user's followers list the console says this:
[Firebase/Database][I-RxxBxxxxxx] Listener at /users/user1 failed: permission_denied
This shows, that it is somewhat working, because only for user1 the permission was denied.
So what is the mistake?

Firebase security rules don't filter the data. They merely enforce that the data you're trying to access is allowed by the rules.
This is so important that there's even a documentation section about it: rules are not filters. It's also a common source of confusion though, given these previous questions on the topic.
Since in your rules nobody is granted access at /users, the code that tries to read from /users is rejected. And since your test user apparently was blocked by user1, the rule there rejects their access.
To securely query data the rules and code need to work together. The code should only request data it is allowed to access, so that the rules can then verify that.
In your case that'd mean that a user can only request /users if they somehow exclude users that have blocked them. This unfortunately isn't possible in Firebase queries, so you'll have to come up with a different data model for this use-case, or by loading the user data one-by-one. The latter is not nearly as slow as you may initially think, as Firebase pipelines the requests over a single connection.

Related

what is the correct way to make signup Auth and store it in database?

I have three screens:
Sign Up
log In
HomePage
now, In signup, I have some text field and a profile picture to store.
my question is how and what is the correct way to store data from the signup screen and then use the data to authenticate in the login screen.
Currently, I m using a realtime database from firebase to store data and email and password authenticate.
but rules for the realtime database is this:
{
"rules": {
".read": true,
".write": true
}
}
but I want to use this rule:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
tell me what is the correct way to do this?
You can use this link Authenticate with Firebase using Password-Based Accounts on Android
The best approach is when a user signs up. You do it with the above code.
After the first authentication success.
You can use the FIrebaseUser.getUId to get the specific users unique identifier and use it as the user's key in a database.
In your databaseRerence you can save the user's data like the following.
FirebaseDatabase.getInstance().getReference().child(FirebaseUser.getUID).setValue(USERDATA)
The USERDATA here is a pojo representing the user's data e.g. name,address,telephone etc
I always structure my apps in a way that am in control of the userflow.
have a splash screen that opens when a user opens my app, the i check if the user was already authenticated in an earlier process.
If firebaseAuth.getCurrentUser returns an object, i know that the user is registered and is already logged in so i will forward him to the Homepage.
If it returns null then i know the user might have logged out or not signed up. In that case i just send him to a login screen in your case log in.
if there weren't signed up they will not be able to proceed to HOmepage so you redirect
them to the Sign up screeen.
Hope that helps. If you don't succeed with this approach. Don't worry the community got you.

Firebase rule allowing new user inclusion and user-specific path privileges

After reading lots of tutorials and StackOverflow's questions I still couldn't figure how to do it.
All the tutorials start with the following rule:
"users":{
"$uid":{
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
But how to allow a new user in the users node when a new user log in (auth != null) and keep the read and write user-specific path privileges ?
In other words:
Is there a way to make a new user be inserted in the users node after login, and at the same time restrain him to only read and write to his own node ?
Another question. I have a write rule in another node with newData.exists(). In the Simulator when I try to write null data to the node it denies it as expected, but it allows me to write null to a child of this same node. Shouldn't the node write rule cascade to its children ?
The rules you have above will match $uid to auth.uid. So, for example if a user's UID is cKzMyjImSBX6ybzeCCCjf0qbTym1, they will be only be able to read & write at /users/cKzMyjImSBX6ybzeCCCjf0qbTym1 in your database, regardless of whether or not this key currently exists (if it doesn't exist when written to, it will be created).
From the Firebase documentation on rules:
Once a user authenticates, the auth variable in your Firebase Database
Rules rules will be populated with the user's information. This
information includes their unique identifier (uid) as well as linked
account data, such as a Facebook id or an email address, and other
info.

Keeping firebase data secure

So the last thing I want is anyone accessing the database that isn't supposed to. Users on my app create an account which has a key and children in my database (an easy to acces user profile) and it also makes an auth account. The rules of the database state that only authenticated users can access the database. Is it possible for someone who is authenticated to somehow access the rest of the database (through hacking maybe)? This is my first app using firebase and I want to make sure that user information will be protected.
It depends by your rules.
If the rule is:
// These rules require authentication
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
This kind of rule allows full read and write access to authenticated users of your app. In other words an authenticated user can access all the data in the database without any hacking.
If you set something similar to this rule:
{
"rules": {
"users": {
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
it grants write access to the owner of this user account but only of this data.
It means that you have to set the rules to obtain the wanted result for each nodes in your data.

How do you block users on Firebase?

I'm using Firebase for my app and was wondering how to block certain users. I see on the Auth tab of the console, there are "delete" and "disable" options. What do those do? I haven't been able to find documentation on that. Will one of those allow me to block a user?
What I mean by blocking a user is for the ".read": "auth != null" rule to prevent him from accessing data on the database
The disable feature consist in preventing that user to authenticate. So if he tries to authenticate he will fail with error code INVALID_CREDENTIALS and he won't have access to the data that has the ".read": "auth != null" rule. It works like he is deleted but the admin still have the power to reactivate the user account.
If you want to build a list of "blocked users" that will be able to authenticate but will have restricted access, you can store the blocked ids in a node on your firebase database like /databaseRoot/blockedUsers and then work with the security and rules.
".read": "auth != null && !root.child('blockedUsers').hasChild(auth.uid)"
blockedUsers could look like the tree bellow but you could also add some other info under the userId such as the date this user was blocked.
/databaseRoot
/blockedUsers
userId1 : true
userId2 : true
Adding the user to this list will depend on your necessity. You can do it manually by accessing the firebase console and adding the user id to the node. Or, if you want to block an user based on an event on the application, you could simply call something like
ref.child('blockedUsers').child(userIdToBlock).set(true);

Share data with friends on Firebase

I am currently developing an app that needs a server backend to sync data between devices and also friends. So while researching if I should make my own server (which I'd prefer not to) I stumpled upon Firebase.
What I havenĀ“t figured out is how public data is. From how I understood it, is that whatever I send up could be seen by every user of my app. I saw that you can define rules like "The user needs to be logged in", but can I specify that a certain child should only be visible to the user who created it? And then, is there a way to invite an other user to collaborate on that child? So that now only the creator and the invited user can see that child?
My app would be running on iOS in the beginning, but I guess thats not relevant to my question, is it?
Yes you can do that, you can set security rules to allow only the user with a specific UID (firebase user id) to write or read data like this example...
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid"
}
}
also with custom authentication you can create your custom claims to grant different access levels (for example admin, editor..etc)
example...
"frood": {
// A towel is about the most massively useful thing an interstellar
// hitchhiker can have
".read": "auth.hasEmergencyTowel === true"
}
and for the invitation part.. you can also grant permission by using a child node as a reference like in this example...
".read": "data.child(auth.uid).exists()",
In the last case.. if the data path requested has a child key that is equal to the uid of the client trying to access it the information will be able to read the data,
all the detailed information is here:
https://firebase.google.com/docs/database/security/user-security#section-revisiting-advanced-example

Resources