My users will increment a value in the database by 10. I have tried to copy the exact example from documentation but I am still getting
"Simulated write denied"
in the testing console.
Here are my rules:
{
"rules": {
"my-app": {
"myapp": {
".read": "auth != null",
".write": "auth != null && newData.exists() && newData.val() === data.val() + 1",
// Only authenticated users can read and write
// and Prevents only Delete
"totalbyallusers": {
".validate": "newData.isNumber()"
},
}
}
}
}
If I remove newData.val() === data.val() + 1 then it works. I have also tried moving newData.val() === data.val() + 1 to "totalbyallusers" but to no avail. Basically I want that data should only be updated if it's incremented by 10. Or, less preferably, if it is not possible then it can be validated if it ends with a zero. What can I do?
The location is set to /my-app/myapp/ and the data is this:
{
"totalbyallusers" : 230
}
I have also tried changing location to /my-app/myapp/totalbyallusers but the result is same.
Here is the rule to apply to your variable:
"totalbyallusers": {
".validate": "newData.isNumber()",
".read": "auth != null",
".write": "auth != null && (newData.val() != null && data.val() != null && newData.val() == data.val() + 10 || data.val() == null && newData.val() == 10)"
}
You are applying rule to parent instead of the actual variable you need. Try this hopefully it will work.
Ok so I found out that I was using "my-app" as the top-most parent, whereas "my-app" was the project name and was appearing on my Data tab in Firebase but was not included in the actual JSON. So I commented it out and used the same +10 technique and this time it worked!
Thank you all users who helped me in this. Here is the code which works:
{
"rules": {
// "my-app": {
"myapp": {
".read": "auth != null",
".write": "auth != null",
// Only authenticated users can read and write
"totalbyallusers": {
".validate": "newData.val() === data.val() + 10"
}, // newData.val() % 10 === 0 // this also works but is not very safe.
}
// }
}
}
Related
I have checked the documentation but I am not sure how to apply that rule to my specific data structure, please check how my data is organized and provide me the rules as it is supposed to go.
I am using realtime Database, in my app code I write and read base on the user ID, but firebase keeps telling I should change my rules.
To apply the rules in the documentation on content-owner only access to your structure would take:
{
"rules": {
"Expenses": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth != null && auth.uid == $uid"
".write": "auth != null && auth.uid == $uid"
}
},
"Users": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth != null && auth.uid == $uid"
".write": "auth != null && auth.uid == $uid"
}
}
}
}
I created my app with the following database structure
Root/
Users/
+12345566777
+12345667765
+43223456677
And here it is an example of my security rules
{
"rules": {
"$uid": {
"Users": {
".read": "auth != null",
".write": "auth != null && auth.uid == $uid"
}
}
}
}
My problem is that instead of verifiying the auth.uid inside of my security rules i want to verify the (identifiant) the UserPhoneId is there any way to do that, thank you.
I'm developing an Android app using Firebase Realtime Database.
My project contains 3 distinct databases:
Database 1: for common items;
Database 2: for feature A;
Database 3: for feature B;
In database 1, I'm able to create rules (working for this database) using its nodes to validate if specific user is able to read and write any data, for instance:
{
"rules":
{
"plants":
{
".read": true, /*"auth !== null",*/
".write": "auth !== null && root.child('userRegistration/' + auth.uid).child('profileTypeInfo').val()=='0'"
},
"criteria":
{
".read": "auth !== null",
".write": "auth !== null && root.child('userRegistration/' + auth.uid).child('profileTypeInfo').val()=='0'"
},
"guide":
{
".read": "auth !== null",
".write": "auth !== null && root.child('userRegistration/' + auth.uid).child('profileTypeInfo').val()=='0'"
},
"userRegistration":
{
".read": true,
".write": true
},
"report" :
{
".read": "auth !== null && root.child('userRegistration/' + auth.uid).child('isActiveInfo').val()==true",
".write": "auth !== null && root.child('userRegistration/' + auth.uid).child('isActiveInfo').val()==true",
}
}
}
For this Database is OK, because I'm using the root.child of the current database. The issue is related to database A and B, because I'd like to use something like this:
database1.child('userRegistration/' + auth.uid).child('profileTypeInfo').val()=='0'"
instead of using
root.child('userRegistration/' + auth.uid).child('profileTypeInfo').val()=='0'"
In other words, I need using the child data from the database 1 despite of using the root child, which not contains the child userRegistration
I do appreciate your help!
I am trying to extend a social android aap, currently its rules are public, its data structure is something like this,
{
"posts" : {
"postId1" : {
"authorId" : "abcd",
},
"postId2" : {
"authorId" : "abcd",
},
"postId3" : {
"authorId2" : "wxyz",
},
"postId4" : {
"authorId2" : "wxyz",
}
}
}
I want to allow an authenticated user to create and delete his own post in "posts" node
I tried this,
{
"rules": {
".read":"auth.uid != null",
".write":false,
"questions": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}}
But this does not allow a user to create a post although a user can edit or delete his pre-existing post in "posts" node, it seems that there is no write permission within the "posts" node.
But if i allow write permission for "posts" then due to cascading rules, every authenticated user can access other's data. How can I achieve my desired functionality?
First please see firebase-bolt for writing rules for real time database: https://github.com/firebase/bolt
This tool makes it easy to write rules.
And for your rules here is a sample which will allow only the author to update post:
{
"rules": {
".read": "auth.uid != null",
"posts": {
"$postId": {
".write": "data.val() == null && newData.child('uid').val() == auth.uid || data.val() != null && newData.val() != null && data.child('uid').val() == auth.uid || data.val() != null && newData.val() == null && newData.child('uid').val() == auth.uid"
},
".read": "auth.uid != null"
}
}
}
and the firebase bolt equivalent is below :
path / {
read() {auth.uid != null}
}
path /posts {
read() {auth.uid != null}
/{postId}{
create() { this.uid == auth.uid}
delete() { this.uid == auth.uid}
update() { prior(this.uid) == auth.uid}
}
}
In continuation to my previous question I have below design for my application.
Design
A user who can login to the application
Logged in user can create customers which will be stored under node
whose value will be the current logged in userid
Here is how I add the data through my android application.
FirebaseInstance mFirebaseInstance = FirebaseDatabase.getInstance();
FirebaseDatabase mFirebaseDatabase = mFirebaseInstance.getReference("tbl-customers").child(FirebaseAuth.getInstance().getCurrentUser().getUid());
//This will create or fetch user id node under tbl-customers.
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String name = inputName.getText().toString();
String email = inputCode.getText().toString();
String limit= inputLimit.getText().toString();
createUser(name, email,limit);
}
});
private void createUser(String name, String email,String limit) {
userId = mFirebaseDatabase.push().getKey();
Customer customer = new Customer(name, email,limit);
mFirebaseDatabase.child(userId).setValue(customer);
}
That's it.. In Database it is somehow represented as below:
tbl-customers
|___loggedInUserId1
|___customerID1
|___customerName
|___customerCode
|___customerLimit
|___customerID2
|___customerName
|___customerCode
|___customerLimit
|___customerID3
|___customerName
|___customerCode
|___customerLimit
|___loggedInUserId2
|___customerID4
|___customerName
|___customerCode
|___customerLimit
and I have rules defined as
{
"rules": {
"tbl-customers": {
".read": "auth != null",
".write": "auth != null",
"$custId": {
"customerName": {
".validate": "newData.isString() && newData.val().length < 100 && newData.val().length > 8"
},
"customerCode": {
".validate": "newData.isString() && newData.val().length<4 && !newData.exists() && newData.val().length>1"
},
"customerLimit": {}
}
}
}
}
Unfortunately, the data is inserted without considering any of the validation written for each properties. Even the empty data gets inserted.
I started thinking whether the rule written is of proper structure, because if I see the data inserted then it has 3 levels - tbl-customer-->loggedInUserId-->customerId but rules have been only written for tbl-customer-->customerId.
So I changed the rules as below.
{
"rules": {
"tbl-customers": {
".read": "auth != null",
".write": "auth != null",
"$user_id": {
".validate": "auth.uid===$user_id",
"$custId": {
"customerName": {
".validate": "newData.isString() && newData.val().length < 100"
},
"customerCode": {
".validate": "newData.isString() && newData.val().length<4 && !newData.exists()"
},
"customerLimit": {}
}
}
}
}
}
extending it to one more level by including,
"$user_id": {
".validate": "auth.uid===$user_id"
...
}
But now this throws Permission Denied Exception. Am out of ideas at this point of time. Could someone guide me in the right direction? I have referred lot of posts from my previous question but to my bad, I couldn't grab much information from it. Hope to find some clear explanation as on why rules validation are failing and why data gets inserted with above mentioned first rule.
I might be wrong here, but the .read and .write rules will always cascade down your tree regardless here, which the line ".write": "auth != null" is most likely where you're facing the problems.
It would be best to move this rule to where the ".validate": "auth.uid===$user_id" rule is and remove the validate rule. You would then change it to something like "auth.uid == $user_id". The 'validate' rule I believe is just for taking in a written input at that specific location and then accepting or rejecting.
This is how I believe it should look:
{
"rules": {
"tbl-customers": {
".read": "auth != null"
"$user_id": {
".write": "auth.uid === $user_id"
"$custId": {
"customerName": {
".validate": "newData.isString() && newData.val().length < 100"
},
"customerCode": {
".validate": "newData.isString() && newData.val().length<4 && !newData.exists()"
},
"customerLimit": {}
}
}
}
}
}
This structure will allow all logged in users to read the data, which you could restrict further to the $user_id location if you wish, similar to the write rule currently in place. This would then only allow users who match the $user_id read and write privileges.
CASE STUDY
To add to this, this is a structure I set up sometime ago that would allow an administrator the ability to add users:
{
"rules": {
"Administrator": {
".read": "auth != null"
},
"Users": {
"$user_id": {
".write": "$user_id === auth.uid",
".read": "$user_id === auth.uid"
}
}
}
}