River Tam
River Tam

Reputation: 3216

Deny the deletion of one property on a resource

I'm trying to lock one individual property from being updated or deleted on certain conditions. I've tried this:

allow update if: (
  !('lockedProperty' in request.resource.data)
  || hasPermissionToChangeLockedProperty()
);

However, while this stops people from changing the value of the locked property, it doesn't seem to stop people from deleting the locked property. Specifically:

await firebase.assertFails(doc.update({ lockedProperty: 'fail' }));
await firebase.assertSucceeds(
  doc.update({ lockedProperty: firebase.firestore.FieldValue.delete() }),
);

This test passes.

How can I make the second update fail with the rules?

Upvotes: 0

Views: 33

Answers (1)

Todd Kerpelman
Todd Kerpelman

Reputation: 17523

We cover this in a lot of detail starting at the 21:53 mark of this video, and I would definitely recommend watching the entire thing if you want a better understanding of how security rules work. But to answer your question, you could do this by saying...

allow update if: (
   (request.resource.data.lockedProperty == resource.data.lockedProperty ||
    hasPermissionToChangeLockedProperty())
)

Essentially, you're saying "the value of locked property has to be the same in the document before it was changed and in the document afterwards".

Although if you're going to do this with multiple fields a more general purpose way of doing it would be to say:

allow update if: (
   (!(request.resource.data.diff(resource.data).affectedKeys().hasAny(['lockedProperty'].toSet()))||
    hasPermissionToChangeLockedProperty())
)

Yeah, that first line is a bit of a mess, but you're basically saying, "Create a set of all the keys that have been changed between the original document and the changed one. Then make sure "lockedProperty" isn't one of those keys.

Like I said, you might want to watch the video for a more complete idea of things, but this should get you on the right path...

Upvotes: 1

Related Questions