user-data-protection
user-data-protection copied to clipboard
Generated wipeout rule contained special characters and caused errors
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)
--