I am wondering if the following will cover all cases where there was no resource at the request's path before:
allow write: if resource == null;
This should only allow files to be created but not updated.
Yes - that is all you need to prevent editing/overwriting files. Note that it will also prevent any deletions, if you want to allow deletions you'd need to add in a condition something like:
allow write: if (resource == null || request.resource == null);
I'm sure you've already found the official docs (subsection Resource Evaluation) on this stuff... but I'll include a link here to an answer by Google's own Frank van Puffelen that acts as a good reference.
Related
At the moment i try to build a chat in flutter with google firebase.
Now i would like my database more secure.
That means only users (room_3) in chat can read and write data data.
Is it possible to check a path contains a user value
and if the user value is contains allow read a other path?
Here my database structer:
/chat/product_id/product_id_12345/chat_room_id/room_1/message_1/message2...
My idea is i add in 'room_1' the user id.
Then i check the user is contains in 'room_1'.
If the user is contains i allow read and write data the complete path (message_1/message_2...).
Here my example:
If you have any questions fell free to ask me.
Many thx.
In the security rules for the messages subcollection you can read the parent document and check whether the current user is in the user_id field with:
...
match /messages/{message} {
allow read:
if request.auth != null &&
request.auth.uid in
get(/databases/$(database)/documents/chat_room/$(chat_room_id)).data.user_id
}
I'm basically trying to use a firestore collection as a an email list. Anyone can create a document that has their email as the id and nothing more. The tricky part is the "and nothing more" bit. When no data is provided in the request, request.resource is undefined which you can't check for in security rules to my knowledge. Is this possible? Or is it necessary to have something like one mandatory field for this use case?
Having empty documents regularly leads to issues down the line. Why not require a single marker field, and validate that in rules?
request.resource.data.keys.hasOnly("marker")
For the benefit of others looking to make an email list in firestore, this is the full rule I ended up using:
match /email-list/{email} {
allow get: if true;
allow list: if false;
allow create: if request.resource.data.keys().hasOnly(["marker"])
&& request.resource.data.marker == true
}
Error [firebase.firestore] FirebaseError: Missing or insufficient permissions.
I have an object that a few users are allowed to update. An admin will set their email, and these users who sign in with those email will be allowed to update.
These are the rules that I have tried:
allow update: if request.resource.data.managerEmails.val().contains(request.auth.email) && request.resource.data.id == resource.data.id;
allow update: if request.resource.data.managerEmails.contains(request.auth.email) && request.resource.data.id == resource.data.id;
allow update: if request.resource.data.managerEmails.includes(request.auth.email) && request.resource.data.id == resource.data.id;
The resource to update:
{
id: "someid",
...fields,
managerEmails: "abcde#email.com,anothermanager#email.com",
}
User auth who is updating:
{
uid: "rSTLnYD9aisyZJHQPC6sg7mlsZh1",
email: "abcde#email.com",
...
}
Update:
Using request.auth.uid has been working in other rules, but in this case, I have to use emails because the users might not have signed up yet.
Using Rules Playground, I get Property email is undefined on object. Maybe using request.auth.email is not possible?
I was having the same problem but switched from using firebase.auth.email to firebase.auth.token.email and it now works.
I strongly suggest doing two things.
Firstly, store UIDs instead of email addresses. A UID is the preferred way to identify a single Firebase Auth account and is always guaranteed to exist and be unique. Email addresses are not.
Secondly, store the list of users as an array type field instead of comma separated string. This will be much easier to manage overall.
After you do these two things, the rule becomes simple:
allow update: if resource.data.managerUids.hasAny([request.auth.uid]);
use: request.auth.token.email insted request.auth.email
documentation here
In Firestor rules, how can I allow new documents to be created to a collection, and new values to be added to a document but not values in the document to be overwritten?
Please see the following for a clearer understanding:
Collections -------------- Documents -------------- Values
Users -------------------- DonutCoder -------------- isAdmin, birthDate
Now, if I want to add email to the values under the document Donut Coder how can I do this but prevent overwriting (eg. changing isAdmin to true so the user gets more priveleges)
What I have tried: allow read, create - but this allows new documents to be created but no properties in the document to be changed.
1) Don't add any code that overwrites the same path.
2) TO prevent others from reverse-engineering and update it, add this:
allow update: if false
Again anyone can still attempt to create the same document again so you need to add more security rules to it. Do check the official documentation for that.
I have answers regarding similar questions but they refer to realtime database. Though you can check it here.
The allow update: if false just prevent updating the existing value.
This official documentation page seems to show how to do this: https://firebase.google.com/docs/firestore/security/rules-fields#preventing_some_fields_from_being_changed
allow update: if (!request.resource.data.diff(resource.data).affectedKeys().hasAny(['average_score', 'rating_count']));
Preventing isAdmin or birthDate being updated:
allow update: if request.resource.data.isAdmin = resource.data.isAdmin
&& request.resource.data.birthDate = resource.data.birthDate;
You can start building on this depending on your needs. For instance, if you want to allow only logged in user and modifying only one field at a time:
allow update: if request.auth.uid != null
&& request.resource.data.diff(resource.data).affectedKeys().size() == 1
&& request.resource.data.isAdmin = resource.data.isAdmin
&& request.resource.data.birthDate = resource.data.birthDate;
If I wanted to not allow users to delete a file stored in Firebase storage, what rule would I need to write to accomplish this?
I know for Firebase database I would do something like:
".write": "newData.val() != null"
But how would I do this for storage?
Pretty sure this has been answered a few times (in a few ways), but the easiest answer I've seen is:
allow write: request.resource.someProperty == resource.someProperty || resource == null;
someProperty can be a hash (if you don't want to allow overwrites) or a name (if you want the contents to be overwritten by a new object).
One way to do this would be to only allow writes if the MD5 hash of the new file is the same as the existing file:
// Allow writes if the hash of the uploaded file is the same as the existing file
allow write: if request.resource.md5Hash == resource.md5Hash;
There are probably more/easier ways. But this is the first one I came across in https://firebase.google.com/docs/reference/security/storage/.