Geofire setLocation failed DatabaseError: Permission denied - flutter

I am trying to set the location of a user by using GeoFire's setLocation but I am getting a permission denied error.
String uid = (Provider.of<UserData>(context, listen: false).uid);
print(uid);
bool? response = await Geofire.setLocation(uid, location.latitude ?? 0.0, location.longitude ?? 0.0);
print(response);
Here is the output:
I/flutter (23479): z9jbb4W9gvbfkOt9mnPhsJBNxSX2
I/TAG (23479): setLocation
W/RepoOperation(23479): setValue at /users/z9jbb4W9gvbfkOt9mnPhsJBNxSX2 failed: DatabaseError: Permission denied
I/flutter (23479): false
Here are my gradle files:
android/build.gradle
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:multidex:1.0.3'
implementation 'com.google.firebase:firebase-core:16.0.0'
implementation 'com.google.firebase:firebase-auth:16.0.1'
implementation 'com.google.firebase:firebase-database:12.0.1'
implementation 'com.google.firebase:firebase-storage:12.0.1'
implementation 'com.google.firebase:firebase-appcheck:16.0.0'
implementation 'com.firebase:geofire-android:2.3.1'
}
app/build.gradle
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.0.1'
}
and here are my database rules on firestore:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
match /users/{userId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
I have tried setting the rules to True for everything and still get the same error.

Related

Getting Unhandled Exception: [cloud_firestore/permission-denied]. I have checked everything was fine in firebase

Hello Guys I had created the flutter application in which when a user pressed signup button then they will be checked that provided email exists in the firestore database or not if no then they will be move to next screen. I am getting this [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation. exception even everything looks fine in my code and firestore configuration
Here is my firestore database rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
Here is my project level build.gradle:
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.13'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Here is my app-level build.gradle
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.recipedia.fyp.recipedia"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation platform('com.google.firebase:firebase-bom:31.0.3')
}
Here is my signup code:
onPressed: () async {
if (nameTextController.text.isEmpty) {
displayToastMessage(
"Please enter name", context);
} else if (nameTextController.text.length < 3) {
displayToastMessage("Name must be atleast 3 characters", context);
} else if (nameTextController.text.contains(RegExp(r'[0-9]'))) {
displayToastMessage("Numbers and special characters cannot be included", context);
} else if (emailTextController.text.isEmpty) {
displayToastMessage("Please enter email", context);
} else if (!emailTextController.text.contains('#')) {
displayToastMessage("Please enter a valid email", context);
} else if (passwordTextController.text.isEmpty) {
displayToastMessage("Please enter password", context);
} else if (passwordTextController.text.length < 6) {
displayToastMessage("Password must be at-least 6 Characters", context);
} else {
print('Before emailExists');
emailExists = await UserModel().checkIfEmailExists(email);
print('Email exist: $emailExists');
if (emailExists == true) {
snackBar(context, 'Email is already registered');
} else {
/*Move to next screen*/
}
}
}
User Model class checkIfEmailExist function
Future<bool> checkIfEmailExists(String email) async {
try {
var collectionReference = FirebaseFirestore.instance.collection('users');
var doc = await collectionReference.doc(email).get();
return doc.exists;
} catch (e) {
rethrow;
}
}
Solution: In Firestore database rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}

Allow access to customer data if user is part of privileged collection

