Firebase Security + Swift - Not able to read data - swift

Having some issues with reading data. I can write just fine according to my security rules. See below for my query in swiftui code and my security rules. For context, I have a users collection and a routines collection. Each routine document has a uid that is tied to a user. Anyone know why I might not be able to read correctly here (which is affecting my ability to then subsequently write?
Security Rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
match /routines/{routine} {
allow write: if request.auth != null && request.auth.uid == request.resource.data.uid;
allow read: if request.auth != null && resource.data.uid == resource.data.uid;
}
}
}
Swift Query Code
func updateRoutine() {
db.collection("routines").whereField("name", isEqualTo: "temp routine").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
self.db.collection("users").document(self.currUser?.uid ?? "").updateData(["routinePreference": document.documentID])
self.db.collection("routines").document(document.documentID).updateData(["name": "another temp routine"])
return
}
}
}
}
EDIT
This is the error I'm getting:
Error getting documents: Error Domain=FIRFirestoreErrorDomain Code=7
"Missing or insufficient permissions."
UserInfo={NSLocalizedDescription=Missing or insufficient permissions.}
2020-07-03 01:43:24.440221-0400 TestRulesApp[58965:7804974] 6.26.0 -
[Firebase/Firestore][I-FST000001] Listen for query at routines failed:
Missing or insufficient permissions.

You are updating data here.The technique to use is incoming-field-value-equal-existing-field-value. So you should have your update rule allow update:if request.resource.data.uid == resource.data.uid;

Related

Failed to get downloadURL when uploading file in FirebaseStorage

