auth.uid not working in firebase rules - android

I'm trying to add security rules to my firebase application. But auth.uid is not working..
Here is two of my security rules..
"groups": {
"$groupid":{
".read" : true,
".write" : "root.child('groupmembers').child($groupid).child('admins').child(root.child('users').child(auth.uid).child('username').val()).val()==true"
}
},
"groupchat":{
"$chatid":{
".read" : "root.child('groupmembers').child($chatid).child('members').child(root.child('users').child(auth.uid).child('username').val()).val()==true",
".write" : "root.child('groupmembers').child($chatid).child('members').child(root.child('users').child(auth.uid).child('username').val()).val()==true"
}
}
On the first rule auth.uid is working.. But in case of second and rest other rules, auth.uid is not working at all. I added my original uid in place of auth.uid and all rules are working properly.
Client side operation example..
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", userid);
map.put("message", userid + " Created This Group.");
map.put("timestamp", ServerValue.TIMESTAMP);
map.put("zcode",chat_key);
map.put("type", "action");
FirebaseDatabase.getInstance().getReference()
.child('groupchat')
.child(groupid)
.push()
.updateChildren(map);
Users Structure
"users":{
"my_uid" : {
"email" : "example#gmail.com",
"username" : "user1"
}
}
groupmembers structure
"groupmembers":{
"groupid":{
{
"admins" : {
"user1" : true,
"user3" : true
},
"members" : {
"user1" : true,
"user2" : true,
"user3" : true,
"user4" : true
}
}
}
}
So how can I solve this problem?

I think it was because of the version mismatch or different packages used for it so it can't can the auth.uid

Related

android firebase saving data to realtime database

