nested firebase-firestore rules: owner id within parent document - firebase

I can't get these rules to work:
I've got a collection with projects, which all have an owner. The owner should be allowed to read/write his projects and the subcollection working_copies as well.
This implementation succesfully grants reading the project, but fails (Missing or insufficient permissions) when reading a working_copy from the sub collection. I suspect it tries to find an owner within the sub-document.
service cloud.firestore {
match /databases/{database}/documents {
match /projects/{projectId} {
allow read, write: if
resource.data.owner == request.auth.uid;
match /working_copies/{doc} {
allow read, write: if true;
}
}
}
I've also tried using this condition either in the project path or in the working_copies path, but it both fails as well:
get(/databases/$(database)/documents/projects/$(projectId)).data.owner == request.auth.uid
Everything above also fails when i use a recursive wildcard for nesting:
match /projects/{projectId=**} {
...
The strange thing is, i think the first version used to work until some days ago.
I use angular/angularfire and call the requests like this:
this.db.collection('projects').doc('3279').collection<ProjectData>('working_copies').valueChanges().pipe(...
In the rules simulator it's green lighted though.

I've finally found a workaround:
!('owner' in resource.data) || resource.data.owner == request.auth.uid
This makes it accept that the child document doesn't provide the owner once more. So it seems, when nesting rules, the parent rules are also applied to child documents.

Related

How to check auth uid with the uid present in the collection data

In firebase's firestore security rules:
I want to check the auth.uid with the uid data available in the document of the collection.
I tried using below code but it is not working....is there any way to get this done?
match /databases/{database}/documents {
match /candidates/{candidate}/{document=**} {
allow read: if request.auth != null && request.auth.uid == resource.data.userId;
allow write: if true ;
}
This is some improvement for your code. Check whether it would help to solve your problem.
Here in line 2 the syntax should be in the following format.
match /collection/document/collection
So because I think you referring to the documents in the candidate collection it should be as below if you don't want to the rule to be applied deep in the hierarchy.
match /candidates/{candidate}/ {
or as below if you need the deep hierarchy application of the rule.
match /candidates/{document==**}/ {
for the rule statements the first rule can be re-written as
allow read: if request.auth.uid == resource.data.userId;
since looking for the auth.uid in the request token will automatically block unauthenticated users since they won't have auth property on them.
For the second rule I guess you're using only for testing purposes. Since it is dangerous to allow anyone to edit documents without any permission. You can either same rule for the read operation or use a different rule to not allow unauthenticated write access.

Firebase rules not applying to subcollection documents

Here are my rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /Users/{id}{
allow read : if (request.auth.uid == resource.data.uid);
allow write : if false;
}
match /Class/{id}{
allow read : if (request.auth.uid == resource.data.instructor.uid || (request.auth.uid == resource.data.admin.uid));
allow write : if false;
}
match /Class/{id}/Topics/{doc} {
allow read:
if request.auth.uid == resource.data.topicOwnerUID || request.auth.uid == resource.data.adminUID
allow write: if false;
}
}
}
Everything is fine except trying to pull all the topics from Class/docs/Topics/docs. I use getDocuments and try to get all documents using limit(50), I only have 1 topic now, but I also tried making limit to 1 and still don't work.. In each of the Topics docs, there is an adminUID and a topicOwnerUID field. When the owner tries to pull all documents I am getting an error: "Error: Missing or insufficient permissions.". I checked and all the required fields are there and this should allow.
Edit: seems like if i remove .limit and just get a single doc with a specific docID it works. But this isn't what I want :/. Maybe I will have to make the subcollection into its own collection.
Edit2: doesn't work even if it is not a subcollection. completely lost rn. Looks like the only way is to get each doc individually but this ruins lazyLoading. Firebase is lagging behind. will be switching to another db.
Security rules do not mean anything without the matching queries - remember that Security Rules ARE NOT FILTERS - they will NOT "just give you the records that are allowed" - you MUST use queries to match your rules. If your query could return a document that isn't allowed by the rules, then the ENTIRE query is disallowed.
I can tell you from EXTENSIVE use that Firebase/Firestore do not lag behind in any way, and I use complex queries continuously.

Super basic firestore security rule won't work

I can't get the literal simplest firestore security rule I can write to work in the play ground. Just for testing, I've made a Cloud Firestore database with a collection named users. It has one field stuff. In the playground, these are my rules:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{user} {
allow read, write: if true;
}
match /{document=**} {
allow read, write: if false;
}
}
}
I'm simulating a get on location: /databases/(default)/documents/users, but it always fails due to the document=** match, and never matches /users/{user}. Why is this! Feels like I'm following the most basic examples from the docs.
Added a couple screenshots for clarify.
In the "Rules playground", in the location field, you don't need to enter /databases/(default)/documents/. This part of the path is already taken into account, as it is shown above the editable field with the pale grey (or greyed out) /databases/(default)/documents string.
So, by just entering users/C8YDk... it will work, since your rule allows reading the doc, due to an overlapping matching statement.
More info on how to use the playground is to be found here.

Firebase Database has insecure rules even though the rules are necessary

This was asked quite a lot but I still don't know what I can do to silence the warning I am getting every week from Firebase ...
Your Cloud-Firestore database has insecure rules
As you can guess my rules are all can read & write.
My problem is that I actually need that. Inside the SignUp process I need to access all the users emails and usernames to check if the currently selected is available or not. And after the User has signed up he is able to search for other users and create/delete/change his own files.
I don't quite get how I can get rid of the security issue. Where is the threat ?
As I said in then comments if your users can create/delete/update only his own files then your rules wouldn't be read/write true. As i understand you need to have all users to be able to read but you want them to write only to their own documents.
On way to do it is by putting the document id the same as the user id and then use the below rules to check if it is valid.
match /users/{userId} {
allow write: if request.auth.uid == userId;
allow read: true;
}
So, finally got it right. With this solution everyone can read and user can only write their own stuff.
Here is my code:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow write: if request.auth.uid == userId;
allow read;
match /{allSubcollections=**} {
allow write: if request.auth.uid == userId;
allow read;
}
}
}
}

