I have a collection of signatures where each signature has a few properties: public: fullname, city and then email.
I want to keep the email property private and I've been struggling with writing the correct rules to only return fullname and city. Here is what my rules.json looks like so far:
{
"rules": {
"signatures": {
"$signatureID": {
"public": {
".read": true
},
"email": {
".read": false
}
}
}
}
}
When I go to the /signatures end point, I would like to receive an array of signatures with the public data and not receive the email addresses.
So far I haven't had any luck getting this to work the way I want it to. Am I doing something wrong? Should I structure my data differently?
With respect to security rules, Firebase operations are all-or-nothing.
As a result, attempting to load all of the data at /signatures will fail because your client does not have permission to read all of the data at that location, though you do have permission to read some of the data there. Similarly, writing to a location behaves the same way, and full permission is required before your operation will continue.
To handle this use case, consider restructuring your data like this:
{
"rules": {
".read": false,
".write": false,
"signatures-public": {
".read": true,
"$signatureID": {
// ... public data here
}
},
"signatures-private": {
"$signatureID": {
// ... private data here
}
}
}
}
Related
Im working on an ionic app, i would like to send data to my firebase realtime-database as an object and compare the data with something, however on the server side which is my security rules for the newData, the write rule seems to be incorrect.
This is my sending code
var firebaseRef = this.afd.database.ref();
firebaseRef.child('Download/01/1').set({password:2431,name:'john'});
my database node should be written here
Download: {
01 : {
1: { // the data will be written here
}
}
}
and this is my security rules
"Download": {
"$id": {
".write": "newData.child('password').val() === 4321"
}
}
As you can see, i have purposely written the password on my set function '2431' in order to be process as incorrect during the validation of write rules, however the write rule still proceeds in writing the database even though the password it receive is incorrect, can you advise what should correct in my code? Thanks
Your rules and query don't match. You're writing to "Download/01/1", and password is set at "Download/01/1/password". However, your rules are set at "Download/XX", and newData.child('password') is referring to "Download/XX/password" (note that the "1" is missing in the path). Perhaps you meant something like:
"Download": {
"$id": {
"$i": {
".write": "newData.child('password').val() === 4321"
}
}
}
Or maybe:
"Download": {
"$id": {
".write": "newData.child('1').child('password').val() === 4321"
}
}
I'm planning to create a realtime database for a chatting apps with private message channel, is there any specific rules that we can check the authenticated user has access to this room?
my database structure is mostly like this:
{
"channel": {
"unique_room_id": {
"participants": {
"uid1": 1537259273000,
"uid2": 1537259273000
}
"message": {
....
}
}
}
}
Is it possible to use hasChild like how it is used on .write rule or we need to manually validate the reference which means it's not really possible to add more participants to the room?
If possible I want to avoid the latter, thanks in advance
Note:
I'm also open to any alternative structures, and maybe some explanation why it is recommended
It's always easiest to use top-level lists instead of nesting multiple entity types in a single list. So remodel your data to:
{
"participants": {
"unique_room_id": {
"uid1": 1537259273000,
"uid2": 1537259273000
}
}
"messages": {
"unique_room_id": {
....
}
}
}
Now you can ensure that only participants in a room can read its messages with:
{
"rules": {
"messages": {
"$roomid": {
".read": "root.child('participants').child($roomid).child(auth.uid).exists()"
}
}
}
}
I am attempting to rewrite my database rules to only allow members of a specific 'collection' to access that collection only if that member is included in the teams list. Referring to the image attached below, this is what my rule currently looks like:
{
"rules": {
"collection": {
"$collection_id": {
"$teams" : {
".read": "data.child('id').val() === auth.uid"
}
}
}
}
}
However this doesn't seem to work and I believe it's incomplete. How can I update my rules to match this design structure? If any change in my structure is necessary to support this, do pitch that and I will attempt to update the current production data.
You could reach into the teams node like this:
{
"rules": {
"collection": {
"$collection_id": {
".read": "data.child('teams').child(auth.uid).child('id').val() === auth.uid"
}
}
}
}
Right now you have unnecessary redundancy in the teams node. The id of the child node is repeated in its own child id. You can simplify your database and rules if you simply set teams/{teamId} = true in the database, your rule could look like this instead to allow only users listed under teams to read the entire collection:
{
"rules": {
"collection": {
"$collection_id": {
".read": "data.child(auth.uid).val() === true"
}
}
}
}
I tried to set some important write persmissions but I can't solve my problem. I got told that, if I add a write-rule to room, then I overwrite my room/$roomID/ingame rule.
What I'm trying to do is
Creating a room by auth users.
Set/update ingame of a room only by the creator of the room. (That works)
Rules:
{
"rules": {
".read": true,
"user": {
".indexOn": "displayname"
},
"room": {
"$roomID": {
"ingame":{
".write": "data.parent().child('creatorUid').val() == auth.uid"
}
}
}
}
}
How I call to create a new room:
let user = firebase.auth().currentUser
dbRoomRef.push().then((room) => {
room.set({
creatorUid: user.uid,
ingame: false,
})
}).catch(function(err) {
console.log(err.message)
}
)
Error message (as expected):
FIREBASE WARNING: set at /room/-L572bnuRv0_vntko-Bd failed: permission_denied
Thank you.
The error messages says that you're trying to write /room/-L572bnuRv0_vntko-Bd and have no permission to write there. That is correct, since your rules only give permission to write to /room/-L572bnuRv0_vntko-Bd/ingame.
If creatorUid is already set when you create the room, you don't have to include it in your write statement and can just do:
room.child("ingame").set(false);
If you're trying to allow everyone to create a new room (or write to an existing room) as long as they are the owner, you need to set your rules one level higher:
"room": {
"$roomID": {
".write": "newData.child('creatorUid').val() == auth.uid"
}
}
I have a collection of signatures where each signature has a few properties: public: fullname, city and then email.
I want to keep the email property private and I've been struggling with writing the correct rules to only return fullname and city. Here is what my rules.json looks like so far:
{
"rules": {
"signatures": {
"$signatureID": {
"public": {
".read": true
},
"email": {
".read": false
}
}
}
}
}
When I go to the /signatures end point, I would like to receive an array of signatures with the public data and not receive the email addresses.
So far I haven't had any luck getting this to work the way I want it to. Am I doing something wrong? Should I structure my data differently?
With respect to security rules, Firebase operations are all-or-nothing.
As a result, attempting to load all of the data at /signatures will fail because your client does not have permission to read all of the data at that location, though you do have permission to read some of the data there. Similarly, writing to a location behaves the same way, and full permission is required before your operation will continue.
To handle this use case, consider restructuring your data like this:
{
"rules": {
".read": false,
".write": false,
"signatures-public": {
".read": true,
"$signatureID": {
// ... public data here
}
},
"signatures-private": {
"$signatureID": {
// ... private data here
}
}
}
}