Rule entries duplicates firebase not working - android

I have an application in android that registers sellers, which have a unique email, I am storing them in firebase. Create a rule to not allow duplicates to be added but it does not seem to work. What am I doing wrong?
{
"rules": {
".read": true,
".write": true,
"sellers": {
"$seller": {
"email": {
".write": "!data.exists()"
}
}
}
}
}
my method to add
public void addSeller(Seller seller){
HashMap<String,Seller> map= new HashMap<>() ;
String email = seller.getEmail().replace(".",",");
map.put(email,seler);
database.child("sellers").setValue(map);
}

You're calling push(), which generates a new child that is statistically guaranteed to be unique.
If you want to ensure unique email addresses, you will have to keep a collection where the (encoded) email addresses are the keys:
emails
pete#somedomain,com
puf#somedomain,com
With this structure, the following rule will work to ensure an email address can only be written once:
{
"rules": {
".read": true,
"emails": {
"$email": {
".write": "!data.exists()"
}
}
}
}
The topic of unique values comes up regularly, so I recommend you also check out these:
Firebase android : make username unique
How do you prevent duplicate user properties in Firebase?
Enforcing unique usernames with Firebase simplelogin
unique property in Firebase
Firebase Unique Value
What Firebase rule will prevent duplicates in a collection based on other fields?

Related

Realtime database storage issues in firebase of android app

Authentication,verification of new user is working properly but in real time database,none of the user info is getting stored.
/in firebase method/
public void addNewUser(String email, String username, String description, String website, String profile_photo){
User user = new User( userID, 1, email, StringManipulation.condenseUsername(username) );
myRef.child(mContext.getString(R.string.dbname_users))
.child(userID)
.setValue(user);
UserAccountSettings settings = new UserAccountSettings(
description,
username,
0,
0,
0,
profile_photo,
username,
website
);
myRef.child(mContext.getString(R.string.dbname_user_account_settings))
.child(userID)
.setValue(settings);
}
As Frank says you must enable your read , write permissions into your rules from your database
Then inside you can change the following parameters
Allow users to read all the data from your database but not write if they are not authenticated
"rules": {
".read": true,
".write": "auth!=null"
}
Allow users to read and write documents inside your database without authenticating (not secure)
"rules": {
".read": true,
".write": true
}
Or simply use the best option that is allowing read and write only when the users are signed in with any of the Firebase Auth options
"rules": {
".read": "auth!=null",
".write": "auth!=null"
}

Querying a child of email id when email id is the key in Firebase, to check if the child exists or not

I have a Firebase database in Android where I have the root "USERS" and there are multiple users with the key as email id.
So the schema of database is something like this and the database uses email id as main key for each user:
{
"USERS":
{ "ABC#GMAIL,COM" :
{ "USERNAME": "abc",
"URL": "SOME_URL",...
}
}
{ "DEF#GMAIL,COM" :
{ "USERNAME": "dfe",
"URL": "SOME_URL2",...
}
}
.......
.......
.......
}
Now the email id serves as the main key for each user. Inside the email id is the username key which I want is to do a query on. I want to check if the username exists or not?
So the usual way to do this is to have a Database Reference- something like this-
DatabaseReference mDBRef = FirebaseDatabase.getInstance().getReference("/USERS/" + ???? + "/USERNAME");
Then add a value event listener on the database reference. In the dataSnapshot check if it exists or not-
dataSnapshot.exists()
Now I don't know what to append after "USERS". Also I want the database query to search username to be as efficient as possible. What could be the possible way to iterate through the email ids and check if the child key of email-id exists or not?
You can filter the results using orderByChild() function
databasereference.orderByChild("USERNAME").equal("whatever")
in order to get full performance add .indexOn attribute in firebase database rules
rules{
//other rules
"USERS":{
".indexOn":["USERNAME"]
}
}

How to set firebase read rule and read all siblings if one matches