The database structure is like so:
suppliers(collection)>user_email(document)
customers(collection)>user_email(document)>foo(field)
And the current firestore.rules is like so:
match /databases/{database}/documents {
//Base rule - fully restrictive
match /{document=**} {
allow read, write: if false;
}
//Checks if user is registered in the suppliers section
function isSupplierTeam(request) {
return exists(/suppliers/$(request.auth.token.email));
}
// Supplier self-data access
match /suppliers/{email} {
allow read, write: if request.auth.token.email == email;
}
match /suppliers/{email}/{document=**} {
allow read, write: if request.auth.token.email == email;
}
// Checking the Customer Sub-Section
match /customers/{email} {
allow read, write: if request.auth.token.email == email || isSupplierTeam(request);
}
match /customers/{email}/{document=**} {
allow read, write: if request.auth.token.email == email || isSupplierTeam(request);
}
}
And the query run in javascript, when logged in as a "supplier" is:
db.collection("customers").get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id);
console.log(doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
It doesn't seem to work and instead triggers a missing/insufficient permission error. How should I tweak my firestore.rules to allow suppliers to access the customer data?
So this works:
//Checks if user is registered in the suppliers section
function isSupplierTeam(request) {
return exists(/databases/$(database)/documents/suppliers/$(request.auth.token.email));
}
It seems like the full "URL" is needed to access the relevant firestore document.

Firestore Rules: Only show documents if document field is false

I have a NSFW system where it checks the document if it is NSFW and if it is it updates the document field isNSFW to true. That works just fine but now I wanted to not show those documents to all users via settings a rule instead of querying it out.
This is what I have but it's not working...
javascript
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
match /users/{user} {
allow read: if true;
}
match /docs/{doc} { // THIS HERE
allow read: if resource.data.isNSFW == false;
}
}
I tried adding request. before the resource and it still didn't work.
UPDATE:
javascript
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match /{document=**} {
// allow read, write: if request.auth.uid != null;
// }
match /users/{user} {
allow read: if currentUser().uid != null;
}
match /docs {
allow read: if existingData().users[currentUser().uid] == false;
}
match /docs/{doc} {
allow write: if currentUser().uid != null;
}
}
// MARK - Funcs ---------------
function existingData() {
return resource.data
}
function incomingData() {
return request.resource.data
}
function currentUser() {
return request.auth
}
function isSignedIn() {
return request.auth != null;
}
}
Getting error:
Listen for Query(docs where users.`40S88coPQObEWSeiYMZIJlIKJkI2` == false order by __name__) failed: Status{code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null}
If you are using Firebase Datastore, you can simply query 1
your data:
var myDB = db.collection("YOUR-DB-COLLECTION");
var query = myDB.where("isNSFW", "==", false);
If you are using GCP datastore, you do it this other way 2:
const query = datastore
.createQuery('YOUR-COLLECTION')
.filter('isNSFW', '=', false);
Your matches are not nested correctly. They should be inside the block that starts with match /databases/{database}/documents. Also, you should strongly consider removing the match on /{document=**} because that will let everyone read any document in the database if they're logged in, ignoring all other rules.

Firebase Authentication creates user but does not add their Info to database

I am new to using firebase and ios development in general. I am having an issue with adding user's info to the firestore database even though they are being added as authenticated users. Any Suggestions?
Auth.auth().createUser(withEmail: email, password: password) { (result, err) in
if err != nil {
self.errorLabel.text = "Error Creating User"
self.errorLabel.alpha = 1
} else {
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstname":firstname, "lastname":lastname, "uid":result!.user.uid]) { (error) in
if error != nil {
self.errorLabel.text = "error saving user data"
self.errorLabel.alpha = 1
}
}
self.transitionScreens()
}
}
}
}
Change your code to the following:
// Add a new document with a generated ID
var ref: DocumentReference? = nil
ref = db.collection("users").addDocument(data: [
"firstname": firstname,
"lastname": lastname,
"uid": result!.user.uid
]) { err in
if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: \(ref!.documentID)")
}
}
Using this print statement print("Error adding document: \(err)") you can know exactly what the error is.
Also change your security rules to the following:
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Check out the following different rules you can give access to users depending on the data
service cloud.firestore {
match /databases/{database}/documents {
//allows all users to read and write, but dangerous as any one can flood your database
match /public_collection/{document=**} {
allow read, write: if true;
}
//only read access
match /public_read_collection/{document=**} {
allow read: if true;
allow write: if false;
}
//prefered for storing users personal info, users can access only their data
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
//any authenticated user can access or write data
match /posts/{documentId} {
allow read, write: if request.auth.uid != null;
}
}
}

Firebase Geofire permission denied

I'm using Firebase Geofire to get user locations to store them in my database. I get an error when I try to run a query:
Listener at /RDio5CZF2fcJTUOcaeNJhuvYP2Q2 failed: permission_denied
2017-09-19 22:34:24.809 HeartQuest[26419] <Warning> [Firebase/Database][I-RDB038012] Listener at /RDio5CZF2fcJTUOcaeNJhuvYP2Q2 failed: permission_denied
An error occurred getting the location for "firebase-hq": Optional("Permission Denied")
The errors occur after running the following query:
let userID = User.current?.key
let geofireRef = Database.database().reference()
let geoFire = GeoFire(firebaseRef: geofireRef)
geoFire?.getLocationForKey(userID!, withCallback: { (location, error) in
if (error != nil) {
print("An error occurred getting the location for \"firebase-hq\": \(error?.localizedDescription)")
} else if (location != nil) {
print("Location for \"firebase-hq\" is [\(location?.coordinate.latitude), \(location?.coordinate.longitude)]")
} else {
print("GeoFire does not contain a location for \"firebase-hq\"")
}
})
}
Can anyone please explain what the location key is and why I might not have permission for it? I'm using CLLocationManager to request the user's permission for their phone's location.
EDIT: Firebase rules
{
"rules": {
".validate": "auth != null",
".write": "auth != null",
"users" : {
".read": "auth != null",
".indexOn" : ["email","username"],
"$userId": {
".write": "data.val() == null || (newData.val() == null && $userId === auth.uid)"
}
}
}
}