What does $uid mean in the code ?
is $uid a column name or key name?
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}
}
as in document
A wildcard path used to represent ids and dynamic child keys.
more detail , let say you have this data
{
users : {
"SOME_KEY_1" : {"name" : 'test 1' , "private" : {...}} ,
"SOME_KEY_2" : {"name" : 'test 2' , "private" : {...}} ,
"SOME_KEY_3" : {"name" : 'test 3' , "private" : {...}} ,
}
}
and these rule
{
"rules" : {
"users" : {
"$uid" : {
"private" : "auth != null && auth.uid === $uid"
}
}
}
}
you cannot know the keys of users node but you need to prevent other users to private node except their own so you put $uid to represent dynamic child keys
in your case you just allowing user to write to their own data
Related
I am on the blaze plan and building a chat functionality in my app using Firebase realtime database.
I have 3 databases for now :
Main instance that contains sharding information and users chats' info.
The 2 other instances will contain the chats and messages.
The database structure for the main instance looks like this :
{
"shards" : {
"shard1" : {
"full" : false,
"name" : "shard1",
"num" : 1,
"url" : "shard1Url"
},
"shard2" : {
"full" : false,
"name" : "shard2",
"num" : 0,
"url" : "shard2Url"
}
}
}
And here is the data structure of one of the shard :
{
"users" : {
"user_id_1" : {
"chat_id_1" : true
},
"user_id_2" : {
"chat_id_1" : true
}
},
"chats" : {
"chat_id_1" : {
"created" : true,
"createdAt" : 1645888918717,
"members" : {
"user_id_1" : true,
"user_id_2" : true
},
"name" : "",
"uid" : "chat_id_1",
"updatedAt" : 1645895862214
}
},
"messages" : {
"chat_id_1" : {
"mess_id_1" : {
"content" : "Hello",
"chatID" : "chat_id_1",
"createdAt" : 1645895862214,
"senderID" : "user_id_1",
"uid" : "mess_id_1"
},
"mess_id_2" : {
"content" : "Bye",
"chatID" : "chat_id_1",
"createdAt" : 1645889441313,
"senderID" : "user_id_2",
"uid" : "mess_id_2"
}
}
}
}
I want the following rules to apply :
Reads :
A user can listen for changes under /users/$user_id/ where $user_id is auth.uid
A user can get all the chats from the above IDs when he is in the member map (under /chats/$chat_id)
A user can read all the messages from a chat when he is a member (under /messages/$chat_id)
Writes :
A user can create a chat if there is no data under the chat_id node
A user can update a chat if he is a member under the chat_id
A user can create a message if a chat_id exists and if he is a member under the chat_id and if the senderID matches the auth.uid
A user can delete a message if he is the sender of the message (not sure i can do this with security rules but only client side)
A user can add only an item like {"$chat_id": true} under any other user under /users/$user_id/
So far, here are my rules that are not working :
-> Main shard :
{
"rules": {
"shards": {
".read": "auth.uid != null",
".indexOn": ["full"],
"$shardName": {
"num": {
".write": "auth.uid != null"
},
"$other": {
".write": false
}
}
},
}
}
-> For other shards :
{
"rules": {
"users": {
"$userID": {
".write": "auth.uid != null && !data.exists()",
".read": "auth.uid == $userID",
}
},
"chats": {
"$chat_id": {
".read": "data.child('members/'+auth.uid).exists()",
".write": "(!data.exists() && newData.hasChild('members')) || data.child('members/'+auth.uid).exists()",
}
},
"messages": {
"$chat_id": {
".read": "root.child('chats').child($chat_id).child('members').child(auth.uid).exists()",
".indexOn": ["createdAt"],
"$mess_id": {
".write": "(!data.exists() && newData.child('senderID').val() == auth.uid) || (data.exists() && data.child('senderID').val() == auth.uid)"
}
}
}
}
}
EDIT :
I have made many edit regarding the database structure.
I especially need help with reads rather than writes, as writes seem to be working fine now but i would like confirmation and / or changes if you see mistakes.
l want make only user able to create new post, and only user able to modify only the post that were created by them. Like delete or edit !
database structure
{
"post" : {
"-LWzHsKzAyK9Wfa1kbD_" : {
"name" : "test",
"title" : "test",
"userId" : "8D3sENaBcLaXoGNnh1MPuoyj5LP2"
},
"-LWzHx6u-gQ7XoVR714a" : {
"name" : "check",
"title" : "check",
"userId" : "WUM2HBkGo8TFDeOjEqO1s3lCj1p1"
}
}
}
l used this rules but l got error when to save No such method/property 'userId'.
{
"rules": {
".read": false,
".write": false,
"report": {
".read": "auth != null",
".write": "auth != null && ( (data.exists() && data.userId === auth.uid) || !data.exists() || !newData.exists() )"
}
}
}
You can't just use property accessor notation to get a child value of the data. You must call the child() function to get the child, and the val() function to get its value.
So:
data.child('userId').val() === auth.uid
I have a database schema like this:
Posts
unverified
post_1
post_2
...
And here is a shortened list of data in /posts/unverified path
{
"-L7xmY2HMeEImDZnZqTf" : {
"categorie" : 0,
"commonFields" : {...},
"fbKey" : "-L7YM7vEf8RpcxGUTpDE",
"images" : [...],
"specialFields" : {
"area" : "150",
"productPrice" : {
"currency" : "dollar",
"value" : "65000"
},
"requestType" : "sell",
"requesterType" : "personal",
"roomCount" : 3,
"suburbia" : "false"
},
"subCat" : 0,
"timestamp" : 1521011840178,
"uid" : "Fo5f6VonWgQVpsf6u80TPgoi2it2"
},
"-L7YNUZPL1-Dl7EhScEE" : {...},
"-L7YNUZPL1-fdfasfa" : {...},
"-L7YNUZPL1-ljljklfd" : {...},
"-L7YNUZPL1-lkjlkjfas" : {...},
}
And a firebase security rules defined as below
{
"rules": {
"posts": {
"unverified": {
".indexOn": "timestamp",
".read": "data.child('uid').val() === auth.uid"
As the rules show, I want to read unverified posts if the users id equal to the uid field in the post data
But every time i use the rules simulator ( or test the with the codes ) with the below configuration, its' giving Simulated read denied error
Thanks for your helps
Your .read rule is defined on /posts/unverified and checks a child called uid. So the total path is /posts/unverified/uid.
You're trying to read /posts/unverified/-L7xmY2HMeEImDZnZqTf. And the UID value is defined on /posts/unverified/-L7xmY2HMeEImDZnZqTf/uid.
The two paths don't match. You need to add a wildcard in your rules:
{
"rules": {
"posts": {
"unverified": {
".indexOn": "timestamp",
"$postid": {
".read": "data.child('uid').val() === auth.uid"
I have my data like, a teacher and few students with payment options.
I want to structure below data.
Authenticated teacher with read/write access to students profiles.
r/w access to Authenticated student profile.
invoice readable by student however, write access to teacher.
looking for inputs/help in structuring the above dB with security rules in firebase.
Update
Use below sample DB to test against Bradley answer.
{
"invoices" : {
"stid1" : {
"studentID" : "9EtsXHveIyaEkkLLk5hpo6vCtVx1"
}
},
"students" : {
"3d2HnQUxAbgaOqWBEqfDuhkhkj63" : {
"name" : "s2"
},
"9EtsXHveIyaEkkLLk5hpo6vCtVx1" : {
"name" : "s1"
}
},
"teachers" : {
"aiBunX1rZceD2lRslEmCrFHS2XF3" : {
"name" : "s1"
}
}
}
The following database rules:
{
"rules": {
// teachers profiles stored under this node
// teachers can read and write under their own node
"teachers": {
"$teacherID": {
".read": "auth != null && auth.uid == $teacherID",
".write": "auth != null && auth.uid == $teacherID"
}
},
// teachers can r/w student profiles, and the students can also r/w their own profile
"students": {
"$studentID": {
".read": "auth != null && (root.child('teachers').child(auth.uid).exists() || auth.uid == $studentID)",
".write": "auth != null && (root.child('teachers').child(auth.uid).exists() || auth.uid == $studentID)"
}
},
"invoices": {
"$invoiceID": {
// assuming each invoice has the student ID located at /$invoiceID/studentID
// students can read, teachers can r/w
".read" : "auth != null && (root.child('invoices').child($invoiceID).child('studentID').val() == auth.uid || root.child('teachers').child(auth.uid).exists())",
".write": "auth != null && root.child('teachers').child(auth.uid).exists()"
}
}
}
}
Works on the following database:
{
"teachers" : {
"aiBunX1rZceD2lRslEmCrFHS2XF3" : {
"name" : "s1"
}
},
"students" : {
"3d2HnQUxAbgaOqWBEqfDuhkhkj63" : {
"name" : "s2"
},
"9EtsXHveIyaEkkLLk5hpo6vCtVx1" : {
"name" : "s1"
}
},
"invoice" : {
"stid1" : {
"9EtsXHveIyaEkkLLk5hpo6vCtVx1" : {
"ispaid" : false
},
"studentID" : "9EtsXHveIyaEkkLLk5hpo6vCtVx1"
}
}
}
This is the structure of my data
{
"projects" : {
"proj1" : {
"-JccS4StrTnJdTficR-u" : {
"name" : "consultation",
"status" : false
},
"-Jd6JlJUfyyZ2U0NTQEs" : {
"name" : "Words",
"status" : false
}
},
"proj2" : {
"-JccS6nwYHRrxvjZtCkt" : {
"name" : "Rework",
"status" : false
},
"-Jd6Jqa7-EPJuWxbtJAV" : {
"name" : "Review",
"status" : false
}
},
"proj3" : {
"-JccSJ5lEBQEg3XCbG-u" : {
"name" : "translation",
"status" : false
}
}
}
}
Here are my rules
{
"rules": {
".read": true,
"projects": {
"proj1": {
".write": "auth != null"
},
"proj2": {
".write": true
},
"proj3": {
".write": true,
".validate": "newData.child('name').isString()
&& newData.child('name').val().length < 10"
}
}
}
}
When I created the database, there was no rule. Now, I've created the rules. I want the length of the name to be less than 10 characters.
When I run the code, I'm getting the following error: FIREBASE WARNING: set at /projects/proj3/-Jd4n6XditTHLWKVmhC6 failed: permission_denied
I can't exactly tell why it's not working. I've also tried just this portion newData.child('name').isString(), but I'm still getting the same error.
Here is the code that push data to FireBase
function saveToFB(taskName, proj) {
// this will save data to Firebase
var project=projTasks.child(proj);
project.push({
name: taskName,
status: false
});
};
Looking at the structure of your data, as well as your rules, it looks like there is a missing level of data between "proj1"/"proj2"/"proj3" and the object that has name and status attributes.
Specifically, the .validate rules you have configured is checking the length of the name attribute for "proj3", not the new element added to the list there.
To get around this, try increasing the depth of the security rules definitions, and make use of the $wildcard functionality, where any security rules key prefixed with $ is treated as a wildcard with a name that you can reuse.
{
"rules": {
".read": true,
"projects": {
"proj1": {
".write": "auth != null"
},
"proj2": {
".write": true
},
"proj3": {
".write": true,
"$someChildElementHere": {
".validate": "newData.child('name').isString()
&& newData.child('name').val().length < 10"
}
}
}
}
}