malte238749874
malte238749874

Reputation: 308

Firestore security rules and vuefire

i have the following sample app here: Github repo

It uses vuefire in ChatList.vue

// vuefire firestore component manages the real-time stream to that reactive data property.
firestore() {
    return {
        chats: db.collection('chats').where('members', 'array-contains', this.uid)
    }
},

I now wrote security rules to secure the data, but can't seem to get the combination of vuefire and security rules to work:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
    // THIS IS THE PART I'D LIKE TO REMOVE
    match /chats/{chatId=**} {
      allow read: if request.auth.uid != null;  
    }
    // THIS WORKS AS INTENDED, AND I'D LIKE TO INCLUDE "READ"
    match /chats/{chatId}/{documents=**} {
      allow write: if chatRoomPermission(chatId)
    }
    function chatRoomPermission(chatId) {
      return request.auth.uid in get(/databases/$(database)/documents/chats/$(chatId)).data.members;
    }
  }
}

So the goal is: make the individual chats only readable and writable to users that are in the members array in firestore. (Currently i achieved this partially, since all chats are readable to anyone, but only writable to users in the members array.)

Do i have to rewrite the vuefire component so i can have the following security rule? (It gives an error message: listing of chats not possible due to missing permissions)

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
    match /chats/{chatId}/{documents=**} {
      allow read, write: if chatRoomPermission(chatId)
    }
    function chatRoomPermission(chatId) {
      return request.auth.uid in get(/databases/$(database)/documents/chats/$(chatId)).data.members;
    }
  }
}

For completeness, the working solution is (credits to Renaud Tarnec):

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
    match /chats/{chatId=**} {
      allow read: if request.auth.uid in resource.data.members; 
    }
    match /chats/{chatId}/{documents=**} {
      allow read, write: if chatRoomPermission(chatId)
    }
    function chatRoomPermission(chatId) {
      return request.auth.uid in get(/databases/$(database)/documents/chats/$(chatId)).data.members;
    }
  }
}

Upvotes: 0

Views: 204

Answers (1)

Renaud Tarnec
Renaud Tarnec

Reputation: 83093

Since you want to check, in your Security Rules, if a given value (the user uid in this case) is contained in a field of type Array in your document, you can use the in operator of the List type.

So, the following should do the trick:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
    // THIS IS THE PART I'D LIKE TO REMOVE
    match /chats/{chatId=**} {
      allow read: if request.auth.uid in resource.data.members;
    }

    // ....
  }
}

Upvotes: 1

Related Questions