Trying to separate the data by user uid firebase? - firebase

I have this in my rules but it's not working, just started using firebase a few weeks ago
match /pets/{owner} {
allow read, write: if request.auth.uid == owner
}
this is the code im using to get the data from the collection:
Stream<List<Pet>> get pets{
print(userUid);
return petsCollection.where('owner', isEqualTo:
userUid).snapshots().map(_petListFromSnapshot);
}
im using the print to see if i get the uid from the current user for that query, but it comes null. In a diffrent part of the code i already add the uid of the person that creates a document to the collection.
what im trying to say is that i need advice on how to only get the current user data.

You cannot use security rules to filter results
Once you secure your data and begin to write queries, keep in mind that security rules are not filters. You cannot write a query for all the documents in a collection and expect Cloud Firestore to return only the documents that the current client has permission to access.
https://firebase.google.com/docs/firestore/security/rules-conditions?authuser=0#rules_are_not_filters
Use filter to get current user related documents.

Related

Firebase security rules based on custom user field

I'm trying to set up security rules (use Firebase Cloud Firestore).
I changed the "users" table (added company_id field) and create "appointments" table (with company_id). I want to implement the following functionality (when a user requests appointments, he only receives appointments with his company id)
Wrote a rule:
match /appointments/{appointment} {
allow write;
allow read, update, delete: if resource.data.company_id == get(/databases/$(database)/documents/users/$(request.auth.uid)).data.company_id;
}
But my code throw error about permissions
const q = query(collection(db, 'appointments'), where("company_id", "==", company_id), orderBy("createdAt"));
Firestore doesn't magically know what documents have what company_id, so it tries to read all documents to return the documents that you want, but it can't, your security rules stop it.
Either get rid of the security rules, or find a way to structure your database so that you don't have this problem.
I don't know enough about your database to tell you a good structure, but what about something like this?
A collection called companies.
Each document in the collection is a company_id
A subcollection called users, where you put all users that belong to this company.
Another subcollection, called appointments, where you put all appointments for the company.
That way, you could write a security rule like so:
match /companies/{company}/appointments/{appointment} {
allow create: if true;
allow read, update, delete: if exists(/databases/$(database)/documents/companies/$(company)/users/$(request.auth.uid))
}
The problem with this approach is that, because we have divided all users and appointments into different collections, it will be impossible to query for all existing users or for all existing appointments.
It all depends on your use case.

Firestore rules validate query field value

