I have this set of rules in firestore
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document} {
allow read: if true;
allow write: if isTrustworthy();
}
match /stores/{storeId}{
match /{document} {
allow read: if true;
allow write: if isTrustworthy();
}
match /departures/{departureId} {
allow read: if true;
allow write: if !(resource.data.locked);
}
}
function isTrustworthy(){
return isSignedIn() && emailVerified();
}
function isSignedIn() {
return request.auth != null;
}
function emailVerified() {
return request.auth.token.email_verified;
}
}
}
but I get an error when setting, updating or deleting in the departures path.
eg.
this.afs.collection('stores').doc(this.auth.store)
.collection('departures')
.doc(element.shipping.trackingNumber.toString())
.set({"test":true})
the document is not existent, but it won't work neither if the document exist, independent of the parameter "locked" I got the following error:
ERROR Error: Uncaught (in promise): FirebaseError: [code=permission-denied]: Missing or insufficient permissions.
FirebaseError: Missing or insufficient permissions.
What I need is that if the document has a parameter "locked" set to true, it cannot be deleted, updated, nor set with {merge:true} option.
any help will be much appreciated.
CodePudding user response:
There are a few issues with your rule and code:
- On
create
,resource.data
does not exist - On
update
ordelete
, it could be that the fieldlocked
does not exist - When you use
set
to create or update a document in Firestore, you have to add the options{merge: true}
, to update the document instead of overwriting it in case it already exists.
Try this instead:
Code:
this.afs.collection('stores').doc(this.auth.store) .collection('departures') .doc(element.shipping.trackingNumber.toString()) .set({"test":true}, {merge: true})
Rules:
match /departures/{departureId} { allow read: if true; allow create: if true; allow update, delete: if !resource.data.get("locked", false); }
CodePudding user response:
I add a set of functions to my rules to make writing rules like this easier:
function existing() {
return resource.data;
}
function resulting() {
return request.resource.data;
}
function matchField(fieldName) {
return existing()[fieldName] == resulting()[fieldName];
}
resource
refers to the document being accessed, and request.resource
refers to the new data for the document. With these you can refer to values on the existing or incoming document.
The matchField
is useful in combination with various claims/Roles protect parts of the document(s) from being changed.
In your case you can check the status of a specific field "locked
", for example some form of:
match /whatever/points/to/the/doc {
allow write: if !existing().locked
}
(I use a couple dozen such functions MOSTLY to make my rules almost look like text)