I have a Collection of Player Documents in firestore. I want to mark some of those Documents as private, so that they can't be queried against. A JSON dump of my data looks like this:
[
{
"id": "H0ycPIqXB5pX5VmdYlmY",
"name": "Tim",
},
{
"id": "VICMGdutgIN7PUjG571h",
"name": "Zoe",
},
{
"id": "query-blocker",
"name": "Don't look here",
"private": true
},
{
"id": "zYkhO5f7gYPe2VgqQQXe",
"name": "Bob"
}
]
Now apply this security rule, intended to protect any document with a field labelled private
:
match /players/{document=**} {
allow read: if !('private' in resource.data);
}
Results:
- A query to read a single document that contains a field
private
, correctly returns a permission denied error. - A query to read all the documents in the collection successfully returns all documents in the collection, including all of the ones marked
private
.
It seems like the query for all documents should also fail (I understand that security rules are not filters). Is there something I am misunderstanding here?
Here is a working example of the issue using the emulator: https://github.com/Keltin42/firebase-it-rulestest
Here is a simplified example you can run from the command line:
'use strict';
const firebase = require('firebase');
require('firebase/firestore');
firebase.initializeApp({
apiKey: 'your api key here',
projectId: 'your project id here'
});
const db = firebase.firestore();
async function doTest() {
const playersCollection = db.collection('players');
await playersCollection.add({ name: 'Sue' });
await playersCollection.add({ name: 'Bob' });
await playersCollection.doc('good').set({ name: 'Fred' });
await playersCollection.doc('query-blocker').set({ name: 'Tim', private: true });
// Read a good document.
await playersCollection.doc('good').get().then(doc => {
console.log('The good document: ', JSON.stringify(doc.data()));
});
// Read all the documents
await playersCollection.get().then(querySnapshot => {
console.log('All documents: ');
querySnapshot.forEach(doc => {
console.log('\t', doc.id, ' => ', doc.data());
});
});
// Read the query-block document
await playersCollection.doc('query-blocker').get().then(doc => {
console.log('The query-blocker document: ', JSON.stringify(doc.data()));
}).catch(error => {
console.error('Error retrieving query-blocker document: ', error);
});
}
doTest();
with the security rules:
service cloud.firestore {
match /databases/{database}/documents {
match /players/{document=**} {
allow write;
allow read: if !('private' in resource.data);
}
}
}