Firestore rules: How do I allow access to a subcollection depending on a field of the document that contains it?

I am writing a small program in react that manages a league of sorts.
The problem I have is how do I allow access (read, write) to the matchdays of a league for the correct user. The matchdays are named "matchday-1", "matchday-2", and so on, and are collections of documents (the matches), and are subcollections inside the league.
My firebase structure looks like this basically:
leagues(collection) -> league(document) -> matchday-n(collection) -> match-m(document)
where n and m are numbers.
Here's the issue:
The league document contains a field called "creator", which contains the ID of the user that created that league. Only they are supposed to access it and its matchdays!
But as it seems, when I am accessing a matchday, the value for resource.data.creator in the firebase rules is different from when I am accessing the league itself.
My question is: Which rule do I have to implement, so that only the user who created the league can access it and its subcollections?
I tried to find a way to compare the request.auth.uid to the creator of the league.
I tried something like this as a condition:
request.auth.uid == get("path-to-league").creator
, as you can see in the code I provided.
But it doesn't seem to work this way, as I might be referencing the path incorrectly.
This is my code at the moment:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /leagues/{league} {
allow read, write: if request.auth.uid == resource.data.creator
}
match /leagues/{league}/{document=**} {
allow read, write: if request.auth.uid == get(/databases/$(database)/documents/leagues/$(league)).creator
}
}
}
Depending on how I fiddle with the rule set, but in case of my provided code, I get "missing or insufficient permissions" when trying to access (read or write from) a league that has the wrong creator, which is good, but even if it's the correct creator, I cannot access the matchdays.
You're missing a bit of syntax. It should probably be this:
match /leagues/{league}/{document=**} {
allow read, write: if request.auth.uid ==
get(/databases/$(database)/documents/leagues/$(league)).data.creator
}
Note that there is a data property before creator. This gives you access to the raw field values of the document Resource object.

Resources