I'm using FirebaseStorage in my Swift project for uploading images in a non public bucket.
Here are my rules:
In GoogleCloud Storage console:
allUser access has been removed
In FirebaseStorage console:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if request.auth != nil
allow write: if true;
}
}
}
With these rules, upload failed when trying to downloadURL:
let uploadTask = fileRef.putFile(from: url, metadata: metadata, completion: { (metadata, error) in
guard let _ = metadata else {
completion(nil,error)
return
}
fileRef.downloadURL { (url, error) in
completion(url,error) // <--- url is nil and error is set
return
}
})
Error is:
▿ Optional<Error>
- some : Error Domain=FIRStorageErrorDomain Code=-13021 "User does not have permission to access gs://utw6xcl26d6ywvtosast/6309669a88262d10cea863e6/35B8D02C-476E-4B6D-A51D-501CC061F047.jpg." UserInfo={ResponseErrorDomain=com.google.HTTPStatus, data={length = 73, bytes = 0x7b0a2020 22657272 6f72223a 207b0a20 ... 2e220a20 207d0a7d }, object=6309669a88262d10cea863e6/35B8D02C-476E-4B6D-A51D-501CC061F047.jpg, NSLocalizedDescription=User does not have permission to access gs://utw6xcl26d6ywvtosast/6309669a88262d10cea863e6/35B8D02C-476E-4B6D-A51D-501CC061F047.jpg., bucket=utw6xcl26d6ywvtosast, data_content_type=application/json; charset=UTF-8, ResponseErrorCode=403, ResponseBody={
"error": {
"code": 403,
"message": "Permission denied."
}
}}
If I change rules in Firebase Storage to read,write: if true this is working but resource is accessible even without access token. Which is not I want.
Do you have an idea?
Thanks!
The user who uploads the file will have to have read access to that file in order to generate a download URL for it. Given your allow read: if request.auth != nil rule, it seems like the user is not authenticated.
You might want to authenticate the user (even if just with anonymous sign-in, which doesn't require them to enter credentials) and then for example to allow them read/write access to files that are written under their own UID.

Firebase Realtime Database rules for specific node of structure

Before creating a new user I want to check if creating username property already exists in Firebase Database.
Checking function is:
let databaseRef = Database.database().reference()
databaseRef.child("users").queryOrdered(byChild: "username").queryEqual(toValue: loginRegisterTextField.text).observeSingleEvent(of: .value, with: { (snapshot: DataSnapshot) in
if snapshot.exists() {
print("Login exists")
} else {
print("Login does not exist")
}
})
JSON is:
Rules are for node users:
{
"rules": {
"users" : {
".read": "auth != null",
"$uid" : {
".write": "auth != null && auth.uid == $uid",
}
},
Is it possible to write a rules to check existing of username without a new uid?
There is no way to check for a specific value across a JSON branch in security rules. This has been covered quite a few times before, so I recommend checking some of these search results.
But you can make your query on /users more secure, by only allowing that specific query, and not allowing people to read all of /users. To secure the query you could some something like:
{
"rules": {
"users" : {
".read": "auth != null &&
query.orderByChild == 'username' &&
query.equalTo !== null",
...
This is the first time I've used query.equalTo !== null, so there may be some small mistakes in that part, but the flow should be clear.

Firebase Cloud Firestore Security Rules for updateData FieldValue.delete() [swift]

I'm removing the map element in the Test field.
Removing the "myID" key from the "Test"
self.db.collection("events").document("bkxREqn24JpdKYBLnBio").updateData([
"Test.myID": FieldValue.delete(),
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
How do I get the key of an item that I remove in the "security rules"?
That's not how it works:
service cloud.firestore {
match /databases/{database}/documents {
match /events/{eventID} {
allow write, update : if request.resource.data.Test.keys()[0] == "myID"
}
}
}
although this rule works for the record
self.db.collection("events").document("bkxREqn24JpdKYBLnBio").updateData([
"Test.myID": "MyText",
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
If I understand correctly, you want to only allow the write if the new document still contains myID value in the Test field, which is an array.
That'd be this in security rules:
allow write, update : if "myID" in request.resource.data.Test;
If you want to check if myID is being added, you'll compare request.resource.data with resource.data. So something like:
allow write, update : if "myID" in request.resource.data.Test
&& !("myID" in resource.data.Test);

Swift: Firestore adding new data gives error

Using Firestore, I'm trying to add a new collection and document. I keep getting "Missing or insufficient permissions". What's the problem? What permission do I still need?
struct FirestoreReferenceManager {
static let db = Firestore.firestore()
static let root = db.collection("dev").document("dev")
}
ViewController
#IBAction func handleRegistration(_ sender: Any) {
FirestoreReferenceManager.root.collection("cities").document("LA").setData(["name": "Los Angeles", "state": "CA"]) { (err) in
if let err = err {
print("Error writing document:", err.localizedDescription)
}
}
}
Try,
go to Database -> Rules -> Change allow read, write: if false to if request.auth != null
or
go to Database -> Rules -> Change allow read, write: if false to if true
It turns off security for the database!
It is not recommended solution for production environment but you can
use for only testing purposes
More you can find here: https://firebase.google.com/docs/firestore/security/rules-conditions
Please perform this step :
1) Open console and open your project
2) Open database -> Cloud Firestore
3) Click on RULES
4) Make allow read, write: if true instead of if false
service cloud.firestore { match /databases/{database}/documents {
match /<some_path>/ {
allow read, write: if true;
} } }
Make allow read, write: if request.auth.uid != null instead of if false
service cloud.firestore { match /databases/{database}/documents {
match /<some_path>/ {
allow read, write: if request.auth.uid != null;
} } }
This will set permission for read and write data on firestore.

Firestore Insufficient Permissions

I keep receiving this error:
Adding Post Error: Missing or insufficient permissions.
These are my current permissions, which lets anyone do anything (which isn't ideal, but I'm just testing).
service cloud.firestore {
match /databases/{database}/documents {
match /Posts {
allow read, write;
}
}
}
And the code I am trying to run is:
func addPost (postID: String, date: NSDate, link: String, profileID: String, text: String) {
let db = Firestore.firestore()
let settings = db.settings
settings.areTimestampsInSnapshotsEnabled = true
db.settings = settings
db.collection("Posts").document(postID).setData(["Date": date, "Link": link, "ProfileID": profileID, "Text": text]) { (error) in
if (error != nil) {
print ("Adding Post Error: " + error!.localizedDescription)
} else {
print("Post added sucessfully")
}
}
}
Why am I getting this error message? I am running the latest version of FirebaseFirestore as of June 27, 2018.
I'm pretty sure you need to specify that the user is allowed to access documents in the collection as shown in the documentation on basic read/write rules:
service cloud.firestore {
match /databases/{database}/documents {
match /Posts/{post} {
allow read, write;
}
}
}
Difference above is the {post} in match /Posts/{post}.