How to prevent Firestore to create root collection automatically during addDocument? - firebase

In Firestore, I have a collection "form1"
In my client app, when I create a document in a collection that doesn't exist, say "form2"
db.collection("form2").addDocument(data: data)...
I see from Firestore console, "form2" was created automatically to hold the new document. I hope addDocument() would return error in this case.
How to do it with Security rules? or with other method?
Here is my current Secuirty rules:
rules_version = '12';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} { // only logged-in user can access
allow read, write: if request.auth.uid != null;
}
}
}
Why can't following work? (insufficient permission even if the root collection exist)
service cloud.firestore {
match /databases/{database}/documents {
match /{collection} {
allow read, write: if false;
}
match /{collection}/{document} {
allow read, write: if exists(/databases/$(database)/documents/$(collection));
}
}
}

You can disallow writing to all documents as default and then write rules to allow the only ones you decide:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;// This disallow write and read for all documents
}
match /admin_/** {
allow read, write: if request.auth.token.admin == true;
}
}
}
This will not allow writes to any collection or document except to admin

Related

Firebase Firestore Security Rules: Why are these basic rules not allowing access?

I have a fairly simple Firestore with these collections:
households/entries
users
To my understanding, this should allow everyone access to my collections:
service cloud.firestore {
match /databases/{database}/documents {
// match /{document=**} {
// allow read, write;
// }
match /households/{household} {
allow read, write;
match /entries/{entry} {
allow read, write;
}
}
match /users/{user} {
allow read, write;
}
}
}
However, it is not. What am I doing wrong?
(The commented out section would allow me access, but I want to use the others to add conditions more granularly.)

Firestore security rules and vuefire

i have the following sample app here: Github repo
It uses vuefire in ChatList.vue
// vuefire firestore component manages the real-time stream to that reactive data property.
firestore() {
return {
chats: db.collection('chats').where('members', 'array-contains', this.uid)
}
},
I now wrote security rules to secure the data, but can't seem to get the combination of vuefire and security rules to work:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
// THIS IS THE PART I'D LIKE TO REMOVE
match /chats/{chatId=**} {
allow read: if request.auth.uid != null;
}
// THIS WORKS AS INTENDED, AND I'D LIKE TO INCLUDE "READ"
match /chats/{chatId}/{documents=**} {
allow write: if chatRoomPermission(chatId)
}
function chatRoomPermission(chatId) {
return request.auth.uid in get(/databases/$(database)/documents/chats/$(chatId)).data.members;
}
}
}
So the goal is: make the individual chats only readable and writable to users that are in the members array in firestore. (Currently i achieved this partially, since all chats are readable to anyone, but only writable to users in the members array.)
Do i have to rewrite the vuefire component so i can have the following security rule? (It gives an error message: listing of chats not possible due to missing permissions)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /chats/{chatId}/{documents=**} {
allow read, write: if chatRoomPermission(chatId)
}
function chatRoomPermission(chatId) {
return request.auth.uid in get(/databases/$(database)/documents/chats/$(chatId)).data.members;
}
}
}
For completeness, the working solution is (credits to Renaud Tarnec):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /chats/{chatId=**} {
allow read: if request.auth.uid in resource.data.members;
}
match /chats/{chatId}/{documents=**} {
allow read, write: if chatRoomPermission(chatId)
}
function chatRoomPermission(chatId) {
return request.auth.uid in get(/databases/$(database)/documents/chats/$(chatId)).data.members;
}
}
}
Since you want to check, in your Security Rules, if a given value (the user uid in this case) is contained in a field of type Array in your document, you can use the in operator of the List type.
So, the following should do the trick:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
// THIS IS THE PART I'D LIKE TO REMOVE
match /chats/{chatId=**} {
allow read: if request.auth.uid in resource.data.members;
}
// ....
}
}

firebase firestore rules authenticated access to all collections except one

I have the following firestore structure, basically 3 collections
publicdata
protecteddata1
protecteddata2
I want to have protecteddata1 and protecteddata 2, and really the entire firestore database as authenticated users only.
But i want the public to have readonly access to 'publicdata' collection..
The following is my attempt but it doesn't work
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if (request.auth.uid != null);
}
match /publicdata {
allow read;
}
}
}
You can use the following functions I created to do this
function isUserAuthenticated() {
return request.auth.uid != null;
}
You can then use it like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if isUserAuthenticated();
}
match /publicdata/{itemId} {
allow read : if true;
allow create : if isUserAuthenticated();
allow update: if isUserAuthenticated();
allow delete: if isUserAuthenticated();
}
/* Functions */
function isUserAuthenticated() {
return request.auth.uid != null;
}
}
}
As others have explained, if you have multiple matches for the same document they are OR'ed together, so you can't implement an exception with that.
What you can do though is capture the collection name in a variable, and then implement the exception in a single match:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{collection}/{document=**} {
allow read: if collection != 'publicdata';
allow write: if (request.auth.uid != null);
}
}
}
So here we allow reads from all collections except publicdata.
Because here is says:
Overlapping match statements
It's possible for a document to match more than one match statement. In the case where multiple allow
expressions match a request, the access is allowed if any of the
conditions is true: ...
You can use this:
rules_version = '2';
service cloud.firestore {
// Check if the request is authenticated
function isAuthenticated() {
return request.auth != null;
}
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if isAuthenticated();
}
match /publicdata/{document=**} {
allow read: if true;
}
}
}

Different security rules for different Firestore collections

I'm currently using Firestore for the first time and trying to understand the security rules a bit. I now my question is really simple and that I could figure out an answer by doing a bit more research but I wanted to be sure that I am doing the right thing, so I thought it would be better to just ask here.
If I had two collections in Firestore one called "A" and the other "B" what would my security rules have to be if I wanted just authenticated users to read, write, update, delete... in A and everyone to read in B but just authenticated users to write, update, delete... in B.
Edit:
Here are the current rules they apply the rules for B to all collections:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if request.auth.uid != null;
}
}
}
If you look at the documentation on authentication in security rules, you will find these rules:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to access documents in the "cities" collection
// only if they are authenticated.
match /cities/{city} {
allow read, write: if request.auth.uid != null;
}
}
}
Modified for your use-case, that'd be something like:
service cloud.firestore {
match /databases/{database}/documents {
match /A/{id} {
allow read, write: if request.auth.uid != null;
}
match /B/{id} {
allow read;
allow write: if request.auth.uid != null;
}
}
}

How can Firestore check a collection to allow write (rules)

I use a collection called "admin" in Firestore to define which users can write new documents (image below).
At moment, it is controled just by software. I would like to add rules to Firestore. I tried the rule below but it didn't work. What would be the correct rules in that case ?
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow write: if get(/admin/{anyDocument}).data.userId == request.auth.uid;
}
}
}
I'd recommend instead having a users collection with an admin field that can be set to true/false. Then you can do something like:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow write: if get(/users/${request.auth.uid}).data.admin == true;
}
}
}
As far i know this is not possible with your current database structure. Because the push key is not accessible in firestore rules unless it is with in the admin node.
One way is to save the admin with their uid as key like admin/userID/data...
now you can access it
allow write: if get(/databases/$(database)/documents/admin/$(request.auth.uid)).data.userId == request.auth.uid;;

Resources