I am trying to set-up Firestore permission rules. This is my data as well as my rules and my authentication payload.
service cloud.firestore {
match /databases/{database}/documents {
match /questions/{questionId} {
allow create: if isAdmin() && emailVerified();
allow read: if isAdmin() && emailVerified();
allow update: if isAdmin() && emailVerified();
allow delete: if isAdmin() && emailVerified();
}
match /users/{userId} {
allow get: if isOwner(userId) && emailVerified();
}
}
function isAdmin2() {
return request.auth.uid == 'CoKtrTQEA8P18v0jtcDUt766rVl1';
}
function isAdmin() {
return getUserData().roles.keys().hasAny(['admin']);
}
function getUserData() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
}
function emailVerified() {
return request.auth.token.email_verified;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
function isSignedIn() {
return request.auth != null;
}
}
{
"uid": "CoKtrTQEA8P18v0jtcDUt766rVl1",
"token": {
"sub": "CoKtrTQEA8P18v0jtcDUt766rVl1",
"aud": "flying-pigs",
"email": "myemail#example.com",
"email_verified": true,
"phone_number": "",
"name": "",
"firebase": {
"sign_in_provider": "google.com"
}
}
}
When trying to read the questions list, isAdmin() will return false every time while isAdmin2() will work just fine, but it is hardcoded.
What am I missing?
Once I had the same problem, I end up doing something like this:
function isAdmin(request) {
return ['admin'] in getUserData(request).roles
}
Make sure your functions receive request as parameter, your isAdmin and getUserData are not currently receiving it. how this helps
Related
I wrote this but its not working:
isAdmin(): not working
isLogin(): working well
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write : if false;
}
function isLogin() {
return request.auth != null
}
function isAdmin() {
return isLogin() &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true
}
// allow for only auth & is admin
match /users/{userId} {
allow read, write : if isAdmin();
}
}
Thanks in advance
You need to pass the database variable as an argument in your function like this:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write : if false;
}
function isLogin() {
return request.auth != null
}
function isAdmin(database) {
return isLogin() &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true
}
// allow for only auth & is admin
match /users/{userId} {
allow read, write : if isAdmin(database);
}
}
}
Firestore doesn't work well with get inside a function
I have this rule
service cloud.firestore {
match /databases/{database}/documents {
function isProjectOpenForAssign() {
return get(/databases/$(database)/documents/projects/$(anyProject)).data.canAssignTask == true;
}
match /projects/{anyProject} {
allow create: if request.auth != null;
match /tasks/{anyTask} {
allow create: if request.auth != null && (isProjectOpenForAssign());
}
}
}
}
When running the simulator testing it I get:
Error running simulation — Error: simulator.rules line [23], column [14]. Function not found error: Name: [get].; Error: Invalid argument provided to call. Function: [get], Argument: ["||invalid_argument||"]
The problem is in the scope of where you define your function. Since you define isProjectOpenForAssign at the same level as this match match /projects/{anyProject}, the function won't have access to anyProject.
There are two solutions:
Pass anyProject as a parameter to isProjectOpenForAssign.
function isProjectOpenForAssign(anyProject) {
return get(/databases/$(database)/documents/projects/$(anyProject)).data.canAssignTask == true;
}
match /projects/{anyProject} {
allow create: if request.auth != null;
match /tasks/{anyTask} {
allow create: if request.auth != null && (isProjectOpenForAssign(anyProject));
}
}
Define the function inside the match that declares anyProject.
match /projects/{anyProject} {
function isProjectOpenForAssign() {
return get(/databases/$(database)/documents/projects/$(anyProject)).data.canAssignTask == true;
}
allow create: if request.auth != null;
match /tasks/{anyTask} {
allow create: if request.auth != null && (isProjectOpenForAssign());
}
}
I am getting the error:
FirebaseError: Missing or insufficient permissions when trying to view a document in a subcollection. I'm trying to get at the documents 'character' in subcollection 'settings'.
systemsCol()
.doc(localStorage.getItem("systemId"))
.collection('settings')
.doc('character')
How can i set all items and subdocuments for each 'system' document?
Here are my permissions
service cloud.firestore {
function authed (auth, data){
return auth.uid == data.owner.uid || auth.token.email in data.collaborators;
}
match /databases/{database}/documents {
match /systems {
allow read, write:
if request.auth.uid != null;
match /{systemId} {
allow list, create:
if request.auth.uid != null;
allow get, update, delete:
if authed(request.auth, resource.data);
}
match /{systemId}/{document=**} {
allow read, write:
if authed(request.auth, resource.data);
}
}
}
}
Also tried
service cloud.firestore {
function authed (auth, data){
return auth.uid == data.owner.uid || auth.token.email in data.collaborators;
}
match /databases/{database}/documents {
match /systems {
allow read, write:
if request.auth.uid != null;
match /{systemId} {
allow list, create:
if request.auth.uid != null;
allow get, update, delete:
if authed(request.auth, resource.data);
match /{document=**} {
allow read, write:
if authed(request.auth, get(/systems/{systemId}).data);
}
}
}
}
}
I am trying to setup security rules for my firestore instance, I have three basic requirements:
User must be authenticated to read
Owners of documents are the only
ones who can write to them (use a field called owner on document to
verify)
Any admin user can also write to any document
The code below achieves all of this (excluded the check for ownership) but the get function to determine the users role only works when specified on the same row as the if condition. In the code below the update and delete works for the admin but not the create.
Can anyone please tell why the isAdmin() function does not evaluate to the same result?
service cloud.firestore {
match /databases/{database}/documents {
// Only 'owners' of data can make changes to data
match /posts/{post} {
allow read: if isAuthenticated();
allow create: if isAuthenticated() && isAdmin();
allow update, delete: if isAuthenticated() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 1;
}
}
/// FUNCTIONS ///
function isAuthenticated() {
return request.auth.uid != null;
}
// function requestIsOwner() {
// return request.resource.data.owner == request.auth.uid;
// }
// function resourceIsOwner() {
// return resource.data.owner == request.auth.uid;
// }
function isAdmin() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 1
}
}
You need to pass the database variable as argument in your function like this:
service cloud.firestore {
match /databases/{database}/documents {
// Only 'owners' of data can make changes to data
match /posts/{post} {
allow read: if isAuthenticated();
allow create: if isAuthenticated() && isAdmin(database);
allow update, delete: if isAuthenticated() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 1;
}
}
/// FUNCTIONS ///
function isAuthenticated() {
return request.auth.uid != null;
}
// function requestIsOwner() {
// return request.resource.data.owner == request.auth.uid;
// }
// function resourceIsOwner() {
// return resource.data.owner == request.auth.uid;
// }
function isAdmin(database) {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 1
}
}
I got a firestore like this:
:stores
|
$Store
:orders
|
$Order
:items
I want to read orders from my database using a user having an workerUid same as the request.auth.uid but geht the Error: Missing or insufficient permissions.
The important part of my firebase rules:
service cloud.firestore {
match /databases/{database}/documents {
//Matches any document in the stores collection
match /stores/{store} {
function isStoreAdmin(uid) {
return get(/databases/stores/$(store)).data.adminUid == uid;
}
function isStoreWorker(uid) {
return get(/databases/stores/$(store)).data.workerUid == uid;
}
allow read: if request.auth.uid != null;
allow write: if request.auth.uid == resource.data.adminUid;
//Matches any document in the orders collection
match /orders/{document=**} {
allow read, write: if isStoreAdmin(request.auth.uid) || isStoreWorker(request.auth.uid);
}
}
}
}
Funny thing is, that it works if I do this:
match /orders/{document=**} {
allow read, write: if isStoreWorker(request.auth.uid);
}
or this:
match /orders/{document=**} {
allow read, write: if request.aut.uid != null;
}
When deploying the rules I get no syntax error so I really can't understand why this is not working. Does anyone have any ideas? Thank you so much!
Edit:
function readAllDocuments(collectionReference, callback,finishedCallback){
collectionReference.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
callback(doc.id,doc.data());
});
finishedCallback();
});
}
const storeDocument = getRootCollection(STORES_COLLECTION_ID).doc(storeId);
const orderCollection = storeDocument.collection(STOREORDERS_COLLECTION_ID);
orders=new Map();
readAllDocuments(orderCollection, function (id, data) {
orders.set(id,data);
},function(){
finishedLoading();
});
The documentation for use of get() in a security rule states:
...the path provided must begin with /databases/$(database)/documents
Make these changes to the get() paths:
function isStoreAdmin(uid) {
return get(/databases/$(database)/documents/stores/$(store)).data.adminUid == uid;
}
function isStoreWorker(uid) {
return get(/databases/$(database)/documents/stores/$(store)).data.workerUid == uid;
}