raiser00
raiser00

Reputation: 462

Firebase returns permission denied on random setValue() child data

I'm testing Firebase Rules to add more security to the data entry in the Firebase database. I would like to ensure that:

  1. Only Firebase Authenticated "users" can read/write their own account information into "accounts"

  2. only Firebase Authenticated "users" can read/write their own character data into "messages".

For this purpose I have written the following Rules:

{
  "rules": {
    "account": {
      "$uid": {
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid"           
      }     
    },  
    "messages": {
        "$message_id": {
        ".read": "auth !== null",
        ".write": "auth.uid === newData.child('_uid').val() && 
            root.child('account').hasChild(auth.uid) === true"  
      },
    }
  }
}

The above rules look to be correct, however I get "failed: DatabaseError: Permission denied" on (3) of the "messages" child nodes that I am pushing in for a logged-in user account.

Here is a code snippet of my push to firebase method:

public void saveToFirebase(){
  String echo = "";
  String _uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
  DatabaseReference mCurrentRecord = mFirebaseGame.push();
  Log.d(LOG, "User is " + _uid + "\nNew record ID: " + mCurrentRecord.getKey());

  gameCharacter.map.put("_uid", _uid);

  try{
    for(String keys : gameCharacter.map.keySet()){
      echo += keys + ":" + gameCharacter.map.get(keys) + "\n";
      mCurrentRecord.child(keys).setValue(gameCharacter.map.get(keys));
    }
  }
  catch(Exception e){
    error = e.toString();
  }
}

And here is the permission-denied error that I am getting:

Permission denied for txtStr, txtCharName and txtEner

I cannot follow why I would get permission denied errors only for the child nodes "txtStr, txtCharName and txtEner", while the rest have been successfully pushed to the database.

I hope you can point out if I miss anything in my Firebase Rules structure or anything. Thank you.

Upvotes: 0

Views: 239

Answers (1)

raiser00
raiser00

Reputation: 462

The correct answer to this question is as @Frank van Puffelen pointed out, by inserting ALL child node values at once by calling mCurrentRecord.setValue(gameCharacter.map), and not to iterate putting data to setValue() separately.

This is because of the "messages" Rule, which checks for a group of bulk-inserted child nodes in newData.

"messages": {
   "$message_id": {
      ".read": "auth !== null",
      ".write": "auth.uid === newData.child('_uid').val() && 
         root.child('account').hasChild(auth.uid) === true"  
   },
} 

Upvotes: 1

Related Questions