My Firestore database creates a new Collection whenever a new user Signs Up to my app. The name of the Collection is the username of the new user. I wanted to make the documents inside this collection to have restricted write access.
service cloud.firestore {
match /databases/{database}/documents {
match /User1/{info} {
allow read: if signedIn();
allow write: if isOwner(User1);
}
function signedIn() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
}
}
This works if the current user is User1 but is not applicable to any new user that signs up. How do I add this Firestore Security Rule to every new user?
I notice that the first rule matches to /User1/{info}, meaning it will match any path in the collection User1. Instead, if you use brackets, this value becomes a wildcard, meaning the match will work for any value. Check out the examples in the guide for more information.
service cloud.firestore {
match /databases/{database}/documents {
match /{username}/{info} {
allow read: if signedIn();
allow write: if isOwner(username);
}
function signedIn() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
}
}
Related
I am seemingly unable to access the resource.id value when trying queries using these rules. when I manually enter the schools id (the commented out line) the data returns fine. I only have 1 school and the doc ID definitely matches the string. but when I ask to match to the resource.id value, my rules return an 'insufficient permissions' error.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
//functions
function signedIn() {
return request.auth.uid != null;
}
function returnUID(){
return request.auth.uid;
}
function getUserData() {
return get(/databases/$(database)/documents/All%20Users/$(request.auth.uid)).data;
}
match /All%20Users/{userID} {
allow read,write: if
signedIn() && returnUID() == userID;
}
match /All%20Schools/{schoolID}{
allow read, write: if
// signedIn() && getUserData().school == "f7asMxUvTs3uFhE08AJr"
signedIn() && getUserData().school == resource.id
}
}
}
my structure is like this
All Schools / school (document) / Classrooms (subcollection)
All Users / User (document) (each user doc has a classroomID associated to it)
as a point of reference this is a query that is successful
var docRef = db.collection("All Users").doc(uid).get()
and the one that is failing
db.collection("All Schools/" + properties.schoolid + "/Classrooms").onSnapshot()
[update]
the working set of rules!
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
//functions
function signedIn() {
return request.auth.uid != null;
}
function returnUID(){
return request.auth.uid;
}
function getUserData() {
return get(/databases/$(database)/documents/All%20Users/$(request.auth.uid)).data;
}
match /All%20Users/{userID} {
allow read,write: if
signedIn() && returnUID() == userID;
}
match /All%20Schools/{schoolID}{
allow read, write: if schoolID == 'f7asMxUvTs3uFhE08AJr'
}
match /All%20Schools/{schoolID}/Classrooms/{classId} {
allow read, write: if getUserData().school == schoolID;
}
match /All%20Schools/{schoolID}/Student%20List/{student} {
allow read, write: if getUserData().school == schoolID;
}
match /All%20Schools/{schoolID}/Staff/{staff} {
allow read, write: if getUserData().school == schoolID;
}
}
}
The following rules will be effective on documents of 'All Schools' collection only and not documents of 'Classrooms' sub-collection:
match /All%20Schools/{schoolID} {
// ...
}
That's why db.collection("All Users").doc(uid).get() works and fetching 'Classrooms' collection fail since you do not have any rules specified for it. Although you had a recursive wildcard earlier (before editing the question), resource object contains data of those documents being matched in 'Classrooms' sub-collection and hence getUserData().school == resource.id failed too.
That being said, try specifying rules for 'Classrooms' sub-collection as well:
match /All%20Schools/{schoolID}/Classrooms/{classId} {
allow read, write: if getUserData().school == schoolID;
}
match /All%20Schools/{schoolID}/Classrooms/{classID} {
// schoolID is the documentId
allow read, write: if signedIn() && getUserData().school == schoolID
}
If this was my code, I would not use spaces in my collection or field names. Rather I will use snake_case or camelCase.
So instead of All Schools, I will use either all_schools or allSchools.
I have a collection in which I am storing user requests in documents having documents ID as user's email. In the document, I am creating fields the key for which is being generated at client side.
Now, the problem that I am facing is that user can overwrite the existing field/request in the document if the key matches which I don't want to happen.
What I tried was to use this rule which unfortunately does not work
resource.data.keys().hasAny(request.resource.data.key();
So how can I achieve this?
Below are the screen shot of the firestore data and the current security rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /roles/{userId}{
allow read: if isSignedIn() && hasId(userId);
}
match /requests/{email} {
allow read, update: if isSignedIn() && hasMail(email)
}
//functions//
function hasMail (email) {
return request.auth.token.email == email;
}
function hasId (userId) {
return request.auth.uid == userId;
}
function isSignedIn () {
return request.auth != null;
}
function getUserRole () {
return get(/databases/$(database)/documents/roles/$(request.auth.uid)).data.role
}
}
}
You can check if a resource already exists. Here an example:
allow write: if resource == null // Can create, not update
Use that to restrict any edit or update of the data. If you have additional rules you can granulate them to update, delete and create.
I have the following rules in my Firestore database. But I still keep getting a notification from Firestore that the rules I set in my database are not secure. Please see the codes below. Any suggestions or recommendations to make the database more secure?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if userIsAdmin();
}
match /Basket/{Basket} {
allow read, update, delete: if userOwnPost();
allow create: if request.auth.uid != null;
}
match /AllOrders/{AllOrders} {
allow read, create, update: if userOwnPost();
}
match /Items/{Items} {
allow update: if userOwnPost();
}
match /Voucher/{Voucher} {
allow update: if userOwnPost();
}
match /User/{User} {
allow read, update: if userOwnPost();
allow create: if request.auth.uid != null;
}
function userIsAdmin() {
return getUserData().userRole == 'Admin';
}
function getUserData() {
return get(/databases/$(database)/documents/User/$(request.auth.uid)).data;
}
function userOwnPost() {
return getUserData().objectId == request.auth.uid;
}
}
}
You have some overlapping match statements in your rules:
With
match /{document=**} {
allow read: if true;
allow write: if userIsAdmin();
}
you allow read access on all documents in your Firestore database.
As explained in the doc (section "Overlapping match statements"), "in the case where multiple allow expressions match a request, the access is allowed if any of the conditions is true".
So all your other security rules are just overlapped by this one.
So I am assuming that my firebase rules are insecure :
I need second thoughts on it
below I set rules like:
Anyone can read and create(register)
Registered users can read messages
Registered users can create messages
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /usernames/{usernames} {
allow read;
allow create;
}
match /users/{users} {
allow read;
allow create;
}
match /messages/{messages} {
allow read;
allow create : if request.auth.uid != null;
}
}
}
Anyone can read and create(register)
match /users/{users} {
allow read, write: if true;
}
Registered users can read messages (and No one can write it)
match /users/{users} {
allow read: if request.auth.uid != null;
allow write: if false;
}
Registered users can create messages (and No one can read it)
match /messages/{messages} {
allow create: if request.auth.uid != null;
allow read: if false;
}
I have two collections worktimes and submissions. Submission document has uid field.
I want to be able to update/delete worktime document when it's not signed. I want something like this:
match /worktimes/{document=**} {
allow update, delete: if !isMonthSigned()
}
In my isMonthSigned() I want to look into submissions collection, choose the document which uid equals mine and than have access to it's field values. How do I get that document?
So far I'm stucked here:
get(/databases/$(database)/documents/submissions/{submission})
Thanks!
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId
}
match /submissions/{submission} {
allow update, delete: if isSignedIn()
&& isOwner(resource.data.userId);
}
}
}