Firebase Storage Rules customMetadata not working - firebase

I made some rules to access shared files only for a group of people in Firebase Storage.
The way I do this is to put all the uid's in the customMetadata as keys
[uid: Value]
When I evaluate if the user can read and write the data, I do this:
service firebase.storage {
match /b/{bucket}/o {
match /{accountId}/{allPaths=**} {
allow write: if request.auth.uid in request.resource.metadata.keys() && request.auth != null;
allow read: if request.auth.uid in request.metadata.keys();
}
}
}
I can write successfully, but I just can't read the data.
I have tried all kind of ways:
request.metadata[request.auth.uid] == 'theValue'
request.resource.metadata[request.auth.uid] == 'theValue
request.auth.uid in request.metadata
request.auth.uid in request.resource.metadata.keys()
Nothing works.

You should use:
allow read: if request.auth.uid in resource.metadata.keys();
I see that you've tried request.resource many times. This variable is only accessible when writing to Firebase Storage. When reading you must use resource directly.

Related

Firebase rules for collection group subcollection: resource.data is empty?

I use collection grouped subcollections, so (in my understanding) I have to use a wildcard:
match /{path=**}/actions/{action} {
allow read, write: if request.auth != null;
}
This is working so far.
It'sworking also when implenting another rule:
match /{path=**}/actions/{action} {
allow read, write: if request.auth != null
&& request.auth.token.email !='';
}
But I want to check if the user has access with data in the document and there comes the problem:
match /{path=**}/actions/{action} {
allow read, write: if request.auth != null
&& request.auth.token.email in resource.data.access;
}
leads to
FirebaseError: Missing or insufficient permissions.
with:
this.afs.collectionGroup("actions", ref =>
ref.where("owner.email", "==", user.email)
).valueChanges({ idField: 'id' }).pipe(take(1))
So far I couldn't find any further information about how to access data within a wildcard.
The data of document being accessed is present in resource and not request. So the rule should be:
request.auth.token.email in resource.data.access;
Do note that here resource has data of the document in actions sub-collection (/actions/{doc}).
You can find more information about data validation in the documentation.

What is the correct Firestore security Rule for the following scenario?

I have a firestore db like this
users
{userId}
boards
{boardId}
Board Data
I have firestore security rules setup like this.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
}
match /users/{userId}/{document=**} {
allow read, create, update, delete: if request.auth != null && request.auth.uid == userId ;
}
}
}
How should I setup the rules that-
Users can only access their own data.
No one can access the root users collection
There is an overlapping match statement in your rules, since you use match /{document=**} which maps to ALL documents in your database (see the doc).
So, since:
In the case where multiple allow expressions match a request, the access is allowed if any of the conditions is true, and
For the match /{document=**} statement your rule is allow read: if request.auth != null;, then
every authenticated user can read any user document (you don't restrict on the uid as you do for the users collection. And actually you cannot do so, since match /{document=**} does not specifically target the users collection).
The best is to remove this block and just keep the following block.
match /users/{userId}/{document=**} {
allow read, create, update, delete: if request.auth != null && request.auth.uid == userId ;
}
And if you need to grant read access to other collections, use a rule for each collection, instead of using the wildcard approach.
PS: You may double check if you really need to do match /users/{userId}/{document=**}, which grants access to all subcollections of the users docs. You may just need to do match /users/{userId}.

Firebase Database Rules - Is this necessary?

Are Firebase's database rules absolutely necessary? In my app, I've made it so a user can only login to their own account if they know the password. And then every time I access firestore, I only pull data that belong to that user's id. So, why are firebase's rules necessary? Is it just a secondary measure? Asking because I'm also running into a lot of issues with testing firebase rules.
Example.
I have the below rules and they don't work, but without posting my entire code file here (which I don't feel comfortable doing), no one can really help me figure out why it's not working. The code below in theory should work but doesnt.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
match /routines/{routine} {
allow read, write, update: if request.auth != null && resource.data.uid == request.auth.uid;
}
}
}

How to have different rule for a specific collection in firebase firestore

I have a firestore db, for all collections I want to have below rule
allow read : if request.auth.uid != null ;
allow write: if request.auth.uid != null ;
except for service-account collection, which I don't want anybody has access (only firebase functions since they are running under admin service account) so I updated my rules to
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read : if request.auth.uid != null ;
allow write: if request.auth.uid != null ;
}
match /service-account/{serviceAccount} {
allow read: if false;
allow write: if false;
}
}
}
Then I tried to test it via Rules Play Ground, rules are teken into account but result is not correct
So my rule correctly ban access, but the first rule which is going to be applied for all, seems to allow read. I changed the order and no diffrenece.
How can I fix this.
The problem is that this rule is unconditionally applied to every single document in your database:
match /{document=**} {
allow read : if request.auth.uid != null ;
allow write: if request.auth.uid != null ;
}
With this in place, all documents are readable and writable by all users. You cannot override this with another rule. Once a document is deemed readable by any rule, that can't be changed.
See the documentation for overlapping match statements.
What you will need to do instead is call out each individual collection by its name (except service-account), and apply the permissions to them individually.

Limiting permissions to the author not working in Firestore rules

I am attempting to move my Firebase rules from testing where every user could read and write every document to one where only the author can update or delete documents they create.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow update, delete: if request.auth != null && request.auth.uid == resource.data.author_uid;
allow create: if request.auth != null;
}
}
}
This set of rules is resulting in a 'Missing or insufficient permissions" error at Firebase init and if I attempt to delete a document. If I go with my original rules then everything works.
allow read, create: if request.auth != null
I do a standard firebase.initializeApp (but dont want to publish my keys here - lets just say the same initialize works with the basic rules and on three other firebase projects I have). The delete call is as follows and works with the simpler rule set as well but not the tighter rules above:
const decrement = firebase.firestore.FieldValue.increment(-1);
firestore.collection('story').doc(storyid).delete().then(function() {
firestore.collection('users').doc(getUserID()).update({
saves: decrement
});
})
(thank to Sam Stern on the FB team for guidance)
First, there was a mistake in the rules description. While request.auth.uid is defined by firebase the resource.data.author_id needs to be defined by the developer on each of their documents. In this case the 'story' document contains a 'creator' property that is the userid of the owner. So the correct variable would be resource.data.creator in the above rules.
In addition its possible to define the documentid as the userid, as is often the case when you are creating a 'user' object for each account in your firebase app. In this case the userId is the same as the documentId so the following rule would control update permissions that only allow the owner of that document to change it.
match /users/{userId} {
// In this scope the "userId" variable is equal to the documentId because of the wildcard declaration {userId}
allow update: if request.auth.uid == userId;
}

Resources