Android - Firebase rules read permission issue - android

I need help with Firebase read Rules.
this is the structure of my database
db:{
user:{
uid0:{
name:"mario",
lastname:"super"
}
uid1:{
name:"bubu",
lastname:"gogo"
}
uid1:{
name:"fajio",
lastname:"mkokd"
}
}
}
my rules:
{
"rules": {
"user":{
"$uid":{
".read":"auth.uid === $uid",
}
}
}
}
With rules simulator there are not problem to read user's info.
In my activity im using recycler view for populate list with user's name but
i get Permission Denied.
WHat's te problem?? What's wrong??
this is my query for populate list
Query query = FirebaseDatabase.getInstance().getReference().child("user");
EDIT:
`10-28 17:28:22.680 8317-8387/com.scidaconnectpeople.www.scida W/SyncTree: Listen at /user failed: DatabaseError: Permission denied
10-28 17:28:22.680 8317-8317/com.scidaconnectpeople.www.scida W/FirebaseRecyclerAdapter: com.google.firebase.database.DatabaseException: Firebase Database error: Permission denied
at com.google.firebase.database.DatabaseError.toException(Unknown Source)
at com.firebase.ui.database.FirebaseRecyclerAdapter.onCancelled(FirebaseRecyclerAda pter.java:199)
at com.firebase.ui.database.FirebaseRecyclerAdapter$1.onCancelled(FirebaseRecyclerAdapter.java:116)
at com.firebase.ui.database.FirebaseArray.notifyCancelledListeners(FirebaseArray.java:119)
at com.firebase.ui.database.FirebaseArray.onCancelled(FirebaseArray.java:99)
at com.google.android.gms.internal.zzaip.zza(Unknown Source)
at com.google.android.gms.internal.zzakn.zzcxi(Unknown Source)
at com.google.android.gms.internal.zzaks$1.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5538)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:958)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:753)`

Firebase Database security rules are enforced on the level where you try to attach the query. Since you attach a query on /users, that's where it checks if you have read permission. Since you don't have read permission on /users, the query is rejected/cancelled.
This is often unexpected to developers new to Firebase. We call it "rules are not filters", both in the documentation and here on Stack Overflow.

There are lot of chances that problem you are facing due to google-services.json.
please confirm that you have downloaded updated json file.
Check these Docs

Related

Firebase Authentication reassigned UIDs of existing users on migration to a new version of an Android app

