How to access my data field in Firebase Security Rules - javascript

Security Rules
I am trying to grant permission based at a document field:
match /users/{user}/{documents=**} {
allow read, write: if resource.data.uid == request.auth.uid
}
Firebase query
Here is how my query looks:
query(collection(db, "users", match.params.uid, "promotors"));
Error message
But I keep geting this message:
FirebaseError: Missing or insufficient permissions.

Your query is not in any way checking the data in a field in the documents, so it will never meet this part of your rules: resource.data.uid.
Instead what you seem to have is a case where the document ID matches the UID of the user, which you can check with:
match /users/{user}/{documents=**} {
allow read, write: if user == request.auth.uid
}
Also see the documentation on content owner only access.

Related

Why do I get an insufficient permissions error while trying to delete an array element from firestore, yet I can delete the entire document

I have a collection in my firestore named "reports"
one of the fields in the reports map is an array of objects. These objects reference a photo in cloud storage. They look like this (url points to cloud storage):
{
id: uid value
url: some-url
}
my firebase rules are set up like this for the reports document:
match /databases/{database}/documents {
match /reports/{report} {
allow read: if request.auth != null && request.auth.uid == resource.data.userID;
allow create: if request.auth != null && request.resource.data.userID == request.auth.uid;
allow delete, update: if request.auth != null &&
request.auth.uid == resource.data.userID;
}
}
for some reason, I can delete the entire document if I want to proving that I have delete permission.....but when I attempt to delete an item from the photos array like this:
const reportRef = db.collection('reports')
reportRef.doc(activeReport.id).update({
photos: firebase.firestore.FieldValue.arrayRemove(photoToDelete)
})
I end up with an error stating:
Unhandled promise rejection: FirebaseError: Missing or insufficient permissions
Why? Haven't I given permission to update this document properly?
Go in Database ->
Rules ->
For development:
Change allow read, write: if false; to true;
Note: It's a quick solution for development purposes only because it will turn off all the security. So, it's not recommended for production.
For production:
If authenticated from firebase: Change allow read, write: if false; to request.auth != null;
In this case it was a bad parameter that was passed in. I needed to pass activeReport not activeReport.id.
This is a misleading error message. I would delete this question but stackoverflow doesn't want me to because an answer has been posted here. Silly.

Firestore rules not allowing read given valid UID

I have written the following firestore rule to limit reads on the users collection by only allowing the request if the caller's UID matches the document ID. There is parity between the users collections' document ID and the UID in Firebase Authentication.
function isAuthenticated() {
return request.auth.uid != null;
}
// Users collection
match /users/{userId} {
allow read: if isAuthenticated()
&& request.auth.uid == userId;
}
I have a document in the collection with ID Eli90wRvWkfKcOfn1C4DBDqxQTz1. When hitting firestore with the same authentication user, I get the following error:
If I remove the check for the request.auth.uid == userId, it results in this rule and a successful read:
// Users collection
match /users/{userId} {
allow read: if isAuthenticated();
}
The query that is being called is:
export const getUser = (uid: string) => {
return db.collection('users').where('id', '==', uid).limit(1).get();
};
I've seen many people use the UID check in their rules but why isn't it working in my case?
Your security rules match this code:
db.collection('users').doc(uid).get();
So here we access a single specific documents, with the document ID being the UID of the user.
If you instead want to query for the UID in a field in the document(s), you can secure that with these rules:
match /users/{doc} {
allow read: if resource.data.id === request.auth.uid;
}
So now the rules match your original code, and only allow reading documents where the value of the uid field matches the uid of the current user.

Can a user update the script in a console and access other users' data in my firebase code?

For context, I display my Firebase app's configuration in the app.js file (is this safe?) and in order to give a user their data I list the following code:
db.collection('whispers').where("sender", "array-contains",
userID).orderBy('time').onSnapshot(snapshot => {
let changes = snapshot.docChanges();
changes.forEach(change => {
renderSay(change.doc);
});
});
Could a user remove the 'where' condition and access all data in this collection? I only use anonymous sign in so nothing special required in accessing their own data besides using the same device and not clearing data.
I doubt that could be possible by reverse-engineering but the actual security lies in the security rules.
You can change them from the Firebase Console
Here is a video from Firebase and here is the documentation
service cloud.firestore {
match /databases/{database}/documents {
// Match any document in the 'users' collection
match /users/{userID} {
allow read: if request.auth.uid === userID;
allow write: if request.auth.uid === userID;
}
}
}
Using the above security rules will allow users to read and write their data ONLY.
So even if they reverse-engineer your code, it will harm their data only and other data will be safe.
For more details please check the links above and you will get familiar with wildcard [{userID} in this case]
PS: Only you or anyone with access to your Firebase Console can change the rules
EDIT: This Medium Article has many types of rules explained. Please have a read there too :D

firestore rules matching parent data, only work in simulator

I'm trying to make a simple direct message part. I have a document with some meta informations and a subcollection with the single messages.
When I try to get the messages the rules are valid in the simulator, but in js I get everytime: Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
The mongodb structure:
chatRooms
roomId
metaInformation (senderId/Name, recieverId/Name, timestamp, etc.)
messages
messageId
name
text
timestamp
The rules:
match /chatRooms/{chatRoom} {
allow create: if request.auth.uid != null;
allow update, delete: if resource.data.uid == request.auth.uid;
function isChatPartner() {
return parentDoc().receiverId == request.auth.uid || parentDoc().senderId == request.auth.uid;
}
function parentDoc() {
return get(/databases/$(database)/documents/chatRooms/$(chatroom)).data;
}
match /messages/{message} {
allow read: if isChatPartner();
}
}
The js-request:
db.collection("chatRoom").doc(_roomId).collection("messages").get().then(msg => {
console.log(msg);
})
Has anyone an idea what maybe could be wrong?
Your database and rules don't match. In the rule, the top level collection is called "chatRooms", but in your code, it's called "chatRoom". The collection names need to match exactly.
There's another problem. Your code is trying to get all of the documents in the subcollection, but the rules don't allow that. The rules are checking certain fields for access. This won't work in security rules, since rules are not filters (be sure to read and understand those docs). The query must only request documents that will definitely pass the rules - the rules will not check each document and exclude the ones that don't match.

firestore security rule resource.data is empty object

In firestore security rule, the resource.data is an emtpy object always, is this a bug or something ?
My firestore rules:
service cloud.firestore {
match /databases/{database}/documents {
match /hospitals/{document=**}{
// allow read :if resource.data.size() == 0; //this return true, resource.data is an empty object
allow read :if resource.data.name != null; // this doesn't work
}
}
}
My javascript:
auth().onAuthStateChanged((user) => {
if (user) {
//db is the firestore instance
db.collection('/hospitals').get()
.then(printResult)
} else {
}
})
this is my current database snapshot
solved :
thanks for Frank's answer
the issue rely on that firestore security doesn't evaluate the actual document value when we query a over multiple document , in my case
//this doesn't firestore doesnt' evaluate the documetn
db.collection('hospitals').get()
//this will work ,if you need to compare the actual value
db.document('hospitals/somehospital').get()
Security rules don't filter data by themselves. They merely enforce rules on what data a client can read. Your client is currently trying to read all hospitals. Since your security rules have restrictions on what data a client can read, they reject this operation.
You need to ensure that what your client requests is no more than what the security rules allow, by reading the data through a query that matches the security rules. So something like
db.collection('/hospitals')
.where("name", ">=", "")
.get()
.then(printResult)
Note that this does require that the document has a name field, otherwise the name can't be empty.
For more info, see:
the Firestore documentation on securing queries
Firestore select where is not null

Categories