I am getting the firebase warning "Using an unspecified index. Consider adding ".indexOn": "E-mail" at /user/544dceb6-98d-4f7e/clients.
The rule I added is:
{
"rules": {
"user": {
"$clients": {
".indexOn": ["E-mail"]
}
}
}
}
This is the call I'm making:
firebaseRef.child(authData.uid + "/clients").orderByChild("E-mail").equalTo(this.props.params.clientId).on('value', function(clientSnapshot) { ... }
This is how my data is structured:
database
+ user
+ 544dceb6-98d-4f7e...
+ clients
+ -K96sXIXRUIOK8....
+ E-mail
I suspect the issue has something to do with the two layers of keys but can't find a solution.
Many thanks!
You're missing a level in your rules.json:
{
"rules": {
"user": {
"$userid": {
"clients": {
".indexOn": ["E-mail"]
}
}
}
}
}
Side note: it is somewhat confusing that you have user (singular) and clients (plural) in the tree. Making them consistent helps in keeping your data structure easier to understand.
Related
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 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
}
}
}
}
I'm working thru the excellent example on how to structure data as shown by Kato in this post:
Firebase user account security with firebaseSimpleLogin
I'm not having any luck getting validate to work properly.
The data structure is :
accepted_invites
game1
desc "fun game"
invites
game1
uuidAAA true
uuidBBB true
here's a screen shot:
Firebase data
If I try and write the following
ref.child("accepted_invites").child("game1").child("userTwo").child("uuidBBB").setValue(true);
it will make an entry in accepted_invites with this rule :
".validate": "root.child('invites/'+$game_id+'/uuidBBB').exists()"
but not
".validate": "root.child('invites/'+$game_id+'/'+newData.val()).exists()"
I tried using the simulator but I'm getting
Type Error: + only operates on numbers and strings.
Here's the complete rules as I have them:
{
"rules": {
".write" : true,
".read" : true,
"accepted_invites": {
"$game_id": {
"$user_id": {
//This validate rule fails
//".validate": "root.child('invites/'+$game_id+'/'+newData.val()).exists()"
//This one works
".validate": "root.child('invites/'+$game_id+'/uuidBBB').exists()"
}
}
}
}
}
The newData keyword is a special attribute referring to all incoming data, but it is not permitted in path expressions because it may not be a string. i.e., it could very well be an object.
If you're interested in using some portion of that data within the path, I would recommend just including another validation rule at a deeper path, such as:
{
"rules": {
".write" : true,
".read" : true,
"accepted_invites": {
"$game_id": {
"$accepting_user_id": {
"$sending_user_id": {
".validate": "root.child('invites').child($game_id).child($sending_user_id).exists()"
}
}
}
}
}
}
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
}
}
}
}