I know that the answer to this question is: Firebase rules is not a filter system! But I've this case (for a chat app with rooms) and I've a problem with security.
Rooms collection
- ...info about room...
- participants: [id1, id2, id3]
- Messages subcollections
When the user open his rooms view, he should see only the rooms when his id is within "participants" array. I can perform it with a query, and all works fine, but ...
Is there a way to deny the list operation on all collection to avoid that user could see all rooms of all users? I know that I can use a function to restrict the access, but I'm wondering if there are some ways to do it with firestore rules.
My security rules:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents {
function authed() {
return request.auth.token.firebase.sign_in_provider == 'password' && request.auth != null && request.auth.token != null && request.auth.token.email != null;
}
function dataExists() {
return resource != null && resource.data != null;
}
function isConversationVisible() {
return dataExists() && resource.data.visible == true
}
function userInConversation() {
let email = request.auth.token.email;
return dataExists() && email in resource.data.participants;
}
function userInConversationUsingGet(convId) {
let email = request.auth.token.email;
let conv = get(/databases/$(database)/documents/conversations/$(convId));
return email in conv.data.participants;
}
match /conversations/{convId} {
allow create, delete, update: if false;
allow list, get: if authed() && isConversationVisible() && userInConversation();
match /messages/{messageId} {
allow create, read, list: if userInConversationUsingGet(convId);
allow delete, update: if false;
}
}
} }
And my java code to test it:
NOT WORKS
sChatQuery = sChatCollection
.whereArrayContains("participants", "myemail@me.com")
.whereEqualTo("type", type)
.whereEqualTo("visible", true)
.orderBy("timestamp", Query.Direction.DESCENDING);
NOT WORKS
FirebaseFirestore.getInstance()
.collection("conversations")
.get(Source.SERVER)
Both snippets returns PERMISSION_DENIED.
An example of my firestore:
conversations
-- 61a8ec6c99791eb2f7ab5c69
---- participants ["myemail@me.com", "mail1@me.com", "mail2@me.com"]
-- 61a8ec6c99777sjskny77ahw
---- participants ["mail1@me.com", "mail2@me.com"]
-- 61a8ec6c9977718881666618
---- participants ["myemail@me.com"]
UPDATE I suppose that the query fails because "myemail@me.com" is not within all documents (reading official docs). But I'm wondering, how can I deny that a user perform a query passing arbitrary email address? I'm thinking a rule that evaluates the email value passed on whereArrayContains is equal to request.auth.token.email. But I don't found a way to retrieve the parameter passed on query from firestore rules.