two read rules and second rule does a field check - firebase

I currently have a rule setup for firebase. Which works for reads when a member is already part of the subcollection.
match /clans/{clanName} {
allow create;
allow read: if exists(/databases/$(database)/documents/clans/$(clanName)/members/$(request.auth.uid));
match /members/{uid} {
allow create;
allow read,write,delete: if uid == request.auth.uid;
}
}
Now i am trying to use a random key generated that is stored on the clan profile to allow reads also.
I am trying by getting the clan document and checking the key then adding if it matches. I would like to just do a request and the rule validate the docid and key are right.

Related

Is it possible to prevent send custom id by rules in firebase

Is there any way to prevent user send custom id for newly created document?
For example
This operation create's new document with id "8pqLuAc6BXCVRF7SB6xT"
db.collection("users").add({foo : 1})
And in my application i always want to have id generate by firebase sdk not by user
because as we know user can hack app and trigger operation like this
db.collection("users").doc('CUSTOM_ID').set({foo : 1})
After this operation id will be "CUSTOM_ID" instead generated by SDK like '8pqLuAc6BXCVRF7SB6xT'
So question is how to write rule to ensure me that id is generated from sdk
Update following your clarification:
It is not possible with Security Rules to avoid a user specifying the ID of a document when it is created.
Even if the code in your front end only uses the add() method, one can write his own code and use the doc() method to write to your DB (as soon as he gets the Firebase configuration object, which is easy).
One possibility would be to write to Firestore via a Cloud Function, but this has some drawbacks see this article.
Original answer:
It is not crystal clear what you mean by a "custom id" but I understand that you probably want a given user to be able to create a document in the users collection only if this document ID is corresponding to his user uid (from the Auth service)
The following Security Rule should the trick:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow create: if request.auth != null && request.auth.uid == userId;
// ...
}
}
}

Firestore rules allow specific document but not collection

I need to allow a user to read a specific document /customers/cumstomerkey but not to get the whole collection. How can I achieve that? Following rule allows access to get the whole collection:
match /customers/{document=**} {
allow read, write: if true;
}
You will want to read about granular operations in security rules. If you have a single document that should be gettable, just call out the path and allow get access on just that:
match /customers/cumstomerkey {
allow get;
}

Set createdBy field in document with current userId (auth.uid)

I know that Firebase has the FieldValue class, which can be used to generate e.g. a server-side timestamp when writing a document (link).
What's the preferred practice for inserting the current user's uid into a document?
Having the client provide that field seems to allow misuse - unless I provide a server rule that checks for (new/updated) documents to match the request.auth.uid, something like:
service cloud.firestore {
match /databases/{database}/documents {
match /broadcasts/{broadcast}/chatMessagesCollection/{message} {
allow write: if request.resource.data.uid == request.auth.uid;
allow read: if true;
}
}
}
I can't find anything on the web for the use-case of having a document be populated with the user writing it -- so what's the best take on this?
What you're doing now with security rules to enforce that the provided UID matches the current user is exactly the right thing to do. There is really nothing better (for this specific use case), and this is a common practice.
I've even written about it in this blog series: https://medium.com/firebase-developers/patterns-for-security-with-firebase-per-user-permissions-for-cloud-firestore-be67ee8edc4a

Firestore - disallow reading multiple documents at once

I've got a Firestore collection.
The IDs of the documents are secrets. You should be able to read only the document whose ID you know.
For the sake of simplicity. I'd like to stick to this approach.
However, by default, one can read an entire collection from Firestore, for example
await firestore.collection("secret_documents").get()
Is it possible to allow reading only one document at once, only when it's referred by its ID?
Yes, that is actually quite easy. To control what documents can be accessed, use Firebase security rules for Firestore.
By default your security rules will be read and write, but those can actually be broken down into more granular operations of get, list, create and update. And what you're trying to do is to allow get, but not a list operation. From the documentation:
service cloud.firestore {
match /databases/{database}/documents {
// A read rule can be divided into get and list rules
match /cities/{city} {
// Applies to single document read requests
allow get: if <condition>;
// Applies to queries and collection read requests
allow list: if <condition>;
}
...
So to allow get for everyone and disallow list calls:
allow get: if true;
allow list: if false;
You'll probably want to elaborate on the allow get rule a bit, because it's more common to restrict it, for example to users that are signed in to your project with Firebase Authentication:
allow get: if request.auth.uid != null;
https://firebase.google.com/docs/firestore/security/rules-query

Do I need to do a get for every field of a document I want to access

I see that to get a field of a document in security rules one must use get. The example below shows getting the 'admin' field of some document in the users collection. If I wanted to get another field, would I have to do another get request or can I just do one get request and get all the fields I need in the document.
Here is the example I'm referring to in the documentation.
https://firebase.google.com/docs/firestore/security/rules-conditions
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
// Make sure a 'users' document exists for the requesting user before
// allowing any writes to the 'cities' collection
allow create: if exists(/databases/$(database)/documents/users/$(request.auth.uid))
// Allow the user to delete cities if their user document has the
// 'admin' field set to 'true'
allow delete: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
}
}
}
Yes, you would have to write another get(). There are no variables in Firestore security rules, so you can't store the contents of a get() in order to use its data multiple times.
Multiple gets accessing the same document might not incur multiple read charges. The documentation states:
Some document access calls may be cached, and cached calls do not count towards the limits.

Resources