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)) ))"
Related
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.
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've a form which creates the following JSON structure.
{
"reviewed":false,
"title":"Just a title",
"user":"UYV9TRKXfNW1NeCyFyfjZfagJ8B",
"items":[
{
"age":"33",
"experience":"Newcomer",
"image":"https://image-url",
"job":"Nerd",
"name":"Testname",
"party":"AAA",
"type":"person"
},
{
"age":"33",
"experience":"Newcomer",
"image":"https://image-url",
"job":"Informatiker",
"name":"Testname",
"party":"AAA",
"type":"person"
}
]
}
How do I check the values of "items" with firestore's security rules? Is there a way to loop/iterate over the array?
For the sake of completeness: That's my solution so far. I did it the way described in the linked answer. The possible amount of items is limited to 10, so we can go without dynamic loops.
service cloud.firestore {
match /databases/{database}/documents {
match /events/{event} {
function isAuthed() {
return request.auth.uid != null
&& request.auth.uid == request.resource.data.user
&& request.auth.token.email_verified == true;
}
function isReviewed() {
return request.resource.data.reviewed == false
|| request.resource.data.reviewed == "false"
}
function isValidTitle() {
return isValidStringInput(request.resource.data.title, 200);
}
function items() {
return request.resource.data.items;
}
function isValidPerson(item) {
return items()[item].keys().hasAll(['image','type','name','job','age','party','experience'])
&& isValidStringInput(items()[item].image, 100)
&& isValidStringInput(items()[item].type, 10)
&& isValidStringInput(items()[item].name, 50)
&& isValidStringInput(items()[item].job, 50)
&& isValidStringInput(items()[item].party, 50)
&& isValidStringInput(items()[item].experience, 50)
&& isValidNumber(items()[item].age);
}
function isValidParty(item) {
return items()[item].keys().hasAll(['image','type','name','orientation','experience','promi'])
&& isValidStringInput(items()[item].image, 100)
&& isValidStringInput(items()[item].type, 10)
&& isValidStringInput(items()[item].name, 50)
&& isValidStringInput(items()[item].orientation, 50)
&& isValidStringInput(items()[item].experience, 50)
&& isValidStringInput(items()[item].promi, 50);
}
function isValidItem(item) {
return isValidPerson(item)
|| isValidParty(item);
}
function isValidStringInput(input, maxSize) {
return input is string
&& input.size() > 0
&& input.size() <= maxSize;
}
function isValidNumber(input) {
return input is int
|| input.matches('^[0-9]+$');
}
// One can READ
// always ...
allow read: if true;
// One can WRITE, when ...
// writer is logged in
// uid in event is same as uid of writer
// writer has email confirmed
// reviewed is initial set to false
// form/user input is ok
allow write, update:
if isAuthed()
&& isReviewed()
&& isValidTitle()
&& items().size() >= 1
&& items().size() <= 10
&& isValidItem(0)
&& (items().size() < 2 || isValidItem(1))
&& (items().size() < 3 || isValidItem(2))
&& (items().size() < 4 || isValidItem(3))
&& (items().size() < 5 || isValidItem(4))
&& (items().size() < 6 || isValidItem(5))
&& (items().size() < 7 || isValidItem(6))
&& (items().size() < 8 || isValidItem(7))
&& (items().size() < 9 || isValidItem(8))
&& (items().size() < 10 || isValidItem(9));
}
}
}
As far as I know. You still can't use loops in firestore security rules and the linked answer and the example is still valid and shows how you can do validations using functions. This could become unusable if the array grows and it might be better to choose another data structure like an own collection for your items.
Cheers,
Lars
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.
I have this structure
"Following": {
".validate": newData != null && newData.child(count).val() == root.child(Following).child($User).child(count).val() + 1),
"$User": {
"$Following": {
"created": {}
},
"count": {}
}
}
i want to prevent that the count variable can be incremented or decremented without the creation or the delete of a following
for prevent the increment without the creation of a new following i add this rule
".validate": newData != null &&
newData.child(count).val() ==
root.child(Following).child($User).child(count).val() + 1)
but i have problem to prevent the decrement without the delete of a following.
the my ask is this
how can I decrease the count variable only if I know that the Following is going to be deleted ?
sorry for bad english :/
What do you think of this method?
"Event": {
"$User": {
"counter": {
".validate": "newData.hasChildren(['value', 'tmp'])",
"value": {},
"tmp": {},
"$other": {
".validate": "false"
},
".write": "data.val() != null && newData.val() != null && (newData.parent().child(newData.child('tmp').val()).val() != null && newData.child('value').val() == data.child('value').val() + 1 || root.child('Event').child($User).child(newData.child('tmp').val()).val() != null && newData.parent().child(newData.child('tmp').val()).val() == null && newData.child('value').val() == data.child('value').val() - 1)"
},
"$Event": {
//some variable and permissions
}
}
}
i use the tmp variable to recognize the event key that i want verify if is in creation or in delete and consequently i update the value variable .
in the example i add only the update rules without other rules to not get in confusion