Firebase Firestore fetch all documents via REST API and ID Token - firebase

I have a running firebase web app where I want to let users fetch their data via API. Users can get their access bearer token and should only be able to fetch documents they created.
My firebase rules look like this:
match /chatroom/{chat} {
allow read, write: if request.auth.uid != null && (resource.data.createdByUid == request.auth.uid);
}
This works fine when trying to fetch single documents via:
https://firestore.googleapis.com/v1beta1/projects/my-project/databases/(default)/documents/chatroom/{id}
But when I try to fetch the whole list of chats at once it does not and returns 'insufficient access rights:
https://firestore.googleapis.com/v1beta1/projects/carta-portal/databases/(default)/documents/chatroom
I know the API call works in principle since when I open up security it returns the full list. So that leads me to the question how I can check the data field for 'createdByUid' in a REST call where I expect to return a list instead of a single referenced document.
Thanks in advance for the help - I am struggling with whole firestore rule setting.

Related

exposing firebase credentials with user information

hey i am developing a web application for a public project using firebase and I am worried about exposing user emails.
The basic idea of the website is:
1.) input -> user provides email and some information
2.) calculations happen on the server and information is written to firestore (admin sdk)
3.) output -> user receives a link in their email to view the results
the information i store is essentially
taskID {
input,
email,
output
}
users only have read permissions
my firebase rules as follows:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if false;
}
}
}
i know the firebase credentials are somewhat exposed on the client, so I am worried that somebody can use them to list all tasks, then iterate over all tasks to get the emails and the user provided inputs.
Is this possible at all? Would i have to have a different collection which can only be read by admins, then reference the fields?
taskID {
input,
email : privateCollectionID,
output
}
privateCollectionID {
email
}
Thanks
Your current rules allow anyone and everyone to read all data in your database at will.
If that's not what you want, you'll need to structure your data in a way that meets what you do want.
If you want some data to be publicly readable, and other data to be only readable by the owner of that data, you will need to separate that data into different documents/collections and apply different rules to them.
For an example, have a look at the Firebase documentation for public/private access in security rules.
You could use a Callable Cloud Function that you call from the front-end passing the desired email.
The CF queries the collection to find the document corresponding to the email and returns the document data.
Since the Admin SDK bypasses security rules you can deny read access to this collection in the security rules.
Note that:
This will not prevent users to test for a certain email existence but it will prevent them getting direct (one shot) access to the entire emails list.
The response time will be a bit longer compare to a direct query to Firestore via the JS SDK. More details in this article.

Evaluating whether a user exists or is invited in Firestore / Firebase Cloud Functions

I have a React application that I'm building for production that is using Firestore and Firebase Authentication. Each user can have one other user paired with their account. Each user can only be paired with one other account.
Currently, each email address is logged to a Firestore collection in an array either as an invitedUser when they are invited or a pairedUser when they become paired with another user. This is used to validate when a user suggests an email that they would like to be paired to. To access this, the Firestore Security rule is set as
match /admin/checkUsers {
allow get, list: if request.auth.uid != null
}
It seems too insecure to have all of my emails exposed like this. Is there a Cloud Function that could be written for this or another way to setup my Firestore security settings data structure so I can validate this more safely within my application?

Firestore Security Rules for specific user that was added in the Firebase console directly

I have this user where I added it directly from the firebase console, hence, it is not in any user collection.
Is it possible that only this specific userID can access collections of orders and products?
If it's only one user then you can restrict read access of those collections to that specific UID using the following rule:
match /orders/{orderId} {
allow read: if request.auth.uid == "firebase_user_id";
}

Firestore security rules using uid from database

