Home  >  Q&A  >  body text

Firestore rules deny every request to chat applications with nested collections. What did I do wrong?

I'm currently building a chat app and I'm having trouble with Firebase rules. I want to limit users from seeing conversations they are not a part of. However, when I try to implement these rules, access seems to be denied even after checking to see if the conversation exists. How do I properly configure Firebase rules to allow users to view only the conversations they are a part of, rather than all conversations in the database?

This is the ruleset I'm trying to implement only for conversations.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    
    // Allow users to read and write their own participant documents
    match /conversation/{conversationId}/participants/{userId} {
      allow read, write: if request.auth.uid == userId;
    }

    // Allow users to read and write messages in a conversation they are a participant of
    match /conversation/{conversationId}/messages/{messageId} {
      allow read, write: if exists(/databases/$(database)/documents/conversation/$(conversationId)/participants/$(request.auth.uid));
    }

    // Allow users to read and write their own conversation documents
    match /conversation/{conversationId} {
      allow read, write: if exists(/databases/$(database)/documents/conversation/$(conversationId)/participants/$(request.auth.uid));
    }
  }
}

Access has been denied at the "top level", which is this part:

// Allow users to read and write their own conversation documents
    match /conversation/{conversationId} {
      allow read, write: if exists(/databases/$(database)/documents/conversation/$(conversationId)/participants/$(request.auth.uid));
    }

I think it has something to do with the way these nested conversations work, but I don't know what I have to change. I tried reading about this in the google firebase documentation but couldn't find anything related to this. If you have any ideas how to fix this please let me know. Thanks!

I've tried getting it to work with multiple "rule sets". It always fails at exists() function.

I also tried this, but that doesn't seem to work either:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    function isUserInParticipants(conversationId) {
      return get(/databases/$(database)/documents/conversations/$(conversationId)/participants/$(request.auth.uid)).data != null;
    }

    match /conversations/{conversationId} {
      allow read, write: if request.auth != null && isUserInParticipants(conversationId);

      match /messages/{messageId} {
        allow read, write: if request.auth != null && isUserInParticipants(conversationId);
      }
    }
  }
}

This is the query I use in Vue.js:

init() {
      const storeAuth = useStoreAuth();
      conversationCollectionRef = collection(db, 'conversation')
      conversationCollectionQuery = query(conversationCollectionRef) 
      this.getConversations()
    },
    async getConversations() {
      this.coversationsLoaded = false
      getConversationSnapshot = onSnapshot(conversationCollectionQuery, (snapshot) => {
        console.log('getConversations')
        console.log(snapshot)
        this.conversations = []
        snapshot.forEach((doc) => {
          this.getMessagesOfConversation(doc.id)
          const conversation = {
            id: doc.id,
            ...doc.data(),
          }
          this.conversations.push(conversation)
        })
      })
      this.coversationsLoaded = true
    },

P粉627136450P粉627136450407 days ago503

reply all(1)I'll reply

  • P粉459578805

    P粉4595788052023-09-09 14:03:04

    You have not shared the running query that triggered this failure, but it is important to remember that Firestore rules are not filters .

    If your query is like this:

    firestore.collection("conversation").get()

    If you expect Firestore to only return conversations where the rule evaluates to true, then this won't work. Firestore will discover that some conversation documents will not evaluate to true and the entire query will fail .

    You need to make sure that the query you run that causes the rule to evaluate only looks at conversations where the rule evaluates to true, for example:

    firestore.collection("conversation").where(<some condition>).get()

    You can check the official Firestore rules document.

    reply
    0
  • Cancelreply