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);
}
}
}