1

For the past few weeks i've been exploring Firebase and its features to build a web app, but I've kind of ran into a wall when it comes to security rules.

I've build a data structure on Firebase but I'm not sure if it follows best practices (if it doesn't, feel free to suggest anything different about it):

{   
 "groups" : {
    <GROUP_KEY>
        "name": "",
        "rels": {
            "users": {
                <RELS_USERS_KEY>
                "key":"" (USER_KEY)
            },
            "notes": {
                <RELS_NOTES_KEY>
                "key":"" (NOTE_KEY)
            }
        },
        "isPrivate": true 
},

"users": {
    <USER_KEY>
    "email": "",
    "rels": {
        "friends": {
            <RELS_FRIENDS_KEY>
            "key":"" (USER_KEY)
        }
    },
},

"notes": {
    <NOTE_KEY>
        "title": "",
        "description": "",
        "rels": {
            "files": {
                <RELS_FILES_KEY>
                "key":"" (FILE_KEY)
            }
        }
},

"files": {
    <FILE_KEY>
        "mode": "",
        "url": ""
}
}

The application flow is as follows:

  • The user signs up: a key is created on "users";
  • Is redirected to "Groups" view, where he should be shown only groups that have his ID in RELS > USERS, or that has "isPrivate":"false";
  • As the user creates a Group, a new group is added with his ID in RELS > USERS;
  • Entering the Group view, he should only see notes that are in RELS > NOTES for that group.

The rest of the logic follows the same principle, and I believe that if I can get through the first hurdle of understanding the Firebase security rules and applying them to this case, I can get through the rest.

I've tried a couple of rules, but I can't seem to get any feedback at all from the web application, debugging this has been a trial-and-error process, and its not really working.

Could someone help me at least understanding the logic behind it ? I've read all of their tutorials but they all seem very shallow with no deeper examples on complex structures.

Thanks for the help.

EDIT

I've added the debug:true flag to the login (thanks @Kato), but I'm still getting no feedback on the rules. With the rules as below, I still enter the "Groups" view, but get no feedback on the console, and the logged-in user sees groups he shouldn't:

{
"rules": {
  "groups": {
    ".read": "data.child('rels').child('users/' + auth.user).exists()",
    ".write": "data.child('rels').child('users/' + auth.user).exists()"        
  }
}
}

As for the rules I've tried, they were countless, but this is the most recent one (still no feedback).

Maybe I'm missing something ?

Thanks again.

jsfrocha
  • 1,812
  • 2
  • 21
  • 32
  • To get feedback on your rules, go to the simulator in Forge (type your Firebase URL into the browser). You can also create a token with `debug: true` and achieve the same effect on the client. More on that in the custom login docs. – Kato Jun 22 '14 at 15:29
  • On the simulator, what is the format of the JSON used for "Custom Auth" ? Is it the same as the Simple Login `user` returned object ? **EDIT**: Nevermind, i've added the `debug:true` flag to the login, but what should I expect to see? Nothing happens in the console. – jsfrocha Jun 22 '14 at 15:34
  • `debug:true` will only work with custom tokens, not with simple login, [see here](https://www.firebase.com/docs/security/custom-login.html). For simulator, whatever you put into custom auth will be available in the auth object to security rules. You should try console.log(user) on the object you get back from simple login, then match that in simulator. – Kato Jun 22 '14 at 18:12
  • I've thrown a couple of shots at the Simulator, but still no success.. The Simulator only says if theres any syntax error (fairly useful but not needed here) or if the rule passes or fails (i can see that by reloading my web app..). I needed something that could tell my more, something like where my rules are pointing to :\ – jsfrocha Jun 22 '14 at 20:31
  • Simulator will tell you *which* rule allowed the write, which is the one under rules, not the one under rules/groups. I can see this now; was thrown off by the formatting on first read. – Kato Jun 23 '14 at 01:37

1 Answers1

0

Rules cascade. That is, if any rule allows read, then you cannot revoke it later in a nested child. In this way, you can write rules like the following:

"$record": {
   // I can write the entire record if I own it
   ".write": "data.child('owner').val() === auth.uid",

   "foo": {
       // anybody in my friends list can write to foo, but not anything else in $record
       ".write": "data.parent().child('friends/'+auth.uid).exists()"
   },

   "bar": {
       // this is superfluous as permissions are only "granted" and never "revoked" by a child
       ".write": false
   }
}

Note how, because I am the owner, I can also write to foo and to bar, even though bar has tried to revoke my read privilege.

So in your case above, your rules declaration lists read: true which allows full read access to the entire repo. Change that to false and you'll see better results.

Kato
  • 40,352
  • 6
  • 119
  • 149
  • Hi, thanks for the answer and sorry for the delay in commenting, but I've been very busy.. Now my problem is with my version of `child('friends/'+auth.uid)`. Apparently a valid URL is something like `'friends/KEY'` with `KEY` being something like `-JQ07CRJ-hsk0wfFExun`. `auth.uid` doesn't return a `KEY` like that, am I right ? So how can I identify those keys (or iterate) through the rules ? I'm beginning to think my problem is in the Data Structure I chose to represent the relationships.. any suggestions ? Thanks **EDIT** I've changed my rules JSON (I mistakenly had rules in the root) – jsfrocha Jun 25 '14 at 13:24
  • child('friends/'+auth.uid) should work fine. You probably need to call .val() on that before you can compare it to anything. – Kato Jun 25 '14 at 16:57
  • Thanks for the patience in addressing this, but I'm still too confused, and the rules I've been trying do not seem to work. Maybe I'm still looking at the problem the wrong way. I've asked another [question](http://stackoverflow.com/questions/24472074/how-to-provide-user-access-to-groups-firebase-security-rules), which is much simpler I reckon. I thought I'd ask it because maybe I need to start smaller. – jsfrocha Jun 29 '14 at 15:59