Ad

Firestore Database Rule Works In Simulator, But Not In App

I'm building out a React Native application and just starting to build out all of the security rules in my Firestore database. I have several rules that are working well, but there's one rule that's pretty much identical to the working ones that's giving me Error: Missing or insufficient permissions. What's even weirder is that when I test this rule in the Firestore simulator, it passes without any issues.

I've tried shoving all of the conditional logic from the functions into the rule itself, but that did nothing.

Here are the relevant rules:

service cloud.firestore {
  match /databases/{database}/documents {
    function getCurrentTeam() {
        return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.lastTeam;
    }

    function signedIntoTeam() {
      // For context, all "like" documents have an associated teamId.
      return request.auth.uid != null && getCurrentTeam() == resource.data.teamId;
    }

    match /likes/{like} {
      allow read: if signedIntoTeam();
    }

  }
}

Here's the function in my React Native app that's erroring out:

const getLikes = posts =>
    new Promise((resolve, reject) => {
        const likedPosts = [];
        if (!posts.length) return resolve(likedPosts);
        posts.forEach(post => {
            if (post.likeCount > 0) {
                firebase
                    .firestore()
                    .collection('likes')
                    .where('postId', '==', post.id)
                    .where('userId', '==', firebase.auth().currentUser.uid)
                    .get()
                    .then(querySnapshot => {
                        const likedByUser = querySnapshot.size > 0;
                        likedPosts.push({ ...post, likedByUser });
                        if (likedPosts.length === posts.length) resolve(likedPosts);
                    })
                    .catch(err => reject(err));
            } else {
                likedPosts.push({ ...post, likedByUser: false });
                if (likedPosts.length === posts.length) resolve(likedPosts);
            }
        });
    });

I have very similar functions and rules that work fine elsewhere. I just can't seem to figure out why this one in particular is failing.

Ad

Answer

Your rule is attempting to filter documents from the likes collection based on the contents of the document's teamId field. If your query does not also filter using this same criteria, the rule will always reject the request. This is because security rules are not filters. Please read the linked documentation.

With the rule you have in place, the client is always going to have to filter on the teamId field. Right now, it is just filtering on postId and userId. You should add teamId to that, or change the rule to match the query. The query and the rule need to be in sync - the query must only request documents that is knows to be readable by the rule - it should not rely on the rule to make changes to the result set.

Ad
source: stackoverflow.com
Ad