I have a document whose name consists of two user keys, can I check whether the key of the querying user is included.
for example the user fvmAPXO4BYUVJYkeSxsgsgzjjs should have access to the document 2B0ABrxKgjkrefjCP8tuMgq12e4-fvmAPXO4BYUVJYkeSxsgsgzjjs
I need something like: allow read, write: if document name contains ("request.auth.uid") ;
You can use matches() as shown below:
match /collection/{docId} {
allow read: if docId.matches(".*"+request.auth.uid+".*");
}
This regular expression will simply check if request.auth.uid is present in the document ID.
Related
I am developing a Flutter app and using Firebase as backend. In my app, each user needs o sign up to be able to use the app and the user's profile data is saved in a user_profile collection.
Each user's profile data is stored in a separate document in the collection.
The Document ID for each document is equal to the User ID, created by the Firebase Authentication when the user signs up for the first time.
And I also save the User ID in a field (named uid) in each document as well for the corresponding user.
For the security part, I want that each user may only read his/her own profile data. I set the following rule:
// Rules for User Profile data
match /user_profile/{any} {
allow read: if (request.auth != null) &&
(resource.data.uid == request.auth.uid) &&
exists(/databases/$(database)/documents/users/$(request.auth.uid));
Is it correct if I set my rules as given in the above example?
(1) The user needs to be authenticated
(2) The uid in the incoming request needs to be equal to the uid field in the corresponding document that the user wants to read.
(3) The document with the uid available in the request must exist in the corresponding document
I cannot make it clear to me if I am making the whole thing unnecessarily complicated. For instance, does the rule (1) do the same thing as rule (2)? While I have rules (1) and (2), does it add anything to have rule (3) as well?
Based on the following elements in your question:
The user's profile data is saved in a user_profile collection
The document ID for each (user's profile) document is equal to the User ID
You want that each user may only read his/her own profile data
the following read security rule should do the trick:
service cloud.firestore {
match /databases/{database}/documents {
// Match any document in the 'user_profile' collection
match /user_profile/{userId} {
allow read: if request.auth != null && request.auth.uid == userId;
// ...
}
}
}
In other words, since the document ID for each (user's profile) document is equal to the userId you don't need to use the field containing the userId in the security rule: The wildcard expression {userId} makes the userId variable available in rules, see the doc.
I'm building a chat app with Firestore and each chat room has a map of participants like so:
The keys are the corresponding UIDs of the users. I want to use this map to decide which user can access a chat.
In my security rules, I currently check if the logged-in user's UID exists in this map to allow read and write access:
allow read, write: if request.auth.uid in resource.data.participants
But this only checks if the user is in this map, not if the value is actually true. I want to check that as well.
What I basically want is something like this:
allow read, write: if resource.data.participants.request.auth.uid == true
But this does not actually work. How do I use the current user's UID as the key in a map check?
Use square brackets to index into the Map using any string expression you want:
allow read, write: if resource.data.participants[request.auth.uid] == true
I am trying to figure out how should I write my firestore rule such that Only the matching uid in the key of the document's key-value pair can have permission to write.
More specifically:
my firestore structure is something like:
'Items LA' -> 'Pasadena' -> {'awjij53dHh3dnYAh': {itemInformation}}
collection -> document -> fields
where 'awjij53dHh3dnYAh' is the seller ID.
and I want to write a rule such that it gives awjij53dHh3dnYAh permission to write in that field.
Currently what I have is the following:
match /Items%20LA/{cityName}/{data}{
allow read: if request.auth != null;
allow write: if request.auth.uid == data.key; // This is where I am not sure how to write what I want to accomplish
}
Thanks
First thing - the match path for a rule only includes the path components of a document (collections and document IDs), and not fields. Also, it doesn't need any URL escaping. Just match on "/Items LA/{cityName}".
Second, if you want to refer to the names of fields in a document in a rule expression, you should know that request.resource.data is a Map of all the incoming fields, and you will have to use its API to deal with the those key/value pairs.
Third, if you want to find out which fields of a document changed, you will need to compare the state of the document before and after the change using the MapDiff API.
Putting all this together, you will need to check that only the field changed that equals the user's UID:
match /Items LA/{cityName} {
allow write: if request.resource.data.diff(resource.data).affectedKeys().hasOnly([request.auth.uid]);
}
What you want probably is
allow write: if request.auth.uid == $(data)
//or this
allow write: if request.auth.uid == resource.id
I am writing a chat application and am done apart from the security rules section. I am currently creating two documents for each message (one each for each user) I am okay with writing a document to my user Id but the database isn't allowing for a write in the other paired user Id.
I have tried by allowing the write if the userId is in the resource.data of the other file
match /message/{user}/{chatRoomID}/{messageId} {
allow read, write: if request.auth.uid == user || request.auth.uid in resource.data;
}
How can I make it so whenever a message is sent to the database it is only read and can be written by the specific user Ids??
Each message object has reference to who sent it (each user's object Id). Thanks in advance !!
While in is indeed an operator in security rules, this won't work:
request.auth.uid in resource.data
The in operator checks if a key exists in a map, where it is much more likely that you store the UID of the other user in the value of a field.
To check whether a certain field has a specific value, use something like this:
request.auth.uid == resource.data.senderID
I've found that question relatively often asked here, but i still cant figure out how to manage a rule for unique properties. I have following document datamodel:
users/{usereId}/Object
users/usernames/Object
The first Object contains basic information about the user, like:
{
email: "example#hotmail.edu"
photoURL: null
providerId: null
role: "admin"
username:"hello_world"
}
meanwhile the usernames objects only contains the username as the property key and the uid as the value, for instance:
{
hello_world:"F3YAm8ynF1fXaurezxaQTg8RzMB3"
}
I set it up this way, because I want that every user has a unique username. And its less time consuming iterating through the second object than through the first ones.
But back to my issue. I need that hello_world is unique within the write operation. But my rules so far does not work. I have:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null
}
match /users/{userID} {
allow create: if !exists(/databases/$(database)/documents/users/$(request.resource.data.username)) <== does not apply
}
}
}
The second match is, what should apply the unique property rule. Has anyone an idea how to set the rule correctly?
In the console the object model looks as follows
You created a document called usernames in your users collection, to track the names that are in use. But your rules are trying to find a document named after the current user's name, which will never exist in this structure.
In your current structure, you will need something like this:
allow create: if get(/databases/$(database)/documents/users/usernames).data[$(request.resource.data.username)] == request.auth.uid
So the above gets the document where you keep all the user names, and then checks if the current user name is in their for the current UID.
An alternative approach is to keep an additional colllection of all user names, and then make each document in there map a single user names to a UID. In this scenario your /usernames collection would be top-level, since it's shared between all users. The rules for this would be closer to what you currently have:
allow create: if !exists(/databases/$(database)/documents/usernames/$(request.resource.data.username))
Since your usersnames have to be unique, wouldn't it be an option to use their names as the document key?