Reputation: 1199
I am getting very confused with the Firebase rules structure. Basically I have a root folder called 'Transactions', containing many childByAutoIDs that again contains data, exactly like this:
Transactions {
autoID1 {
transactionID: whatever,
timeCreated: whatever,
"amount": whatever,
"sender": whatever,
"receiver:whatever"
}
}
I am now trying my best to implement the best possible security rules. I therefore tried to do something like this:
"Transactions": {
".write": "auth !== null",
"$transactionAutoID": {
"timeCreated": {
".write": "auth !== null && data.child('sender').val() === auth.uid || data.child('receiver').val() === auth.uid",
".read": "auth !== null && data.child('sender').val() === auth.uid || data.child('receiver').val() === auth.uid"
}
}
}
So basically, from what I have learned, and also what I am struggling with - is the fact that the user is able to write anything, even in the 'wildcard IDs ($transactionAutoID)'. I know this is because I have set the '.write' in Transactions to 'auth !== null' - but if I don't have this set, users may not read or write any transaction data. (I have the rules by default set to false).
How would I proceed if I only wanted users to be able to create new childs in Transactions, but not write in any transaction keys, if they are not either the sender or the receiver?
Upvotes: 1
Views: 171
Reputation: 598668
Once a permission is granted on a node, it cannot be taken away on a lower-level node.
So if you look at this:
"Transactions": {
".write": "auth !== null",
"$transactionAutoID": {
"timeCreated": {
".write": "auth !== null && data.child('sender').val() === auth.uid || data.child('receiver').val() === auth.uid",
".read": "auth !== null && data.child('sender').val() === auth.uid || data.child('receiver').val() === auth.uid"
}
}
}
The write rule on Transactions/$transactionId/timeCreated
is meaningless, since it tries to tighten the permission from Transactions
.
So right now it functions like this:
"Transactions": {
".write": "auth !== null",
"$transactionAutoID": {
"timeCreated": {
".read": "auth !== null && data.child('sender').val() === auth.uid || data.child('receiver').val() === auth.uid"
}
}
}
If you want to put a limit to specifically what a user can do on Transactions/$transactionId/timeCreated
, you will either have to do so in a validation rule or (more likely) by putting all the rules on the transaction itself:
"Transactions": {
"$transactionAutoID": {
".write": "auth !== null && (
!data.exists() || (
newData.child('sender').val() === auth.uid ||
newData.child('receiver').val() === auth.uid)"
)
)"
}
}
In words: you can write a transaction when you're authenticated and either the transaction doesn't exist yet or you're the sender or receiver of the transaction.
Upvotes: 1