Permission Denied Error in Android Emulator when Enforcing App Check for Flutter App - flutter

After spending hours for getting App Check working on the physical devices (iOS and Android) of my Flutter app i also tried the provided documentation steps in order to get it working for Android emulator as well.
Whatever i try i always get the following error for all my listening streams that are invoked against the Firestore database when App Check is enforced:
W/Firestore( 5612): (24.1.2) [Firestore]: Listen for Query(target=Query(Contract where isArchive==false and contractorId==myContractorId order by __name__);limitType=LIMIT_TO_FIRST) failed: Status{code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null}
I've added the depencency in app/build.gradle:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.google.firebase:firebase-appcheck-debug:16.0.0'
}
and have overridden onCreate in MainActivity.kt:
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
if (BuildConfig.DEBUG) {
//Log.d("MainActivity", "debug mode entered")
FirebaseApp.initializeApp( /*context=*/this)
val firebaseAppCheck: FirebaseAppCheck = FirebaseAppCheck.getInstance()
firebaseAppCheck.installAppCheckProviderFactory(DebugAppCheckProviderFactory.getInstance())
} else {
//Log.d("MainActivity", "else mode entered")
}
super.onCreate(savedInstanceState)
}
}
The resulting debug token was added successfully to the list of debug tokens in Firebase console.
All Firestore collection rules look like the following example rule:
match /Contractor/{contractor} {
allow read, write: if request.auth.uid != null;
}
Activating App Check in the Flutter main function looks like this:
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await FirebaseAppCheck.instance.activate();
Without enforced App Check i don't have any problems running the Flutter app on my Android emulator.
All Firebase plugins are the most recent ones.
What else can i try or change in order to get this working?
If it doesn't work also on Android emulators we will give up using App Check.

Have you added this in cloud function:
if (context.app == undefined && !process.env.FUNCTIONS_EMULATOR) {
throw new functions.https.HttpsError(
"failed-precondition",
"The function must be called from an App-Check verified app.");
}
You need to add this code:
!process.env.FUNCTIONS_EMULATOR

Related

Firestore rules aren't working for users following official documentation

So I am running my Flutter app locally with emulators. The firestore rules are copied from the docs:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
After I signup the user successfully I try to create his doc like this:
UserCredential userCredential = await auth
.createUserWithEmailAndPassword(email: data.name!, password: data.password!);
await auth.currentUser!.sendEmailVerification();
DocumentReference ref = FirebaseFirestore.instance.collection("users").doc(FirebaseAuth.instance.currentUser!.uid);
await ref.set({"isOwner":false},SetOptions(merge: true));
This results in the error:
W/Firestore(17604): (24.4.0) [Firestore]: Write failed at
users/JknXHMkWb0jL4ohiW18K9h6NLyyB: Status{code=PERMISSION_DENIED,
description=Missing or insufficient permissions., cause=null}
Does it need time to get the uid? I can't think of anything else
if (Foundation.kDebugMode) {
FirebaseFirestore.instance.clearPersistence();
FirebaseFirestore.instance.useFirestoreEmulator("10.0.2.2", 8080);
}
Found this on some google group. Moving the clearPersistence line below the firestore emulator made it work. This is really non-standard behavior.
Look out as well into the debugging output of your app : the Firebase Firestore SDK outputs a debug token for you to whitelist your test device on Firebase > AppCheck > Apps.
From there, look for the 3-dots menu of the platform you're debugging onto, click it, and select "Manage debug tokens" : add the token here.
From my observations, this debug token doesn't live forever. If experience again permissions issues, try re-adding the token which you get in the debug output.

FDL logging failed. Add a dependency for Firebase Analytics to your app to enable logging of Dynamic Link events

I have created a dynamic link for the Flutter app using the Firebase console and I am trying to access that dynamic link data from within the app. But I am getting this message in the logs.
The app is not using any authentication.
I am using this method for the same:
Future<void> initDynamicLink() async {
dynamicLinks.onLink.listen((dynamicLinkData) {
final Uri uri = dynamicLinkData.link;
final queryParams = uri.queryParameters;
if (queryParams.isNotEmpty) {
String? productId = queryParams['id'];
Navigator.pushNamed(context, dynamicLinkData.link.path,
arguments: {"productId": int.parse(productId!)});
} else {
Navigator.pushNamed(context, dynamicLinkData.link.path);
}
}).onError((error) {
if (kDebugMode) {
print(error);
}
});
}
P.S.: I am able to create new short and long dynamic links from the app.
This warning will show up if you haven't setup the Firebase Analytics SDK on your app. Make sure you have configured it properly on your app.
To add the Analytics SDK:
From the root of your Flutter project, run the following command to install the plugin:
Once complete, rebuild your Flutter application:
Once installed, you can access the firebase_analytics plugin by importing it in your Dart code:
Create a new Firebase Analytics instance by calling the instance getter on FirebaseAnalytics:
You could check this guide for your reference.