I store user data in a Firestore document, and for the document's ID I use the user's UID provided by Firebase Authentication. So to access the user data, I call fAuth.currentUser.uid and provide the string to the query.
The old version of the app was written in Java, and recently I translated it to Kotlin, creating a new project in Android Studio for that, though it's still connected to the same Firebase project. New users register and use the app just fine. Existing users, however, can't access their data (which is crucial for the app's functionality), because the call for UID returns a different value, and the Firestore query returns a non-existing snapshot.
I use authentication with email and password. Both of them stay the same, the old users login successfully, but as soon as the app needs the user data from the database, it crashes.
I guess there is no way to get back to the previous UID, so I am just curious about what has happened. The only differences between Java and Kotlin projects that I could identify are the app's namespace and the rootProject.name variable from the settings.gradle file.
Can anyone please explain why the existing users got new UIDs?
Edit 1: I use Firebase SDK Authentication with email and password
fAuth.createUserWithEmailAndPassword(email, password)
Edit 2: what leads up to the crash:
from a data source, the app listens to a Firestore document containing the user data, and transmits it to a repository as a flow:
fun getUserFlow(): Flow<DocumentSnapshot?> =
if (fAuth.getUserObject() != null) {
fStore.collection("usuarios")
.document(fAuth.getUserObject()!!.uid)
.snapshotAsFlow()
} else {
flowOf(null)
}
the repository collects the flow and stores the data contained in the snapshot locally, in the form of a Proto DataStore object:
private fun collectUserFlow() {
appScope.launch {
fStoreSource.getUserFlow()
.catch {
currentCoroutineContext().cancel(null)
}
.collect { userSnapshot ->
updateUserData(userSnapshot)
}
}
}
private suspend fun updateUserData(userSnapshot: DocumentSnapshot?) {
if (userSnapshot != null) {
userDataStore.updateData { user ->
user.toBuilder()
.setNombre(userSnapshot.getString(KEY_NOMBRE))
.setTelefono(userSnapshot.getString(KEY_TELEFONO))
.setEmail(userSnapshot.getString(KEY_EMAIL))
.setToken(userSnapshot.getString(KEY_TOKEN))
.setMesa(userSnapshot.getString(KEY_MESA))
.setIsPresent(userSnapshot.getBoolean(KEY_IS_PRESENT)!!)
.setBonos(userSnapshot.getLong(KEY_BONOS)!!)
.build()
}
}
}
For the new users, who just downloaded the Kotlin version, the code works perfectly fine. For the existing users, who migrated from the Java version to the Kotlin version, after they logged in successfully (i.e. the transmitted flow of the userSnapshot is not null), trying to update the userDataStore produces a NullPointerException:
2023-01-13 11:17:46.312 20966-21215/com.cafeyvinowinebar.Cafe_y_Vino E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.cafeyvinowinebar.Cafe_y_Vino, PID: 20966
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at com.cafeyvinowinebar.cafe_y_vino_client.UserData.setNombre(UserData.java:46)
at com.cafeyvinowinebar.cafe_y_vino_client.UserData.access$100(UserData.java:9)
at com.cafeyvinowinebar.cafe_y_vino_client.UserData$Builder.setNombre(UserData.java:428)
at com.cafeyvinowinebar.cafe_y_vino_client.data.repositories.UserDataRepository$updateUserData$2.invokeSuspend(UserDataRepository.kt:340)
at com.cafeyvinowinebar.cafe_y_vino_client.data.repositories.UserDataRepository$updateUserData$2.invoke(Unknown Source:8)
at com.cafeyvinowinebar.cafe_y_vino_client.data.repositories.UserDataRepository$updateUserData$2.invoke(Unknown Source:4)
at androidx.datastore.core.SingleProcessDataStore$transformAndWrite$newData$1.invokeSuspend(SingleProcessDataStore.kt:402)
at androidx.datastore.core.SingleProcessDataStore$transformAndWrite$newData$1.invoke(Unknown Source:8)
at androidx.datastore.core.SingleProcessDataStore$transformAndWrite$newData$1.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:169)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
at androidx.datastore.core.SingleProcessDataStore.transformAndWrite(SingleProcessDataStore.kt:402)
at androidx.datastore.core.SingleProcessDataStore.handleUpdate(SingleProcessDataStore.kt:276)
at androidx.datastore.core.SingleProcessDataStore.access$handleUpdate(SingleProcessDataStore.kt:76)
at androidx.datastore.core.SingleProcessDataStore$actor$3.invokeSuspend(SingleProcessDataStore.kt:242)
at androidx.datastore.core.SingleProcessDataStore$actor$3.invoke(Unknown Source:8)
at androidx.datastore.core.SingleProcessDataStore$actor$3.invoke(Unknown Source:4)
at androidx.datastore.core.SimpleActor$offer$2.invokeSuspend(SimpleActor.kt:122)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}#9ab40ad, Dispatchers.IO]
Basically, the get methods called on the snapshot return null.
To understand the issue better, I edited the updateUserData() a bit:
private suspend fun updateUserData(userSnapshot: DocumentSnapshot?) {
if (userSnapshot != null) {
if (!userSnapshot.exists()) {
Log.d(TAG, "updateUserData: snapshot doesn't exist!")
Log.d(TAG, "updateUserData: snapshot's ID: ${userSnapshot.id}")
Log.d(TAG, "updateUserData: current user's UID: ${fAuthSource.getUserObject()!!.uid}")
} else {
userDataStore.updateData { user ->
user.toBuilder()
.setNombre(userSnapshot.getString(KEY_NOMBRE))
.setTelefono(userSnapshot.getString(KEY_TELEFONO))
.setEmail(userSnapshot.getString(KEY_EMAIL))
.setToken(userSnapshot.getString(KEY_TOKEN))
.setMesa(userSnapshot.getString(KEY_MESA))
.setIsPresent(userSnapshot.getBoolean(KEY_IS_PRESENT)!!)
.setBonos(userSnapshot.getLong(KEY_BONOS)!!)
.build()
}
}
}
}
And the log reads:
2023-01-13 11:28:31.744 27734-28131/com.cafeyvinowinebar.Cafe_y_Vino D/UserDataRepository: updateUserData: snapshot doesn't exist!
2023-01-13 11:28:31.744 27734-28131/com.cafeyvinowinebar.Cafe_y_Vino D/UserDataRepository: updateUserData: snapshot's ID: gLYjEBJeMwRi5LgBSgztgqF7XYg2
2023-01-13 11:28:31.744 27734-28131/com.cafeyvinowinebar.Cafe_y_Vino D/UserDataRepository: updateUserData: current user's UID: gLYjEBJeMwRi5LgBSgztgqF7XYg2
To sum up the problem: from the Firebase Authentication the app gets the current user's UID and queries the Firstore db for the user's document, stored under their UID. But since the current UID is not the UID under which the user initially signed in and stored their data, the document's snapshot returns empty, and the user can't access their data.
Edit 3: Also it's important to add, that before I updated the app to the Kotlin version on Google Play, I lost my keystore file and had to request a new upload key. So the upload key of the Kotlin version is different from that of the Java version. Can it be the source of the issue?