In android app I create a firebase user authenticated by phone number and it works fine then I update this user adding display name and this is fine too; in the end I want to save user's data into firebase database so I wrote this rule:
"users" : {
"$user_id" : { // firebase user uid
".read" : "$user_id === auth.uid",
".write" : "$user_id === auth.uid",
".validate": "newData.hasChildren(['enabled', 'group', 'name'])",
"enabled" : { ".validate" : "newData.isBoolean()" },
"group" : { ".validate" : "newData.isString()" },
"name" : { ".validate" : "newData.isString()" },
}
}
This doesn't work and I get returned "permission denied" altough the simulator shows everything is fine (in the simulation I use custom authentication and set firebase as provider with the user's uid).
the user's class is:
public class User {
public boolean enabled;
public String group;
public String name;
public User() { }
public User(boolean enabled, String group, String name) {
this.enabled = enabled;
this.group = group;
this.name = name;
}
}
and i try to save it by:
private void saveUserToDB() {
User newUser = new User(true, "operators", currentUser.getDisplayName());
mRootRef.child("users").child(currentUser.getUid()).setValue(newUser, new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError != null) {
Log.e("ERROR", "Data could not be saved " + databaseError.getMessage());
} else {
Log.e("SUCCESS", "Data saved successfully.");
}
}
});
}
Can anybody kindly help me to understand why this happens?
Thanks
UPDATE
below is a "schema" of how the database should be:
{
"messages" : {
"1763409620982" : { // timestamp
"position" : "position text",
"sender" : "sender name",
"text" : "message text"
},
"1763409734527" : { // timestamp
"position" : "position text",
"sender" : "sender name",
"text" : "message text"
}
...
},
"users" : {
"Yi79w0HgA4ZTNAMHadixzoO5PaR2" : { // firebase user uid
"enabled" : true,
"group" : "group 1",
"name" : "user display name"
},
"kX22c0GgL4ZTNAMHallfgoO4pBN1" : { // firebase user uid
"enabled" : true,
"group" : "group 2",
"name" : "user name"
}
...
}
}
and here's the full set of rules:
{
"rules": {
"messages" : {
".read" : "root.child('users').child(auth.uid).child('group').val() === 'group 1'",
".write" : "root.child('users').child(auth.uid).child('group').val() === 'group 2'",
"$tstamp" :{
".validate": "newData.hasChildren(['position', 'sender', 'text'])",
"position" : { ".validate" : "newData.isString()" },
"sender" : { ".validate" : "newData.isString()" },
"text" : { ".validate" : "newData.isString()" },
}
},
"users" : {
"$user_id" : {
".read" : "$user_id === auth.uid",
".write" : "$user_id === auth.uid",
".validate": "newData.hasChildren(['enabled', 'group', 'name'])",
"enabled" : { ".validate" : "newData.isBoolean()" },
"group" : { ".validate" : "newData.isString()" },
"name" : { ".validate" : "newData.isString()" },
}
}
}
}
as to the class user it's defined as above and only used into the method saveUserToDB
Try to add push() before setValue(): It will add new sub-node containing all the fields from object of User class:
mRootRef.child("users").child(currentUser.getUid()).push().setValue(and so on...
May be you need write permission?:

Firebase security rules issue

I'm trying to restrict access to a particular groups if the user is not in the members list.
So this is my rule,
{
"rules": {
".read":"auth != null",
"groups": {
"$groupid":{
".read" : true,
".write" : "root.child('groupmembers').child($groupid).child('admins').child(root.child('users').child(auth.uid).child('username').val()).val()==true"
}
},
"groupchat":{
"$chatid":{
".read" : "root.child('groupmembers').child($chatid).child('members').child(root.child('users').child(auth.uid).child('username').val()).val()==true",
".write" : "root.child('groupmembers').child($chatid).child('members').child(root.child('users').child(auth.uid).child('username').val()).val()==true"
}
}
}
}
The first rule for "groups">"$groupid" works perfectly. But I'm getting problem with second rule for "groupchat"
DataStructure ex:
Group Chat structure
"groupchat" : {
"testinggroup" : {
"chat" : {
"-KiYN6RKZOyWI-qufWn3" : {
"message" : "Hey",
"timestamp" : 1493094660399,
"type" : "text",
"username" : "user2"
}
},
"lasttimestamp" : 1493094660674
}
}
Users Structure
"users":{
"ujciTL9oFKNylcgiGcdYqUxjcgA3" : {
"email" : "example#gmail.com",
"username" : "user1"
}
}
groupmembers structure
"groupmembers":{
"groupid":{
{
"admins" : {
"user1" : true,
"user3" : true
},
"members" : {
"user1" : true,
"user2" : true,
"user3" : true,
"user4" : true
}
}
}
}
groups structure
"groupid"{
{
"category" : "group category",
"creator" : "creator uid",
"desc" : "group desc",
"id" : "groupid",
"image" : "url",
"name" : "groupname"
}
}
Operation ex:
FirebaseDatabase.getInstance()
.getReference()
.child("groupchat")
.child(j)
.child("lasttimestamp")
.setValue(ServerValue.TIMESTAMP);
So to debug the errors
I added "myusername" in place of root.child('users').child(auth.uid).child('username').val()
and it's working.
But in the previous rule("For groups child") I added the same thing and it was working.
I don't know why I'm getting error.

How to prevent duplicated uname of Users Firebase [duplicate]

This question already has answers here:
How do you prevent duplicate user properties in Firebase?
(2 answers)
Closed 6 years ago.
I am adding username for my Chat App to Firebase Database successfully.
I implemented in activity:
FirebaseDatabase firedb = FirebaseDatabase.getInstance();
in createUser Method.
private void createUser(String uname){
Map<String,Object> newUser = new HashMap<String, Object>();
newUser.put("uname",uname);
DatabaseReference dbref = firedb.getReference();
dbref.child("Users").push().setValue(newUser);
}
When user click a button this method works. This method work correctly but I want to make uname primary key. I do not want to add a username if it is alerady exists.
Database Structure:
Rules:
{
"rules": {
".read": true,
".write": true
}
}
Finally, how to prevent duplicated uname ?
You have to add a top level /uname/ Node. Your data will be like this for example :
{
"Users" : {
"user1" : {
"uname" : "value1",
},
"user2" : {
"uname" : "value2",
},
"user3" : {
"uname" : "value3",
},
},
"uname" : {
"value1": "user1",
"value2": "user2",
"value3": "user3",
}
}
Now you have to Enforce New Data Structure:
{
"rules": {
"users": {
"uname": {
".validate": "!root.child('uname').child(newData.val()).exists()"
},
}
}
}

Adding limits to Firebase Query in Android?

My app loads links shared by a user on a listview. I'm trying to load 10-links/posts at a time, and once the user reaches the end query for 10 more links/posts, and so on.
I've denormalized the data, so that once a post is made, its created under "/links" and "user-links/$userId/" by the following code:
String key = mDatabase.child("links").push().getKey();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/links/" + key, postValues);
childUpdates.put("/user-links/" + FirebaseAuth.getInstance().getCurrentUser().getUid() + "/" + key, postValues);
Firebase Data
links
{
"pushId1": {
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309151261,
"link" : https://www.youtube.com/watch?v=bwbwTKXlvQA
},
"pushId2": {
"userId" : zZio89, //userId2
"createdAt" : 1483309145896,
"link" : https://firebase.google.com/docs/database/android/lists-of-data
},
"pushId3": {
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309155525,
"link" : https://firebase.google.com/docs/database/security/indexing-data
}
}
user-links
{
"userId1":
{
"pushId1":
{
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309151261,
"link" : https://www.youtube.com/watch?v=bwbwTKXlvQA
},
"pushId3":
{
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309155525,
"link" : https://firebase.google.com/docs/database/security/indexing-data
},
},
"userId2":
{
"pushId2":
{
"userId" : zZio89, //userId2
"createdAt" : 1483309145896,
"link" : https://firebase.google.com/docs/database/android/lists-of-data
},
},
}
This is how I currently retrieve the data based on the time its createdAt:
Query myTopPostsQuery = mDatabase
.child("user-link")
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.orderByChild("createdAt")
.limitToFirst(QUERY_LIMIT);
Where; int QUERY_LIMIT = 10;
Firebase Rules
{
"rules":
{
".read": "auth != null",
".write": "auth != null"
}
}
Questions:
1) Once the user reaches the end, how do I skip the first 10 links (which have already been loaded) and load the next 10-links?
2) Is there a way to assign Ascending or Descending order? I would like to show the latest post first.
3) Is firebase-rules ".indexOf" the solution? If so can someone share the exact rule that I must write?
Note: createdAt is generated by the following code while creating the data initially: postValues.put("createdAt", ServerValue.TIMESTAMP );

