Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verifying an anonymous user's display name in Firebase realtime database rules

I'm setting a display name for anonymous users, and want to make sure that new values match this set display name. The following rule is failing:

"name": { ".validate": "newData.val() == auth.token.name" }

Why is this? The docs say that the display name is stored in auth.token.name.

Below is a full copy of my firebase rules:

{
    "rules": {
    ".read": false,
    ".write": false,
    "messages": {
        ".read": true,
        "$message": {
            ".write": "auth != null",
            ".validate": "newData.hasChildren(['createdAt', 'text', 'user'])",

            "createdAt": { ".validate": "newData.val() == now" },
            "text": { ".validate": "newData.isString() && newData.val().length > 0" },
            "user": {
                ".validate": "newData.hasChildren(['_id', 'name'])",
                 "_id": { ".validate": "newData.val() == auth.uid" },
                 "name": { ".validate": "newData.val() == auth.token.name" },
            "$other": { ".validate": false }
        },
        "$other": { ".validate": false }
      }
    }
  }
}
like image 894
Allen Avatar asked Feb 01 '18 21:02

Allen


1 Answers

As I've mentioned in the comments (took this from the documentation):

Shallower security rules override rules at deeper paths. Child rules can only grant additional privileges to what parent nodes have already declared. They cannot revoke a read or write privilege.

This means you won't be able to write to your database because you've declared .write:false at the root node of the database. You might want to remove that line to have a structure like this:

{
    "rules": {
    ".read": false,
    "messages": {
        ".read": true,
        "$message": {
            ".write": "auth != null",
            ".validate": "newData.hasChildren(['createdAt', 'text', 'user'])",

            "createdAt": { ".validate": "newData.val() == now" },
            "text": { ".validate": "newData.isString() && newData.val().length > 0" },
            "user": {
                ".validate": "newData.hasChildren(['_id', 'name'])",
                 "_id": { ".validate": "newData.val() == auth.uid" },
                 "name": { ".validate": "newData.val() == auth.token.name" },
            "$other": { ".validate": false }
        },
        "$other": { ".validate": false }
      }
    }
  }
}

The display name is indeed stored under auth.token.name variable. But when you use the default "Anonymous Authentication" on the Rules Simulator, this sends a request with this default auth payload:

{
  "provider": "anonymous",
  "uid": "N4EbtSX5HbM9JLjsW6hWT3NWzAx1"
}

Notice that there's no name specified under this payload, therefore, the auth.token.name variable is null and the security rule denies the write.

You can use your custom payload on the simulator, by simply changing the auth provider from "Anonymous" to "Custom" and it allows you to edit to payload, so you use this one instead:

{
  "provider": "anonymous",
  "uid": "N4EbtSX5HbM9JLjsW6hWT3NWzAx1",
  "token":{
    "name": "Mike"
  }
}

With this auth payload, the data payload you've provided in the comments should work:

{ 
    "createdAt": { 
        ".sv": "timestamp" 
    }, 
    "text": "Test 1", 
    "user": 
    { 
        "_id": "48c83bf9-7354-4720-838f-8b68e0addd51", 
        "name": "Mike"
    }
}
like image 111
Rosário Pereira Fernandes Avatar answered Oct 03 '22 23:10

Rosário Pereira Fernandes