Firebase Realtime Database Private Shared Data With E-Mail? - firebase

I want to share secure data between users.
"shared_requests" : {
"shared_uid" : {
"deviceSeriNo" : "device1serino",
"user1" : {
"email" : "john#john.com",
"userName" : "John"
},
"user2" : {
"email" : "micheal#micheal.com",
"userName" : "Micheal"
}
}
}
Rules: (Edited, I forgot to write a small part. (auth.uid.email.replace('#','').replace('.','')))
"shared_requests": {
"$key": {
".read": "root.child('shared_requests').child($key).child('user1/email').val() == auth.uid.email.replace('#','_').replace('.','_') || root.child('shared_requests').child($key).child('user2/email').val() == auth.uid.email.replace('#','_').replace('.','_')",
".write": "root.child('shared_requests').child($key).child('user1/email').val() == auth.uid.email.replace('#','_').replace('.','_') || root.child('shared_requests').child($key).child('user2/email').val() == auth.uid.email.replace('#','_').replace('.','_')"
}
}
But not working. How can I solve this problem?
Edit:
It works when I try with the UID.
"shared_req4": {
"shared_uid": {
"$key": {
".read": "auth != null && auth.uid === $key",
".write": "auth != null && auth.uid === $key"
}
}
}
Data:
Simulator:
Simulation results:
But it doesn't work when I try it by email.
"shared_req3": {
"shared_uid": {
"$key": {
".read": "auth != null && auth.uid.email.replace('#','_').replace('.','_') === $key",
".write": "auth != null && auth.uid === $key"
}
}
}
Data:
Simulator:
Simulation results:

Problem is solved.
It doesn't work on the simulator so try on the code. And it needs to be 'auth.token.email' instead of 'auth.uid.email'.
#FrankvanPuffelen Thank you so much.

Related

Securing Firebase RTDB with multiple databases for chat app

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.

Or operator not working in firebase rules

I have a realtime database. In rules, doing (a || b) works, but doing (b || a) does not work. I couldn't find the reason. Since my rules are long, I'm putting a small part of it here. actually it was working until today but today it stopped working and i didn't change anything.
Not working :
{
"rules": {
"allGames": {
"$gameID": {
".read": true
".write": "auth != null && ((!data.exists() &&
(newData.child('players').child('0').child('userID').val().contains(auth.uid) ||
newData.child('players').child('1').child('userID').val().contains(auth.uid) ||
newData.child('players').child('2').child('userID').val().contains(auth.uid) ||
newData.child('players').child('3').child('userID').val().contains(auth.uid)) ) ||
(!data.exists() &&
(newData.child('0').child('name').val().contains(auth.uid) ||
newData.child('1').child('name').val().contains(auth.uid) ||
newData.child('2').child('name').val().contains(auth.uid) ||
newData.child('3').child('name').val().contains(auth.uid)) ) )"
}
}
}
}
my json:
[
{
"durum": "davetYollayan",
"name": "PzbcSmKziaOcd4PdYNPnIWuG2iH2",
"score": 0
},
{
"durum": "davetYollayan",
"name": "efezefebcSmKziaOcd4PdYNPnIWuG2iH2",
"score": 0
}
]
Screenshot:
it works when i replace the write code with this. but both codes are the same, I don't understand why it gives an error?
".write": "auth != null && ((!data.exists() &&
(newData.child('0').child('name').val().contains(auth.uid) ||
newData.child('1').child('name').val().contains(auth.uid) ||
newData.child('2').child('name').val().contains(auth.uid) ||
newData.child('3').child('name').val().contains(auth.uid)) ) ||
(!data.exists() &&
(newData.child('players').child('0').child('userID').val().contains(auth.uid) ||
newData.child('players').child('1').child('userID').val().contains(auth.uid) ||
newData.child('players').child('2').child('userID').val().contains(auth.uid) ||
newData.child('players').child('3').child('userID').val().contains(auth.uid)) ))"

only user can modify has own data in firebase

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

Writing operation fails - firebase database rules

I have the following object:
const offer = {
offerInfo: {
price: '',
status: 'open',
message: '',
ownerUID: '',
ownerName: '',
ownerPhoto: '',
ownerAvgRating: '',
ownerReviewNumber: '',
},
offerMetaData: {
userHasSeenOffer: false,
userHasBeenNotified: false,
}
}
I am trying to post it to the following node:
updates['jobs/${activeJob.key}/offers/${currentUser.uid}] = offer;
and then firebase.database().ref().update(updates)
As you can see I am using the users uid as the id of the offer itself.
Now when I try to post it using the following rules, I get a permission denied error and I have no clue why.
Rules:
"jobs": {
"$job_uid": {
".read": "auth !== null",
"job": {
".write": "!data.exists() && root.child('allUsers/serviceUsers/' + auth.uid + '/paymentDetails').exists() || data.exists() && root.child('jobs/' + $job_uid + '/job/owner').val() === auth.uid",
},
"offers": {
"$offer_uid": {
"offerInfo": {
".write": "$offer_uid === auth.uid",
},
"offerMetaData": {
".write": "root.child('jobs/' + $job_uid + '/job/owner').val() === auth.uid || $offer_uid === auth.uid",
},
},
},
...
Any ideas?
You are trying to write directly to $offer_uid but you don't have any write rules on that node so it will use the default false.
For you current write to succeed you can change your rules like this:
"$offer_uid": {
".write": "$offer_uid === auth.uid",
"offerMetaData": {
".write": "root.child('jobs/' + $job_uid + '/job/owner').val() === auth.uid",
},
},
I moved the write rule one node up, directly in $offer_uid, instead of having it in both the childs seperatly.
Another option would be to keep your rules and split your write so you are writing to the child nodes.

data structuring in Firebase

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"
}
}
}

Resources