In my company documents, I have a reference field named owner, which points to a user document. In the rule, I am trying to check if the authenticated uid is the owner of the company:
match /companies/{companyId} {
allow read: if isOwner(resource.data.owner, request.auth.uid);
}
function isOwner(owner, userId) {
return path('/users/' + userId) == owner;
}
I tried many things but can't figure out how to make this work.
(I know using a string instead of a reference works, but I would rather use a reference)
When you construct the path, include this prefix: /databases/(default)/documents/. It's part of the full path to a document.
match /companies/{companyId} {
allow read: if isOwner(resource.data.owner, request.auth.uid);
}
function isOwner(owner, userId) {
return path('/databases/(default)/documents/users/' + userId) == owner;
}
The following should enable you to compare on the reference field.
match /companies/{companyId} {
allow read: if /databases/$(database)/documents/user/$(request.auth.uid) == resource.data.owner
}
Note: resource.data.owner NOT request.resource.data.owner
Why not making an ownerId field in the compagny document and check if the authenticated user uid is equal to the value?
service cloud.firestore {
match /databases/{database}/documents {
match /companies/{compagnyId} {
allow read: if isOwner()
}
}
}
function currentData() {
return resource.data
}
function isOwner() {
return currentData().ownerId == request.auth.uid
}
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.
So i'm making an app with a friends system and trying to set up rules for firebase to handle reads & writes if the users is friends or not.
I'm very stuck at a particular call that i just don't have any idea on how to make.
My firestore is structured as follows:
users/userUID/places/documentsofplaces
each userdocument have some fields of the usual information, name, username, etc. and an array of friendsUID.
I have managed to get the first part down, that a user can only read and write if it's UID matches the documentUID, and looking in the friendslist a friend can only read but not write.
The next part, in the places collection, just throws me off, how can i get the parent document and compare the userUID to a UID in the friendslist?
This is what i have so far:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
// Allow write and read if user, and read if friend
allow write: if isUser(userId);
allow read: if isUser(userId) || isFriend();
function isUser(userId) {
return (request.auth.uid == userId);
}
function isFriend() {
return (request.auth.uid in resource.data.friendsList);
}
}
match /users/{userId}/places/{documents} {
allow write: if isUser(userId);
allow read: if isUser(userId) || isFriend(userId);
function isUser(userId) {
return (request.auth.uid == userId);
}
function isFriend(userId) {
return (request.auth.uid in get(/databases/$(database)/documents/users/userId.resource.data.friendsList));
}
}
}
}
Any help is greatly appreciated!
Your document get() should look more like this:
get(/databases/$(database)/documents/users/$(userId)).data.friendsList
You have to use variables with $(var) notation inside the document path. get() returns a Resoruce object with a data property. I suggest reading over the documentation for accessing other documents for more details.
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);
}
}
}
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;
}
}
}