user-data-protection icon indicating copy to clipboard operation
user-data-protection copied to clipboard

Generated wipeout rule contained special characters and caused errors

Open rachelmyers opened this issue 7 years ago • 0 comments

Given the database rules below, we generated rules that contained $, which caused an error when the function ran. The rules are complicated enough that we might want to gracefully degrade.

Database rules:

{
  "rules": {
    "feed": {
      "$uid": {
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid",
        "$postId": {
          ".validate": "newData.val() === true && newData.parent().parent().parent().child('posts').child($postId).exists()"
        }
      }
    },
    "posts": {
      ".read": true,
      "$postId": {
        ".write": "!data.exists() || data.exists() && auth.uid === data.child('author').child('uid').val()", // Allow new writes and allow updates and deletes to own posts.
        "author": {
          "uid": {
            ".validate": "auth.uid === newData.val()"
          }
        }
      }
    },
    "comments": {
      ".read": true,
      "$postId": {
        ".write": "!newData.exists() && auth.uid === root.child('posts').child($postId).child('author').child('uid').val() && !newData.parent().parent().child('posts').child($postId).exists()", // Allow deletes from the post owner
        ".validate": "root.child('posts').child($postId).exists()", // Check that the post exists
        "$commentId": {
          ".write": "!data.exists() || data.exists() && auth.uid === data.child('author').child('uid').val()",  // Can write new comments and edit/delete particular comment if you are the author.
          "author": {
            "uid": {
              ".validate": "auth.uid === newData.val()"
            }
          }
        }
      }
    },
    "likes": {
      ".read": true,
      "$postId": {
        ".write": "!newData.exists() && auth.uid === root.child('posts').child($postId).child('author').child('uid').val() && !newData.parent().parent().child('posts').child($postId).exists()", // Allow deletes from the post owner
        ".validate": "root.child('posts').child($postId).exists()", // Check that the post exists
        "$uid": {
          ".write": "auth.uid === $uid",
          ".validate": "newData.val() === now"
        }
      }
    },
    "followers": {
      ".read": true,
      "$followedUid": {
        "$followerUid": {
          ".write": "auth.uid === $followerUid", // Can only add yourself as a follower
          ".validate": "newData.val() === true && newData.parent().parent().parent().child('people').child($followerUid).child('following').child($followedUid).exists()" // Makes sure /people/.../following is in sync
        }
      }
    },
    "people": {
      ".indexOn": ["_search_index/full_name", "_search_index/reversed_full_name"],
      ".read": true,
      "$uid": {
        ".write": "auth.uid === $uid",
        "full_name": {
          ".validate": "newData.isString()"
        },
        "profile_picture": {
          ".validate": "newData.isString()"
        },
        "posts": {
          "$postId": {
            ".validate": "newData.val() === true && newData.parent().parent().parent().parent().child('posts').child($postId).exists()"
          }
        },
        "_search_index": {
          "full_name": {
            ".validate": "newData.isString()"
          },
          "reversed_full_name": {
            ".validate": "newData.isString()"
          }
        },
        "following": {
          "$followedUid": {
            ".validate": "newData.parent().parent().parent().parent().child('followers').child($followedUid).child($uid).val() === true" // Makes sure /followers is in sync
          }
        }
      }
    },
    "$other": {
      ".validate": false
    }
  }
}

Generated wipeout rules:

{ "path": "/feed/#WIPEOUT_UID" }
{ "except": "/comments/$postId/$commentId", "path": "/comments/$postId" }
{ "except": "/likes/$postId/$uid", "path": "/likes/$postId" }
{ "path": "/people/#WIPEOUT_UID" }
{ "path": "/followers/$followedUid/#WIPEOUT_UID" }

Error from running the function:

Error: Firebase.child failed: First argument was an invalid path: "comments/$postId". Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"     at Error (native)     at Ge (/user_code/node_modules/firebase-admin/lib/database/database.js:111:59)     at R.h.n (/user_code/node_modules/firebase-admin/lib/database/database.js:243:178)     at Fd.h.gf (/user_code/node_modules/firebase-admin/lib/database/database.js:91:631)     at evalSingleExcept (/user_code/wipeout.js:219:30)     at evalExcepts (/user_code/wipeout.js:266:23)     at Promise.all.then.then.then.then (/user_code/wipeout.js:585:24)     at process._tickDomainCallback (internal/process/next_tick.js:135:7)
--

rachelmyers avatar Nov 09 '17 21:11 rachelmyers