How to find out if app has been disconnected from Google Drive?

I'm building an app where I store app data in the app-specific-folder on Google Drive. I've been able to setup everything related to file storage and retrieval. The problem I'm facing is regarding permissions. The user has an option to disconnect the app from the Google Drive settings panel.
I use the DriveScopes.DRIVE_APPDATA meaning https://www.googleapis.com/auth/drive.appdata scope to save data.
I'm trying to figure out how to find out if this has happened on the app side. If I try to continue using the drive related apis, with the app being disconnected, then it crashes with a UserRecoverableAuthException.
com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:297)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:868)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:476)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:409)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:526)
at abhiank.maplocs.ui.drivesync.DriveSyncService.onHandleIntent(DriveSyncService.kt:68)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:78)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: com.google.android.gms.auth.UserRecoverableAuthException: NeedPermission
at com.google.android.gms.auth.zze.zzb(Unknown Source:13)
at com.google.android.gms.auth.zzd.zza(Unknown Source:77)
at com.google.android.gms.auth.zzd.zzb(Unknown Source:20)
at com.google.android.gms.auth.zzd.getToken(Unknown Source:7)
at com.google.android.gms.auth.zzd.getToken(Unknown Source:5)
at com.google.android.gms.auth.zzd.getToken(Unknown Source:2)
at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source:55)
at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:267)
at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:292)
I tried the following to figure out if the app does not have the permissions or scopes.
Look at data inside GoogleSignInAccount instance received from GoogleSignIn.getLastSignedInAccount(this). This had the following scopes available in account.grantedScopes() after app had been disconnected. drive.appdata is shown even though app is disconnected.
[https://www.googleapis.com/auth/drive.appdata, https://www.googleapis.com/auth/userinfo.profile, https://www.googleapis.com/auth/userinfo.email, openid, profile, email]
Last thing I tried was hasPermissions method available in GoogleSignIn. I checked if the APP_DATA scope was available with this call and it returned true. So no help there either.
GoogleSignIn.hasPermissions(account, Scope(DriveScopes.DRIVE_APPDATA))
I'm really stuck now. Any help will be really appreciated. Thanks.
I ended up using a try-catch around my drive related code and catching the UserRecoverableAuthIOException. According to the documentation, this is called when -
UserRecoverableAuthExceptions signal Google authentication errors that
can be recovered with user action, such as a user login.
This has worked decently well for me. Considering the fact that this question has not received any other answers in 2 years, there doesn't seem to be any method to fetch the information about whether the app is disconnected or not via an API or SDK call.
Here's the code I use
fun getGoogleDriveService(context: Context): Drive {
val credential = GoogleAccountCredential.usingOAuth2(context, setOf(DriveScopes.DRIVE_APPDATA))
credential.selectedAccount = GoogleSignIn.getLastSignedInAccount(context)!!.account
return Drive.Builder(NetHttpTransport(), GsonFactory(), credential)
.setApplicationName(DriveSyncService.APP_NAME)
.build()
}
try {
val driveService = getGoogleDriveService(this)
var fileList = driveService.files().list().execute()
//...
//more code
} catch (e: UserRecoverableAuthIOException) {
/*
Doing a sign-out on the googleSignInClient so that there is no mismatch
in sign-in state and so that when I start sign-in process again, it
starts afresh
*/
googleSignInClient.signOut()
/*
Then I show a pop up telling user that app was disconnected and
to sign in again. And then on click I start the sign-in flow again.
*/
} catch (e: GoogleJsonResponseException) {
//https://googleapis.dev/java/google-api-client/latest/index.html?com/google/api/client/googleapis/json/GoogleJsonResponseException.html
//404 is file being updated/deleted was not found
if (e.message != null && e.message!!.contains("storageQuotaExceeded")) {
//todo handle storage exceeded error. Inform user
}
} catch (e: IOException) {
//todo handle network error
}

com.samsung.android.simplehealth E/SimpleHealth: Getting step count fails

I'm trying to use Samsung sample SimpleHealth for retrieving data from Samsung Health app, but when I give the permission to get StepCount data, I get a weird error:
java.lang.SecurityException: com.samsung.android.simplehealth does not match with registered signature. 4A:E1:B9:8D:04\
at android.os.Parcel.createException(Parcel.java:2074)\
at android.os.Parcel.readException(Parcel.java:2042)\
at android.os.Parcel.readException(Parcel.java:1990)\
at com.samsung.android.sdk.healthdata.IDataResolver$Stub$Proxy.readData2(IDataResolver.java:588)\
at com.samsung.android.sdk.healthdata.HealthDataResolver.read(HealthDataResolver.java:576)\
at com.samsung.android.simplehealth.StepCountReporter.readTodayStepCount(StepCountReporter.java:67)\
at com.samsung.android.simplehealth.StepCountReporter.start(StepCountReporter.java:48)\
at com.samsung.android.simplehealth.MainActivity$1.onConnected(MainActivity.java:72)\
at com.samsung.android.sdk.healthdata.HealthDataStore$ErrorMessageHandler.handleMessage(HealthDataStore.java:593)\
at android.os.Handler.dispatchMessage(Handler.java:107)\
at android.os.Looper.loop(Looper.java:224)\
at android.app.ActivityThread.main(ActivityThread.java:7548)\
at java.lang.reflect.Method.invoke(Native Method)\
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)\
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Faced same error. You need to add dev access code.
Follow Prerequisites section carefully from this page https://developer.samsung.com/health/android/sample/simple-health.html