Firebase write permission denied

I can't figure out why firebase won't let me do this specific write. I feel like I do it the same in the simulator and it works there. Below are my security rules for this section.
"joinRequests" : {
"$clanid": {
"$requesterid" : {
".read" : "$requesterid === auth.uid || root.child('clans/' + $clanid + '/members/' + auth.uid + '/admin').val() === true",
".validate": "newData.hasChildren(['request'])",
"request" : {
".write" : "true",
".validate": "newData.hasChildren(['name', 'message'])",
"name" : {
".validate": "newData.isString()"
},
"message" : {
".validate": "newData.isString()"
},
"$other": {
".validate": false
}
},
"approved" : {
".write" : "root.child('clans/' + $clanid + '/members/' + auth.uid + '/admin').val() === true || ($requesterid === auth.uid && !newData.exists())",
".validate": "newData.isBoolean()"
},
"$other": {
".validate": false
}
}
}
},
In the code for my android app I run these two lines:
dataSnapshot.child("request").getRef().removeValue();
dataSnapshot.child("approved").getRef().removeValue();
What I find weird is that it allows me to remove the "approved" value but not the "request" value. The dataSnapshot is a $requesterid. If I run this line in the simulator and it allows the write:
/joinRequests/QV28VJYG/c1cef959-2dd3-4cab-8649-2b81892cffa6/request
The error I get in android studio is this:
W/RepoOperation: setValue at /joinRequests/QV28VJYG/qRlJt4UIAcRVIe9VXoYVBa68tO43/request failed: DatabaseError: Permission denied
It must be something dumb that I'm doing but I can't imagine what it would be. Any help would be great, Thanks.
newData is a snapshot that represent how data will look like after the operation took place.
newData.hasChildren(['request']) tells firebase to make sure that the request node exists after the operation was executed. Therefore, deletion of this node is prohibited.

Categories

Resources