Flutter: converting project to web

I have a flutter project currently working well on Android and Ios. I am currently trying to get it working on the web, and while the frontend seems to be fine, im noticing issues with my streams. For instance, when initially loading the app as an authenticated user, a stream of special users called Stingrays is loaded. This works fine on mobile, however in web i get hung up on the following:
error:
Failed to evaluate expression 'stingrays': InternalError: No frame with index 84.
bloc code:
void _onLoadStingray(
LoadStingray event,
Emitter<StingrayState> emit,
) {
_firestoreRepository.stingrays.listen((stingrays) {
add(
UpdateStingray(stingrays: stingrays),
);
});
}
Stream:
Stream<List<Stingray?>> get stingrays {
return FirebaseFirestore.instance
.collection('stingrays')
.snapshots()
.map<List<Stingray?>>(_stingrayListFromSnapshot);
}
Its also not loading any image in the app, saying:
ImageCodecException: Failed to load network image.
Any idea whats going on with all this?

Flutter - Local_auth (Required security features not enabled)

I'm trying to get biometrics authentication to work again after updating the app I'm developing.
But I'm constantly getting the same error when activating it:
PlatformException(NotAvailable, Required security features not enabled, null, null)
The current one in the store has no problems at all.
I'm using local_auth: 1.1.4
MainActivity.java has been converted to a FragmentedActivity
I'm doing a simple check to see if the biometrics are available. Which they are
bool canCheckBiometrics = await auth.canCheckBiometrics;
List<BiometricType> availableBiometrics =
await auth.getAvailableBiometrics();
print(canCheckBiometrics); //Returns true
print(availableBiometrics.toString()); //Returns [BiometricType.fingerprint]
After that I try to do the authentication
try {
authenticated = await auth.authenticate(
biometricOnly: true,
localizedReason: 'Login with biometrics',
useErrorDialogs: true,
stickyAuth: false);
} on PlatformException catch (e) {
print(e);
}
This returns:
PlatformException(NotAvailable, Required security features not enabled, null, null)
And this is what the plugin comments in the code say.
// Indicates the device does not have a Touch ID/fingerprint scanner.
const String notAvailable = 'NotAvailable';
I'm not really sure what to check anymore. Is this something new I need to be aware of?
Really hope someone can help me with this issue!
Hope to hear!
I recommend that you verify all capabilities before of try authenticate the user.
Future<bool> authenticateIsAvailable() async {
final isAvailable = await localAuth.canCheckBiometrics;
final isDeviceSupported = await localAuth.isDeviceSupported();
return isAvailable && isDeviceSupported;
}
This way, you can call localAuth.authenticate only for phones that have credentials enrolled and probably don't have exceptions. Even though, catch the error if possible.
First of all, you need to add a biometric authentication method to your device from settings.
For example if you are using Pixel 2 API 32 as Android Emulator,
Go to Settings inside android emulator.
Go into Security
Under the Device Security section, select Pixel Imprint
Android will ask you to put your finger on the sensor, in this part you should click the Touch Sensor button from the Extended Emulator Settings of Android Studio.
After turning on fingerprint verification in this way, when you return to the application and try again, you will see that the error is gone.
Similarly, if you are trying with a real device or another emulator, you need to enable fingerprint authentication and try again.
I think you don't have a fingerprint activated yet, or you don't have permissions to use it, check the permissions and try again.
Check this out:
https://support.dashlane.com/hc/en-us/articles/203682911-How-to-set-biometric-authentication-or-a-PIN-code-to-unlock-Dashlane-on-Android
Go to settings -> security -> fingerprint and add fingerprint lock.
If you are using Android studio emulator then keep in mind that Android Studio emulator provides fake fingerprint scanning.
I had the same issue and after debugging I discovered that keyguardManager was always null and causing the plugin to throw not enable exception. I had to change the below method in LocalAuthPlugin as follows:
private boolean isDeviceSupported()
{
if (keyguardManager == null) return false;
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
keyguardManager.isDeviceSecure());
}
to
private boolean isDeviceSupported()
{
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
}
It worked for me, hopefully will work for you and others.

Flutter check GPS status continuously

I'm working on an application that requires the user location continuously. If the user disables GPS, I want to show an error screen. How do I do it using a provider maybe?
You can use permission_handler plugin. You can do the task which requires location permission inside if block and shows the error message if the permission is revoked.
if (await Permission.locationWhenInUse.serviceStatus.isEnabled) {
// Use location.
} else {
// show error
}
You can also check this answer which can help you to listen to the permission change.