I have set my firebase rules as follows:
{
"rules": {"users": {
"$uid": {
".read": "auth != null",
".write": "$uid === auth.uid"
}}
}
}
Which allows write only to the node with matching uid and read all child nodes of every uid. But I want it to be like if I query using a child node under uid, only the matching child and it's siblings can be read...
for example this is my json structure:
{
"users" : {
"AJkK4yZJsoseeefrJ7i6KIOUBDghtrhgthrtDi1" : {
"lat" : 20.5001,
"long" : 68.3755,
"number" : "9876543210",
"time" : 1499599788090
}
}
}
I want to query using the number, and set the read rule as can read lat long and time only where the number matches. How to write the rule?
update: my question now is, how to query the database using number and get other siblings if value of number matches in android? I have tried this but not working:}
friend = mDatabase.getReference("users");
friend.keepSynced(true);
Query z = LocationActivity.this.friend.orderByChild("number").equalTo("9876054321");
z.addListenerForSingleValueEvent((new ValueEventListener() {
long lastseen;
public void onDataChange(DataSnapshot dataSnapshot) {
try {
for (DataSnapshot zoneSnapshot: dataSnapshot.getChildren()) {
lastseen = (Long)zoneSnapshot.child("time").getValue();
friendLatitude = (Double) zoneSnapshot.child("lat").getValue();
friendLongitude = (Double) zoneSnapshot.child("long").getValue();
}
} catch (Exception e) {
}}
it returns value null, any help would be appreciated.
Firebase read permissions are enforced when you attach a listener. In order to query a node, you must have read permission on that node (as Bradley also explained). So in order to be able to query users, you must have read permission on /users. And since any user that has read permission to /users can also read any data under that, you cannot use security rules to filter what nodes a user has access to.
This is known as rules are not filters and is one of the common pitfalls for developers new to Firebase security model. I recommend that you read the documentation I linked already and some of the many questions/answer about the topic.
The simplest solution for your use-case seem to be to pull up the .read rule to users:
{
"rules": {
"users": {
".read": "auth != null",
"$uid": {
".write": "$uid === auth.uid"
}
}
}
}
}
In order to query every node, the user needs to have read permission for ALL nodes under the parent.
This is because security rules cannot be used to query data in Firebase.
Not exactly sure if this answers the question, but I found this post looking for the following solution with respect to Firebase Storage .. where I can control which sibling nodes are accessible:
match /uploadRoot/{userId}/{uploadCategory}/{allPaths=**} {
// allow read access for client upload/download
allow read, write:
if request.auth != null
&& request.auth.uid == userId
&& (
uploadCategory == 'userTextFiles'
|| uploadCategory == 'userImages'
);

How to implement ondelete cascade in Firebase (Android)

I am new with Firebase. I want to implement ondelete cascade in Firebase.
Here is the problem for which I want solution
I have two table "users" and "groups".
{ "users":{
"user1":{
"username":"john",
"full_name":"John Vincent",
"created_at":"9th Feb 2015",
"groups":{
"group1":true,
"group3":true
}
"last_logins":...
},
"user2": ...,
"user3": ...
}"groups": {
"group1"{
"group_name":"Administrators",
"group_description":"Users who can do anything!",
"no_of_users":2,
"members":{
"user1":true,
"user3":true
}
},
"group2"{
"group_name":"Moderators",
"group_description":"Users who can only moderate!",
"no_of_users":1,
"members":{
"user2":true
}
}
}
}
Please pardon me for above code indentation.
Now if I removed user1 from users table then how it should be automatically removed from groups table using Firebase.
This can easily done using SQL but I don't know how to do this in Firebase. One way to do this in Firebase is to remove user1 from users and then makes group1 and group3 to null and then in groups table make user1 to null under group1/member but this need 2-3 calls. So is there any another best way to do this.
Please help me I am stuck here.
The Firebase Database has no knowledge of relations between values in its JSON tree. In SQL/relations terms: it doesn't have the concept of foreign keys. This means that it also doesn't have an option to delete related objects with a cascading delete. You will need to delete each value separately.
But you can combine all those deletes into a single call by using multi-location updates. If you write null to each of the locations for the user, you can delete all of them with one call to updateChildren():
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Map<String,Object updates = new HashMap<String,Object>();
updates.put("users/user1", null);
updates.put("groups/group1/members/user", null);
// Do a deep-path update
ref.updateChildren(updatedUserData, new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
System.out.println("Error updating data: " + firebaseError.getMessage());
}
}
})
With this in place, you could then write security rules that validate that members of a group must also exist under the /users node:
{
"rules": {
"groups":
"$groupid": {
"users": {
"$uid": {
".validate": "newData.parent().parent().parent().parent().child('users').hasChild($uid)"
}
}
}
}
}
}
The validation rule is a bit easier to understand if you read the multiple .parent() calls as newRoot (which unfortunately doesn't exist). So in pseudo-code it is:
newRoot.child('users').hasChild($uid)
In words: a UID can only be a member of a group if it also exists under /users.

As Firebase rules are not filters, how do we filter?

I am trying to have a set of chats that contains a list of participants, and be able to query per user, its list of chats where the user is a participant.
Because filtering is not possible in Firebase on the server side (I guess for scalability), I understood that I have to prepare all the data in a resource for each form of "filtering" I need, so I have the following structure right now:
Those are the rules I wrote to secure the data:
{
"rules": {
"users": {
"$user_id" : {
"chats" : {
".read":"auth != null && $user_id == auth.uid",
".write": "auth != null && !data.exists()"
}
}
},
"chats": {
"$chatId": {
".read":"auth != null && root.child('users').child(auth.uid).child('chats').child($chatId).exists()",
".write": "auth != null && !data.exists()"
}
}
}
}
The first rule (/users/&user_id/chats) is OK and works as intended. I am able to query by user_id and get a map of all the chat_ids the user should have access to.
The second rule fails because what I thought I had was the chat_id but what I really have is the id for the object containing an attribute having the chat_id as uid, and I can't get to a child without knowing its ID, as rules are not filters.
The only way I see I can protect a chat is to have a string for a list of participants, and then use contains() on that child of a chat to block access to it if the user is not a participant of that chat.
Is there another way? Is it the way to go?
Instead of pushing new key to set the chat's id in the "uid" key, you can directly set the chat's key as the child under /users/<uid>/chats with true as the value.
{
"users": {
"<uid>": {
"chats": {
"<chat_id>" : true,
"<chat_id2>" : true
}
}
}
}
With this structure, your firebase database rules for the read access should be true for the correct user.

Categories

Resources