Detect added libraries to pirated Android app?

It appears from my crash reports that some people pirate my app and add advertisements to monetise it.
The stack trace from the crash report seems to show a bunch of calls to a library to show interstitials?
Is it possible for me to add code to detect the presence of the com.test.ylh or com.qq.e library?
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#da2c866 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:1126)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:439)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:95)
at android.app.Dialog.show(Dialog.java:473)
at com.qq.e.comm.plugin.intersitial2.e.a(A:315)
at com.qq.e.comm.plugin.intersitial2.e.show(A:113)
at com.qq.e.comm.plugin.intersitial2.e.show(A:107)
at com.qq.e.comm.plugin.intersitial2.d.show(A:35)
at com.qq.e.ads.interstitial2.UnifiedInterstitialAD.show(Unknown Source:4)
at com.test.ylh.InterAd$2.run(InterAd.java:53)
at android.app.Activity.runOnUiThread(Activity.java:6972)
at com.test.ylh.InterAd.showAd(InterAd.java:50)
at com.test.ylh.InterAd.onADReceive(InterAd.java:108)
at com.qq.e.comm.plugin.intersitial2.a$1.run(A:169)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7860)
at java.lang.reflect.Method.invoke(Method.java:-2)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
You can check if a class exists with a method as described over here: How to check if class exists somewhere in package?
However, they could also remove that check when recompiling the app. So it won't be airtight. You can make it more difficult for the "pirates" by adding proper code obfuscation: https://developer.android.com/studio/build/shrink-code#obfuscate

