2

My basic question is how do you setup Firebase rules to only allow access certain leaf nodes from their parent?

Lets say I have data that looks like this:

root: {
  posts: {
    post1: {
      user: "foo",
      post: "this is a post",
      restricted: false
    },
    post2: {
      user: "bar",
      post: "this is another post",
      restricted: true
    },
    post3: {
      user: "bar",
      post: "this is my final post",
      restricted: false
    }
  }
}

I want to $bind to the posts node and get all the posts which that user is allowed to get. I might want the admin to access all of the posts but non-admins to only be able to access post1 and post3.

Note: I'm using angularFire's $bind to synchronize nodes.

I don't believe this is possible but I would like to be able to set up my rules kinda like this:

{
  "rules": {
    "posts": {
      ".read": "auth.admin || $post.hasChild('restricted').val() !== true",
      "$post": {
      }
    }
  }
}

How are other users accomplishing this? Thanks.

yodaisgreen
  • 2,310
  • 3
  • 22
  • 27

2 Answers2

3

You can use the data.hasChild expression to achieve this:

{
  "rules": {
    "posts": {
      ".read": "auth.admin || data.hasChild('restricted').val() !== true"
    }
  }
}

However, this is not the recommended approach and won't work in practice. Security rules are not a good fit for filtering data based on access - you'll see permission denied errors in the console because angularFire will try to read all the posts from /blog and it will fail.

Instead, each user should know which posts they have access to and only fetch those directly. You can use push() (or $add in angularFire) to generate random post IDs and set the security rules such that you can access the data if you know the post ID, for example.

yodaisgreen
  • 2,310
  • 3
  • 22
  • 27
Anant
  • 7,408
  • 1
  • 30
  • 30
  • If I bind to posts using the first method you described I would only get the children that user has access to and get a few access denied messages for the children I don't have access to? What's wrong with that besides the messy console? That seems like the cleanest way to do this. Based on your alternative suggestion I think I would have to maintain an alternate structure that mirrors my data that allows full read access and stores all the permissions for all my data. That seems like it adds allot of complexity to what should be pretty simple and very common use case. Am I missing something? – yodaisgreen Jan 12 '14 at 17:59
  • You won't actually receive any children at all, even if some are readable - again - security rules are not meant to filter items. – Anant Jan 13 '14 at 16:58
0

I believe the canonical way to do that is to place a rule directly on the element to be read, not on the collection.

{
  "rules": {
    "posts": {
      "$post": {
        ".read": "auth.admin || data.hasChild('restricted').val() !== true"
      }
    }
  }
}
Titou
  • 968
  • 10
  • 16