4
votes

I have a specific need to allow my users to create Firestore documents which match a specific structure, but to not allow those same users from updating that structure upon creation.

To put it simply, I want my users to be able to create new documents but to not update them.

I have the following security rules defined:

service cloud.firestore {
  match /databases/{database}/documents {
    function isAuthenticated() {
      return request.auth.uid != null
    }

    match /conversations/{conversationId} {
      function isParticipant() {
        return resource.data.participants[request.auth.uid] == true
      }

      function NewConversation() {
        // One of the participants must be the current user
        return request.resource.data.participants[request.auth.uid] == true
      }

      allow read, delete: if isAuthenticated() && isParticipant()
      allow create: if isAuthenticated() && NewConversation()
      // allow update: if isAuthenticated() && NewConversation()
    }
  }
}

It turns out, however, that no matter how I attempt to create the document, I always get the telltale permission-denied error. I am quite certain that the document I am trying to save contains the participants map with the current user's Id as a key set to true, just as the rule expects.

I can successfully create the document if I also allow update operation by uncommenting the third rule.

Is this a Firestore bug or am I misunderstanding something?

The documentation (and the clear separation of create and update operations) seems to indicate that this is possible.

For completeness, this is the client request I am making which fails the test:

it('allows creating new conversations', async function() {
  // clients.primary is a Firestore instance authenticated with
  // the primary user used below as a key
  const doc = await clients.primary.collection('/conversations').add({
    participants: {
      [users.primary.uid]: true,
      [users.secondary.uid]: true,
    },
  })
})
1
found any solution?iMDroid

1 Answers

0
votes

Try:

function isAuthenticated() {
  return request.auth != null && request.auth.uid != null
}

If your request doesn't contain an "auth", firebase will crash and could return a permission violation.