The JSON looks like this:
I want to remove the child which is [steven : uid] from user_lookup
This is the code:
self.ref.child("user_lookup").queryOrderedByValue().queryEqual(toValue: user?.uid).observe(.value, with: { snapshot in
if snapshot.exists() {
print("I got it")
// remove [steven, uid]
} else {
print("Not found")
}
I don't know how to remove the child, but i've tried to type removeValue but i got Permission_denied
Here is the rules:
`"user_lookup": {
".read": "auth !== null",
".write": "auth !== null && !data.exists()",
".indexOn": [".value"],
I think its because "!data.exists()" but I don't want to duplicate data, so how to fix that?
And how can i remove the child, Any help will be appreciated.
I think this might be what you want:
".write": "
(auth.uid === newData.val() && !data.exists()) ||
(auth.uid === data.val() && !newData.exists()"
The first expressions or the or allows user to claim their name if it doesn't exist yet. The second expression allows then to delete their claim.
Related
I need to allow only 2 specific uid for write access and I can't publish with my current rule:
{
"rules": {
".read": "auth != null",
".write": "auth != null && auth.uid === 'abc123' || '123abc'",
}
}
It keeps complain "rule regulation may not contain '|' operator" and
"right operand for '||' must be boolean", which ever i used.
How should I change my rule to achieve what I want?
Any help will be much appreciated.
The word after || is actually not a boolean, it is just a string. Please, check my fixed code.
{
"rules": {
".read": "auth != null",
".write": "auth != null && (auth.uid === 'abc123' || auth.uid === '123abc')",
}
}
I am currently working on a page where all auth users can create a post. The post should also be editable, but only by the creator. Also an admin with a certain email address should be able to edit the post.
This are my security roles:
{
"rules": {
"shoes" : {
".read": true,
"$shoeID" : {
".write" : "root.child('shoes').child($shoeID).child('postowner').val() === auth.uid && auth != null && root.child('users').child(auth.uid).child('uid').val() === auth.uid || auth.token.email === 'admin#admin.com'"
}
},
"websites" : {
".read": true,
"$shoeID" : {
"$storeID" : {
".write" : "root.child('websites').child($shoeID).child($storeID).child('postowner').val() === auth.uid && auth != null && root.child('users').child(auth.uid).child('uid').val() === auth.uid || auth.token.email === 'admin#admin.com'"
}
}
},
"users" : {
"$uid" : {
".read" : "auth != null && root.child('users').child($uid).child('uid').val() === auth.uid"
}
}
}
}
and this is my database structure:
I think I am doing something wrong, because with my current rules any user can change the data.
I'm not sure where the problem comes from, but this rule seems overly complicated to me:
".write" : "
root.child('shoes').child($shoeID).child('postowner').val() === auth.uid
&& auth != null
&& root.child('users').child(auth.uid).child('uid').val() === auth.uid
|| auth.token.email === 'admin#admin.com'
"
Things that can be improved:
There is no need to check auth != null after you've already used auth.uid. Either move the null check first, or skip it altogether.
There is no need to look up the shoe by $shoeID, as it's already in data. So your root.child('shoes').child($shoeID) is equivalent to the (shorter and more idiomatic) data.
The root.child('users').child(auth.uid).child('uid').val() === auth.uid clause seems meaningless in write operations of shoes. This clause should only be enforced in the write operation of /users/$user.
With these changes your rules become:
".write" : "
data.child('postowner').val() === auth.uid
|| auth.token.email === 'admin#admin.com'
"
As said: I don't see what's going wrong in the write operation, but hopefully thee simpler rules make it easier to troubleshoot that problem. I'd recommend starting in the rules playground, and using that to replay what your code does.
I have put a rule as
(root.child('users').child(auth.uid).child('role/cafe').val() === true)
in my realtime database rules.
My user is
key {
uid: xxxx
name: xxxx
role:{
cafe: true
user: false
}
}
if auth.uid is equal to key, the rule works, however how can I modify the above rule to look for uid inside data
It is unclear what the value of $key is expected to be. So I'm going to assume it's just some random string that isn't used in the rules.
For each security rule, the current data of the node is accessible using the predefined variable data. ".write" and ".validate" rules also have access to the to-be-written data as newData. These are both RuleDataSnapshot objects.
Assuming that a user making changes must be the user given by the uid property, the following rules can be used.
"rules": {
"users": {
"$key": {
".read": "auth != null && data.child('uid').val() == auth.uid",
".write": "auth != null && ((data.exists() && data.child('uid').val() == auth.uid) || (!data.exists() && newData.child('uid').val() == auth.uid)"
}
}
}
The above rules use a fail-fast approach. If a user is not logged in, the check aborts. Otherwise, the user's ID is matched against the existing data at the given node. If the data doesn't yet exist, the newly updated data must also match the current user's ID.
In case the "cafe" role is important, the following rules also require that the "cafe" is set to true to allow read/write operations.
"rules": {
"users": {
"$key": {
".read": "auth != null && data.child('uid').val() == auth.uid && data.child('role/cafe').val() == true",
".write": "auth != null && ((data.exists() && data.child('uid').val() == auth.uid && data.child('role/cafe').val() == true) || (!data.exists() && newData.child('uid').val() == auth.uid && newData.child('role/cafe') == true))"
}
}
}
Note: If $key is storing user info/data, I highly recommend using the user's ID as the key as security rules cannot perform queries like "does userid have admin role?" without structuring your data to allow it. If $key is meant to be a username, instead use a username-to-userID map as it will prevent future problems. One such example is if a user wants to change their username, you can remove and link the new username to the user without ever having to move all their data.
You can use a wild card. In your rules
"users":{
"$key":{
".read" : (root.child('users'+$key).child('role/cafe').val() === true) && (root.child('users'+$key).child('uid').val() === auth.uid ),
".write" : (root.child('users'+$key).child('role/cafe').val() === true ) &&(root.child('users'+$key).child('uid').val() === auth.uid )
}
},
The first condition checks whether the café value for the user is true the second checks whether the uid is the same
I have a firebase database rule to block:
non-authenticated users
users trying to create data for some other user
I also want to prevent updating data.I need this code for that:
!data.exists() || !newData.exists()
This is currently how it looks:
"rules": {
"orders": {
"$order":{
".read": "auth != null && auth.token.admin === true",
".write": "auth != null && auth.uid === newData.child('userID').val()" // check the incoming data's userID value here if sender is same. or someone can send orders with other peoples ids. also anyone can send an order with id 123 but only if it doesnt exist. so they cannot update anyones order. is this safe enough?
},
".indexOn": "userID"
}
}
How am I supposed to include this "||" operator in my logical expression for the ".write" rules?
I am not able to delete data. Is it because Im checking the newData's child in the security rules and there is no newData when using ".remove()" in the app? If that is the case, how does write and delete rules in the same line work?
I got a weird issue that I could not use parantheses at first but it is now working. I created an || between two expressions
First expression is for write:
(auth != null && newData.exists() && auth.uid === newData.child('userID').val() && !data.exists())
Here "newData.exists()" in the expression tells us there is an incoming data ( write/update operation) and "!data.exists()" blocks updating data.
Second expression is for deleting rules:
(!newData.exists() && auth != null && auth.uid === data.child('userID').val()
Here "!newData.exists()" says that there is no new data so this is a delete operation, and the next part makes sure everyone can only delete their own data.
So now the code looks like this:
"rules": {
"orders": {
"$order":{
".read": "auth != null && auth.token.admin === true",
".write": "(auth != null && newData.exists() && auth.uid === newData.child('userID').val() && !data.exists()) || (!newData.exists() && auth != null && auth.uid === data.child('userID').val())"
},
".indexOn": "userID"
},
}
I have this collection
"connection-requests":{
"push-key1":{
"foo":"bar",
"biz":"baz",
"user1":{
"some-info":"",
"uid":"user1uid"
},
"user2":{
"some-info":"",
"uid":"user2uid"
}
}
}
I want this collection to be readable and writable only by the two users whose uid is present this collection.
This is my database rules:
"connection-requests": {
"$key": {
".read": "root.child('connection-requests').child($key).child('user1/uid').val() == auth.uid || root.child('connection-requests').child($key).child('user2/uid').val() == auth.uid",
".write": "root.child('connection-requests').child($key).child('user1/uid').val() == auth.uid || root.child('connection-requests').child($key).child('user2/uid').val() == auth.uid",
}
}
Im accessing the data using this request :
db.ref('connection-requests')
.orderByChild('user1/uid')
.equalTo(uid) // <- auth.uid of user
.once('value')
.then()
.catch()
The rules above doesn't work, my guess is that there is something wrong with .child($any) part but Im not sure what.
Thanks in advance.
The closing double-quote for each rule is misplaced. Instead of being at the end of the line, it is following the OR operator:
auth.uid || "root.child
^
^
Should be:
"connection-requests": {
"$key": {
".read": "root.child('connection-requests') ... == auth.uid",
".write": "root.child('connection-requests') ... == auth.uid",
}
}