I have collection of users and every user can search for others by their publicId
query(
collection(db, "users"),
where("publicId", "==", "..."),
limit(1)
);
and I want to allow users to regenerate their `publicId"s so others won't be able to find them by the old ones.
The problem is that if someone finds a user once and get their doc id they could potentially get the user by that doc("users", "docId") regardless of their "publicId".
I tried to use request.query.publicId == resource.data.publicId, but query seems to only provide limit, offset and orderBy.
Is there a different way to access the query field value or a different way to mitigate the issue?
For the public profile, it might be best to create another collection e.g. "public_users" where the document ID is user's publicId. So when a user regenerates their ID, you can just create another document with new publicId and then delete the previous one.
Do not store a reference to user's UID in this document if you want to keep that a secret. Instead, store this public ID in the "users" collection so that can be read by user only.
Alternatively, you can make your requests through a Cloud Function and block direct requests to Firestore. So there's no way anyone can query by user ID.
For the main collection, you can add a rule that allows users to write their own document only like this:
match /users/{userId} {
allow write: if request.auth.uid == userId;
}

Check References in Array - Firestore Security Rules

I am building firestore security rules for my app and in the events collection I have a property called members that has an array of references from the users collection. How would I go about making sure that the user that has sent the request is in that collection? I know I am able to get the userId through request.auth.uid but I'm unaware of how to get the document reference in firestore rules and make sure that the reference is in the array.
The answer that I have found is this:
match /events/{eventId} {
allow read: if /databases/$(database)/documents/users/$(request.auth.uid) in resource.data.members;
}
Looks like the in keyword allows me to check if a value is inside an array and /databases/$(database)/documents/users/$(request.auth.uid) creates a DocumentReference which is the data type stored in the array.
As clarified in this other post here, similar to yours, Firestore rules are not used for filtering data, but to set which data are accessible for which users and which queries can be performed.
Considering that, you will need to write code that will query and compare the datas from your request.auth.uid, with the ids from your subcollection. This way, you will be able to confirm the data you want, that is the user requesting being authorized to access the information. This would be the correct way to handle the request and return the information or not from your database.
A simple example of code that will confirm that the requesting users is in the members subcollection is similar to the following lines:
var user = firebase.auth().currentUser;
db.collection("events").where("members", "array-contains", user.uid).get()
While this code is untested, is a starting point for what you will need to do, to guarantee that the user requesting is allowed to retrieve the information. You can get more information on what you need here.
Let me know if the information helped you!

Firestore rule on uid doesn't work for unknown reason

I have an 'owner' field in my documents to entitle only the owner to read the document, and only a new document that its 'owner' field is the uid of the user, can be written:
allow read: if request.auth.uid == resource.data.owner;
allow create, write : if request.auth.uid == request.resource.data.owner;
The creation and update rule works as expected! I tested and saw that if the 'owner' field of the record in the new data is not the user's UID then it doesn't work!
The problem is the 'read' section. I wasn't able to read records. Only when I changed to allow read: request.auth.uid != null, I was able to read.
I triple checked that the records has an 'owner' field that is exactly the same as the UID, also in debug.
I'm have experience with Firebase, and I have no idea what is the problem here.
Since you indicate that "[You weren't] able to read records" (with an S at records), your problem most probably comes from the fact that security rules are not filters, as explained in the documentation:
Once you secure your data and begin to write queries, keep in mind
that security rules are not filters. You cannot write a query for all
the documents in a collection and expect Cloud Firestore to return
only the documents that the current client has permission to access.
You don't show the query used to read the Firestore documents, but let's imagine your documents are in a collection named collection.
With a query like
query = db.collection("collection")
query.get().then(....);
you are querying independently of the User ID, hence the problem.
You need to adapt your query with the where() method, as follows:
//get the value of uid
query = db.collection("cities").where("owner", "==", uid)
query.get().then(....)

Firestore permissions and rules for querying collections (list) that belong to the logged-in user

I'm building a contact manager where a user has a bunch of "contacts" in their address book. I only want the user who created the contact to be able to query that contact. I wrote a query below that says what I want it to do, but the query does not work and I do not know why.
All contacts are created with an owner_id field that corresponds to the uid of the user that created the contact.
service cloud.firestore {
match /databases/{database}/documents {
match /contacts/{contactId} {
// only allow read for contacts if the current user is the owner
allow read: if request.auth.uid == resource.data.owner_id // <-- this does not work
allow write: if request.auth.uid != null && request.resource.data.owner_id != null;
}
}
}
When I run the query, I get nothing back, and the simulator does not allow me to run queries on list queries for the entire collection, only get for a single document. The query is simply:
db.collections('contacts')
I've also tried limiting using a where clause:
db.collections('contacts').where('owner_id', '==', <hard-coded-owner-id>)
I should note that when I query for a single document, the syntax above does appear to work. It just appears to fail when I query a collection.
So my question is, how does one write a database rule such that I can list all items in the collection while only returning the items that are associated with the logged-in user?
https://firebase.google.com/docs/firestore/security/get-started
I would expect your first query to fail because it's essentially trying to access documents that it doesn't have permission to read. Your rules will not implicitly filter the results.
I'd expect your second query to work because it's only accessing documents that are allowed by permissions. However, it will only work when the effective UID as reported by Firebase Authentication is the same as the one you hard coded. That's what you're rule is verifying - that the logged in user is only trying to read documents where they are present in owner_id. If you're working in the console simulator, you will have to turn on Authentication and put the right UID in the form.

Resources