I am trying to set up some security rules for my Firestore database, I'm using for my Android and iOS app. My database is open for all users to read and write (to a certain degree), but I don't want the data to be able to be deleted/hacked from writes outside the app, so I need some security rules. What I understand is that: allow read, write: if request.auth.uid != null, is not enough, since it can be easily faked from outside the app.
Here is what I want to achieve. When a user signs in (even anonymously) the app sends his unique uid to a collection in the database. This collection stores all the uid's of all users, where the document name is the uid.
Now in the security rules, I want to only allow read and writes of my database, to users whose uid is stored in this collection. After trying to read about it, I still don't know how to write such a security rule. Could you help? How can I reference this collection field in the security rules, and search if there is a document names with the uid of the requester?
For example, I would like:
match /cities/{city} {
allow read, write: if request.auth.uid = userIdInDatabse()
}
I do not know how to write the function, userIdInDatabase(). This needs to be a function written in the security rules, which takes the request.auth.uid and checks if that uid of the request is in the collection of uid's that I have made from the app. If the uid of the request is in the database, the function will return true. If the uid of the request is not in the database, it will return false. How do I write such a function?
Thanks so much! I hope its clear.

Firebase Storage Security Rule : Check if another object exists / check object's metadata

In Firebase storage security rules (not realtime database), is there any way to perform a check if another object exists at path, or another object's metadata exists?
Some background
Currently my storage security rules are set up so that users only have read access, and not write access to their /users/{userId}/ paths.
I have an admin cloud function that saves a file to /users/{userId}/necessary-file.pdf. And I don't want users to be able to modify or write this file and only cloud functions to have the right to do. To achieve this I think I can match for the filename like :
match /users/{userId}/{fileName} {
allow write: if !fileName.matches("necessary-file.pdf")
}
Question
Is there any way for me to only allow users to write some-other-file.pdf if they already have a necessary-file.pdf at the same path (or even somewhere else if that works better). All while still disallowing them to write necessary-file.pdf.
So is there any way for me to do something like this pseudo-code? :
match /users/{userId}/{fileName} {
allow read: if request.auth.uid == userId;
allow write: if (!fileName.matches("necessary-file.pdf")) && ("necessary-file.pdf".exists())
}
As an alternative, I can have my cloud functions write a metadata to necessary-file.pdf and check for that too. is there any way I can perform something like this pseudo-code? :
allow write: if "necessary-file.pdf".metadata['canUserWrite'] == 'yesUserCan'
Finally
What's really cool about this is that, if this is in any way remotely possible, it can be used to communicate between firebase database and firebase storage rules in a not-so-realtime way. (referring to this question here) A cloud function can listen for changes in the intended field in realtime database, and write a file to firebase storage, which firebase storage can check for.
Firebase's Cloud Storage security rules can only access information about the current request and file. They don't have access to the full storage system, so can't check whether another file is present.
The reason for this is that the rules are evaluated in memory for every request. Providing access to Cloud Storage for other objects would slow the performance down, making the system unscalable. That same reason explains why you can't access the Firebase Database from the security rules.
If you want some control like this, you'll want to look in Cloud Functions for Firebase. If you have your users upload their files into a "staging" area, you can have a Cloud Function validate whether they met all prerequisites and only then move the file into the actual location (making it available for further processing or for clients to see).
(Another Solution) Restricting Storage Access with Auth Claims
Cloud Storage Rules has access to auth info for the request user. By setting up a check during the authorization process an auth property can be added for later access validation in storage rules.
Original Question:
Is there any way for me to only allow users to write
some-other-file.pdf if they already have a necessary-file.pdf at the
same path (or even somewhere else if that works better). All while
still disallowing them to write necessary-file.pdf.
Yes, this could be done by checking an auth.token.
Example flow for a Web App w/ Google Signin:
Create a Cloud Function to set a custom claim that checks for the existence of that file against the current auth user.
Upon success of the user authorizing via Google call that cloud function for it to set a value to the auth object.
Check auth.token in the storage rule.
Web Example for Custom Claims:
https://firebase.google.com/docs/auth/admin/custom-claims?hl=ro#examples_and_use_cases
Example Storage Rule:
https://firebase.google.com/docs/storage/security/rules-conditions?hl=ro#group_private

Resources