I have data in firebase in following format -
"requests" : {
"-KpPjt5jQZHBalQRxKSK" : {
"email" : "pariksheet#agsft.com",
"itemId" : "-KmazkKp5wavdHOczlDS",
"quantity" : 1,
"status" : "new"
},
"-KpZsw3KHE9oD1CIFQ4R" : {
"email" : "pbarapatre#gmail.com",
"itemId" : "-Kmb-ZXfao7VdfenhfYj",
"quantity" : 1,
"status" : "new"
}
}
Every request contains
"email" <- user's email id who has initiated the request.
"itemId" <- id of requested item
"quantity" <- item quantity
"status" <- "new" | "approved" | decline.
I am struggling to write Firebase rule which would:
allow authenticated user to access/read only requests which are raised by him/her.
allow admin user to read/update all requests.
My current rule is as follows :
{
"rules": {
".read": false,
".write": false,
"items" : {
".read": "auth != null",
".write": "root.child('roles').child(auth.uid).val() === 'admin'"
},
"requests": {
".write": "root.child('roles').child(auth.uid).val() === 'admin'", /*Only Admins can update request*/
"$rId": {
".read": "data.child('email').val() == auth.email || root.child('roles').child(auth.uid).val() === 'admin'"/*Request owner and admin can only read the particular request*/
}
}
}
}
I have maintained separate node roles which has
{
"uid" : "role"
}
I am using AngularFire2 to query Firebase in my app.
Sample code to retrieve requests with given status as below
const queryList$ = this.db.list('/requests', {
query: {
orderByChild: 'status',
equalTo: status
}
})
Thanks
Pari
I suggest you make the following changes:
In the root of the database create a new object admins
"admins": {
"<ADMIN_1_UID>": "true",
"<ADMIN_2_UID>": "true"
}
Then make changes to your security rules like this:
"rules": {
"admins": {
".read": false,
".write": false /*This ensures that only from firebase console you can add data to this object*/
},
"requests": {
".read": "root.child('admins').child(auth.uid).val()",
".write": "root.child('admins').child(auth.uid).val()", /*Only Admins can read/update all requests*/
"$rId": {
".read": "data.child('email').val() == auth.email"/*Request owner can read only the particular request*/
}
}
}
Related
I've the follwing database:
actions : [ {
"added" : 1535293085383,
"countdown" : 9999999999,
"item" : 1,
"type" : "a"
}, {
"added" : 1535293085383,
"countdown" : 999999999,
"extra" : "bb",
"item" : "2",
"type" : "b"
}, {
"added" : 1635293085383,
"countdown" : 1,
"item" : 3,
"type" : "c"
}]
I want to any logged user be able to read all data, but ONLY WRITE THE COUNTDOWN NODE.
My idea is everytime users read the data decrement that value, but they are not allowed to update any other node
there are the rules i wrote
{
"rules":{
".read":false,
".write":false,
"actions":{
".indexOn":[
"added"
],
".read": "auth != null",
"countdown":{
".write" : "auth != null"
}
}
}
it is denying read from unauthenticated users
it is allowing to read from authenticated users
it is dennying to write from authenticated users EVEN in the countdown node
how can i fix it
You're missing a level in your security rules. Right now you allow writing to /actions/countdown. But you want to allow writing to /actions/*/countdown. To capture that requirement, use a $ variable in your rules:
{
"rules":{
".read":false,
".write":false,
"actions":{
".indexOn": [ "added" ],
".read": "auth != null",
"$actionid": {
"countdown":{
".write" : "auth != null"
}
}
}
}
Now because of the $actionid the countdown/.write rule under there applies to each child node of /actions.
My data in firebase looks like this, in my web app everyone who accesses it gets authenticated anonymously via firebase, and their UID is stored with every post the user creates:
"-KF5N2V_dKD1dMHebUqc" : {
"note" : "Hello everybody",
"pos" : {
"lat" : 40.3628851,
"lng" : -74.0493175
},
"time" : 1460395853884,
"uid" : "f8cf7863-5607-4e2b-97d7-6a121261466c"
},
"-KHwyP-tnWNOA3nxzEm4" : {
"note" : "hi",
"pos" : {
"lat" : 37.0947156,
"lng" : -121.0179501
},
"time" : 1463459362615,
"uid" : "f8cf7863-5607-4e2b-97d7-6a121261466c"
}
I want my firebase rules setup so that only anonymous users can delete their through own posts.
So far i was only able to come up with this after reading the firebase documentation:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"$msg": {
".validate": "newData.hasChildren(['note','time','uid','pos'])
&& newData.child('note').isString() && newData.child('time').isNumber()
&& newData.child('uid').isString() && newData.child('note').isString()
&& newData.child('pos/lat').isNumber() && newData.child('pos/lng').isNumber()"
}
}
}
You'll need to move the .write permission down and tie it to the data:
{
"rules": {
".read": "auth != null",
"$msg": {
".write": "!data.exists() || (!newData.exists() && data.child('uid').val() === auth.uid)"
".validate": "..."
}
}
}
It's a bit of mix-and-match from these two sections of the Firebase documentation:
https://www.firebase.com/docs/security/guide/securing-data.html#section-data-variables
https://www.firebase.com/docs/security/guide/user-security.html
data
{
"padlock": {
"open": 1432206070000
},
"boxes": [
{"owner": "bob", "amount": 23},
{"owner": "luca", "amount": 13},
{"owner": "louise", "amount": 4},
{"owner": "anna", "amount": 34}
]
}
security rules
{
"rules": {
"boxes": {
".read": "auth !== null",
".write": "auth !== null && root.child('padlock').child('when').val() > now - 15000"
}
}
}
Read and write to boxes is only for authenticated user.
Modification of boxes values only if the padlock is open less than 15 second ago.
To open the padlock for 15 seconds, just update the value with the current time.
How can i protect the padlock with a second simple auth layer? (like a client side pin code)
Is the only way to use privileged worker?
Web client securely send the pincode to the privileged worker. The worker will check the code and update the open timestamp. Add a security rule so only the worker as exclusive access to 'open'
Any idea?
I Think i found a solution just using security rules
how to protect some data from write access with a password based lock (like a pin code)
DATA
{
"boxes" : [
{"amount" : 23},
{"amount" : 11},
{"amount" : 34},
{"amount" : 3}
],
"key" : {
"oldPassword" : "xxxxxxx",
"password" : "xxxxxxx"
},
"lock" : {
"password" : "xxxxxxx",
"open" : 1432292525055
}
}
RULES
{
"rules": {
"key": {
// nobody can read the key
".read": false,
// only people who know the key can change it
// if no key exists you can stil create it
".write": "data.child('password').val() === newData.child('oldPassword').val() || !data.exists()",
// password (string) must exists and be different than the old one
".validate": "newData.child('password').isString() && newData.child('oldPassword').isString() && newData.child('password').val() !== newData.child('oldPassword').val()"
},
"lock": {
// nobody can read the lock
".read": false,
// only people knowing the key can create the lock
// to prevent partial write (without the password), only create and delete are authorized (no data update)
".write": "(!data.exists() && root.child('key').child('password').val() === newData.child('password').val()) || !newData.exists()",
// open is the creation time
".validate": "newData.child('open').val() === now"
},
"boxes": {
".read": "true",
// write only allowed for 15 sec after the padlock is open
".write": "root.child('padlock').child('open').val() > now - 15000"
}
}
}
I have a data structure that adds user's data to their unique id such as follows.
"users" :
{
"user_id":
{
"name":"John Doe",
"email":"email#example.com",
"account":"limited",
"avatar" : "this will be a base64 data string"
}
}
I want to deny users from listing other users and I also want logged in users to access their data based on their "user_id" which is gotten from auth.uid
I had tried some rules:
{
"rules" :
{
"users" :
{
".read" : "false",
".write" : "auth != null && !data.exists() && newData.exists() ",
".validate" : "newData.child('user_id').hasChildren(['name', 'email', 'account','avatar'])",
"user_id" :
{
".read" : "auth.uid === user_id",
".write" : "false",
"avatar" :
{
".write" : "!data.exists() && newData.exists() && auth.uid === user_id",
".read" : "auth.uid === user_id"
}
}
}
}
}
Now keeping in mind that "user_id" can be anything and it changes per user, how can I implement that? Do you have other suggestions on a way I can work this out?
You need to take a close look at the Firebase documentation found here: https://www.firebase.com/docs/security/guide/user-security.html
You need to make use of the wildcard path to represent each user like this:
{
"rules": {
"users": {
"$user_id": { //this is the WILDCARD path
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
Wildcard paths explanation: https://www.firebase.com/docs/security/api/rule/path.html
Finally, I wouldn't recommend storing the email in this way because it will be available anyway via simpleLogin.
In my Firebase security rules, I want anonymous users to be able to read anything except one field (secret_field):
{
"rules": {
".read": true,
".write": "auth != null",
"stuff" : {
"$stuffID" : {
"secret_field" : {
".read" : "auth != null"
}
}
}
}
}
However, in Firebase, if any read rule on the way to secret_field evaluates as true, read access on secret field is granted.
Is there a way to reverse that behavior? (If any read rule on the way to secret_field evaluates to false, disallow read access)
You can't reverse the behavior, but you can solve this by introducing a "container" for the public fields and setting .read to true for it. For example:
{
"rules": {
"stuff" : {
"$stuffID" : {
"public" : {
".read": true
},
"secret_field" : {
".read" : "auth != null"
}
}
}
}
}
And then everything under .../public/ is accessible to everybody but .../secret_field is only accessible for authenticated users.