1
votes

I'm working on an app where you can follow/unfollow other app users. So in firestore i've got a collections of users, and each user contains a property named followers. Followers is an array of userId's.

Like this:

"users": {
    "user1": { 
        "name": "Jack", 
        "imageUrl": "http://lorempixel.nl",
        "followers": ["user1", "user2"]
    }
}

Question

How to write a security rule in firestore, so only the current user can read/write their own object, but others can add/delete their user id to the array of followers.

1

1 Answers

3
votes

To enable people to follow/unfollow users this set of security rules should work on your data structure. The base means they cant change the other data and there are 3 rules that:

  1. Allow them to add themselves, it means that a user can add their uid to the followers list but cant remove others
  2. Allows them to remove their uid but no one elses
  3. If they happen to update the document once they follow they cant modify it.

    service cloud.firestore {
    
        match /databases/{database}/documents {
    
            match /users/{userId} {
            allow update: if 
                resource.data.name == request.resource.data.name &&
                resource.data.imageUrl == request.resource.data.imageUrl &&
                request.resource.data.size() == resource.data.size() &&
                ( 
                    (
                        // If user adding their uid
                        request.resource.data.followers.hasAll(resource.data.followers) &&
                        request.resource.data.followers.hasAll([request.auth.uid]) &&
                        request.resource.data.followers.size() == resource.data.followers.size() + 1
                    ) || 
                    (
                        // If user removing their uid
                        resource.data.followers.hasAll(request.resource.data.followers) &&
                        resource.data.followers.hasAll([request.auth.uid]) &&
                        !request.resource.data.followers.hasAll([request.auth.uid]) &&
                        request.resource.data.followers.size() == resource.data.followers.size() - 1
                    ) || 
                    (
                        // If user tries updating whilst already a follower
                        request.resource.data.followers.hasAll(resource.data.followers) &&
                        request.resource.data.followers.size() == resource.data.followers.size()
                    )
                )
            }
        }
    }
    

I have tested it in the rules simulator in the Firebase Console so should all work but please do extensive testing. It feels very hacky and definitely would be good to have specific rules to support array removals but this should do it in the meantime I believe.