Firestore operations (add(), set()) not working

I am trying to add user details to Firestore db, but can't write data in it.
Actually none of the listeners are triggered neither onSuccess() nor onFailure().
here is my code.
Map<String,Object> userlol = new HashMap<>();
userlol.put("name",name);
userlol.put("email",email);
userlol.put("uid",currentUser.getUid());
Log.d(TAG, "we are here");
CollectionReference dc = db.collection("users");
DocumentReference dd = dc.document(currentUser.getUid());
dd.set(userlol)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(SignupActivity.this, "User Added" ,
Toast.LENGTH_SHORT).show();
Log.d(TAG,"User added to database");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(SignupActivity.this, "ERROR" +e.toString(),
Toast.LENGTH_SHORT).show();
Log.d(TAG, e.toString());
}
});
There is no toast nor the Log in my logcat.I can see
D/logging: we are here
This log and logs after this method.
There is no issue with rules as onFailure() is also not working.
I have searched every possible thing but nothing worked.
The only way I can get neither of the callbacks to trigger is when there is no network connection on my device. In that case the behavior makes sense, since the task is only considered completed when the data has been committed (or rejected) on the server.
To easily see if the Firestore client indeed can't connect to the server, enable debug logging:
FirebaseFirestore.setLoggingEnabled(true);
I see log entries like this after doing so:
11-12 07:56:21.366 10034-10066/com.firebase.firestorestackoverflow I/Firestore: (0.6.6-dev) [zzetk]: (b6322ac) Stream closed with status: zzcd{code=UNAVAILABLE, description=null, cause=java.net.UnknownHostException: Unable to resolve host "firestore.googleapis.com": No address associated with hostname
at java.net.InetAddress.lookupHostByName(InetAddress.java:470)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
at java.net.InetAddress.getAllByName(InetAddress.java:215)
at io.grpc.internal.zzbj$zzb.zztu(Unknown Source)
at io.grpc.internal.zzbk.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
at libcore.io.Posix.android_getaddrinfo(Native Method)
at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:55)
at java.net.InetAddress.lookupHostByName(InetAddress.java:451)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252) 
at java.net.InetAddress.getAllByName(InetAddress.java:215) 
at io.grpc.internal.zzbj$zzb.zztu(Unknown Source) 
at io.grpc.internal.zzbk.run(Unknown Source) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818) 
}.
well for anyone having that problem in the future just Uninstall your application and reinstall it, as savage as it seams it works(y)
I had the same problem.
First of all turning on the logs helped a lot as #Frank van Puffelen suggested.
In my case I got "The Cloud Firestore API is not available for Datastore Mode projects".
So I went to GCP and created manually a collection by changing the db to a native one. And then I had an option on the gui.
Now the error changed to "FirebaseFirestoreException: permission_denied: missing or insufficient permissions"
So I changed the permissions under the "rules" tab in firestore.
And that fixed it for me :)
I guess the problem was the permissions from the beginning, but I can't tell for sure now.
I had the same error. In my case, I was creating a user and automatically logging him/her out, for them to log manually.
I removed the sign out, as data appears not to be written if there is no user logged in.
Do you have a user signed in when the data is written? Creating a user signs him/her in automatically.
Hope it helps!
It appears that just like after adding new permissions in the manifest file, the app has to be reinstalled to register the changes. I tried reinstalling the app after adding the firestore connection and everything worked fine. voila!

Categories

Resources