I've a very simple countdown in my Firebase database
I have this rule granting the node's access:
"actions":{
".indexOn":[
"timestamp"
],
".read":"auth != null",
"$act":{
"countdown":{
".write":"auth != null && data.val() - newData.val() == 1 && newData.val() >= 0"
}
}
}
the innitial value is only set manually by me... so at runtime users only can read and decrement value by 1. there is absolutelly only one call to write this node in my code and I use the following transaction:
@NonNull
public Transaction.Result doTransaction(@NonNull MutableData mutableData) {
long counter;
if (mutableData.getValue() == null)
counter = this.action.getCountdown();
else
counter = (long) mutableData.getValue();
if (counter > 0) {
mutableData.setValue(counter - 1);
return Transaction.success(mutableData);
} else
return Transaction.abort();
}
public void onComplete(@Nullable DatabaseError databaseError, boolean commited, @Nullable DataSnapshot dataSnapshot) {
if (databaseError != null && !databaseError.getMessage().contains("network disconnect")) {
Crashlytics.log("firebase user: " + FirebaseAuth.getInstance().getUid() + " error on action: " + this.action.toString() + " " + (dataSnapshot != null ? dataSnapshot.getValue().toString() : ""));
Crashlytics.logException(databaseError.toException());
} else if (commited) {
do stuff
}}
but I'm getting a very high number of "Permition Denied
" during my onComplete. all cases the: FirebaseAuth.getInstance().getUid()
is != null. so I'm sure there isnt any authentication problem.
My app is used by around 5k users per day
what is wrong with my code to explain why so many Permition Denied in such a simple counter?
======= UPDATE ==========
Explaining the context of this: this code runs only during the 'onCreate' of the Activity called right after login.
The innitial if should not even be necessary since im 100% sure user only gets here after a sucessful login, but as I didnt find anywhere a concrete oficial information saying if the FirebaseAuth can be invalidated when the user switches between apps for a long time I found easier just place the if.
this is absolutelly the only code that touches the refered database node.
if(FirebaseAuth.getInstance().getCurrentUser() != null)
App.getDatabaseInstance().getReference(Firebase.BRANCH_ACTIONS).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull final DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChildren()) {
for (final DataSnapshot actionDataSnapshot : dataSnapshot.getChildren()) {
try {
final Action action = actionDataSnapshot.getValue(Action.class);
//noinspection ConstantConditions
max = action.getTimestamp();
if (action.getCountdown() > 0)
actionDataSnapshot.child("countdown").getRef().runTransaction(new ActionTransaction(action));
} catch(Exception e){}
}
}
}
});
DatabaseReference
on which yuo run the transaction? Also, if you're sureFirebaseAuth.getInstance().getUid()
is not null, it helps if you prove that by logging its value right before you read/write and include the update code and the output of the log statement in your question. – Frank van PuffelenLog.d(TAG, "UID: "+FirebaseAuth.getInstance().getCurrentUser().getUid()
or maybe evenif (FirebaseAuth.getInstance().getCurrentUser() == null) throw new Exception("User is null")
. I trust code much more than anyone's (including my own) certainty. 2) Your secure rule contains 3 clauses that must all be true. Which one is failing? You can determine that by removing them one by one temporarily. – Frank van PuffelenFirebaseAuth.getInstance().getUid()
right after i checked it at the 'if' clause? ('FirebaseAuth.getInstance().getCurrentUser().getUid()'
this can thrownullpointerexception
) I also would like very much to know what clause is failing but firebase doesnt provide any way to debug that... and is very childish to play with database rules in production just for the sake of debug – Rafael Lima