Where is the FireBase doc for $other - firebase

I´m learning FireBase and now at Using $ Variables to Capture Path Segments
' I read about the wildcard usage. I see they use this $othervariable.
Where is a list documentation of all variables that FireBase uses in the RealTime Databas Rules?

There is no $other variable. It's a placeholder and could be any string like $someOtherPath, or $dudesPath or $coolPath
From the docs:
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
The 'title' and 'color' paths are accounted for and have rules set.
$other is any path other than title or color. It could easily be
"$anyPathOtherThanTitleOrColor": { ".validate": false }

Related

How to allow a node to be created, updated and deleted by the creator but not by other users in Firebase?

My app's content is generated by the user. I want each user to access and edit his own data (the nodes he creates). So the user creates a "clips" node and a "clipOwners" node if the nodes are empty and he should also be able also to update any of these nodes and child nodes if he is the owner. Another user shouldn't be able to create a new node if the node pushKey (i.e. "$11111111") is already taken.
Here is my database structure:
clips {
variable Key >>> "111111111111" : {
"MACaddress" : "111111111111",
"comments" : "",
"created" : "Mon Apr 16 2018 12:40:13 GMT+0100 (BST)",
"inRoom" : "-LADDm48Uqabm1bcQGOw",
"ins" : {
"1523878813443" : true
},
"name" : "1",
"outs" : {
"1523878813443" : true
},
"ownerID" : "QpMHsVHHRrMvk92rbSQvcYEv4en1"
},
"222222222222" : {
"MACaddress" : "222222222222",
"comments" : "",
"created" : "Mon Apr 16 2018 12:40:13 GMT+0100 (BST)",
"inRoom" : "-LADDm48Uqabm1bcQGOw",
"ins" : {
"1523878813443" : true
},
"name" : "1",
"outs" : {
"1523878813443" : true
},
"ownerID" : "QpMHsVHHRrMvk92rbSQvcYEv4en1"
}
},
"clipOwners" : {
"111111111111": "QpMHsVHHRrMvk92rbSQvcYEv4en1"
"222222222222": "QpMHsVHHRrMvk92rbSQvcYEv4en1",
}
I am trying this but the "ownerID" child node keeps on being updated by another user if another user tries to write to the same $MACaddress:
"clips": {
".read": "true",
".write": "!data.exists() || newData.exists()",
"$MACaddress":{
"ownerID": {
".validate": "!data.exists() || newData.val() === root.child('clipOwner').child($MACaddress).val()",
}
}
},
"clipOwners": {
".read": true,
".write": "newData.exists()",
"$MACaddress": {
},
Why is it behaving like that?
Any ideas on how I can lock this thing?
In your current write rules you only check if data (not) exists. In this answer i will only focus on the write rules to make sure you can't have duplicate keys (see clipOwners rules) and you can only write to your own data (see clips rules):
"clipOwners": {
".read": true,
"$MACaddress": {
//Only create or delete are possible and value is the user uid
".write": "(!data.exists() || !newData.exists()) && (newData.val() == auth.uid || data.val() == auth.uid)"
}
},
"clips": {
".read": "true",
"$MACaddress":{
//The $MACaddress has to exist in the clipOwners node and its value has to be the user uid
".write": "root.child('clipOwners/'+$MACaddress).exists() && root.child('clipOwners/'+$MACaddress).val() == auth.uid"
}
}
When writing you first have to write the $MACaddress in the clipOwners node because this will be used to check if the user can write to the clips node.
You can take a look at these docs for a simular case.

how to make friends based on follow/follower , Swift Firebase

Currently my Firebase Database looks like this below. I have three users :I want to make feature like this, when one user follow another user and the user follow him back, they will be friends.They wont be friends until they are both follower of each other. So far I have managed to make the followers/following like this : Now I am out of clue what to do next.
Small disclaimer: I didn't get a chance to test this, let me know if it does what you want.
Under followers and following you seem to be using push keys to add the userID of the person that's being followed or that is following. Instead, I would simply add the uid as a child and set the value of that node to something random. Then when you want an user's followers you'd get all the keys instead of all the values.
DB Structure: I omitted anything irrelevant for the sake of brevity.
root: {
user_profile: {
$user1: {
followers: {
$user2: true,
$user3: true
},
following: {
$user2: true,
$user3: true
},
friends: {
$user2: true,
$user3: true
}
},
$user2: {
followers: {
$user3: true,
$user1: true
},
following: {
$user3: true,
$user1: true
},
friends: {
$user3: true,
$user1: true
}
},
$user3: : {
followers: {
$user2: true,
$user1: true
},
following: {
$user1: true,
$user2: true
},
friends: {
$user1: true,
$user2: true
}
}
}
}
I think using DB Rules would be the easiest way to do this.
Using these rules, a user would only be able to write to friends/$friend if the two users in question are following each other.
{
"rules": {
"user_profile": {
".read": true,
"$user_profile": {
".write": "$user_profile === auth.uid",
"friends": {
"$friend": {
".write": "(data.parent().parent().child('followers/'+auth.uid).exists() && data.parent().parent().child('following/'+auth.uid).exists()) && $friend === auth.uid"
}
},
"followers" : {
"$follower": {
".write": "$follower === auth.uid"
}
}
}
}
}
}
Small example on how to follow someone.
func follow(uid: String) -> Void {
// Obv you'd want to do some extra checks here such as whether the user is logged in or not, but for the sake of brevity they're omitted.
let dbRef = FIRDatabase.database().reference().child("user_profile")
let userID = FIRAuth.auth()?.currentUser?.uid
dbRef.child("\(userID)/following/\(uid)").setValue(true);
dbRef.child("\(uid)/followers/\(userID)").setValue(true);
dbRef.child("\(userID)/friends/\(uid)").setValue(true); // These should fail if the users aren't following each other.
dbRef.child("\(uid)/friends/\(userID)").setValue(true); // These should fail if the users aren't following each other.
}
And for unfollowing an user you'd do exactly the same only with .remove() instead of .setValue(true).

Firebase - Index rule for attributes under key created by ChildAutoById

I store my data on Firebase with the format
{
"list": [
"id created by Firebase": {
"foo": "bar"
},
"another id created by Firebase": {
"foo": "bar"
},
...
]
}
I would like to create an index on foo, using Firebase Rules.
However, according to Firebase doc, I need to know the specific ID created by Firebase to put in the rules specification.
Does anyone know of a way to get around this?
You don't need to know the specific ID, that wouldn't be possible. You simply need to have an .indexOn rule on the parent node. https://www.firebase.com/docs/security/guide/indexing-data.html
{
"rules": {
"list": {
".indexOn": ["foo"]
}
}
}
If you need to add additional rules for the children, then you add those normally like so:
{
"rules": {
"list": {
".indexOn": ["foo"],
"$item": {
"foo": {
".validate": "newData.isString()"
}
}
}
}
}

Restricting allowed keys in Firebase

Is there a way to only allow (but not require) keys in a Firebase object? I know you can use .validate to ensure that an object has certain keys. Is it possible to only allow certain keys, in a whitelist of sorts? If not, it seems like this would be a great way for unwanted/unnecessary data to make it into the database from malicious clients.
You can use Firebase's $ variables to disallow all non-specified children. From the Firebase guide on securing your data, comes this example:
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
So the widget node can have a color and/or a title property. But if it has any other properties, it will be rejected.
So these are all valid according to these security rules:
ref.child('widget').set({ title: 'all is blue' });
ref.child('widget').set({ color: 'blue' });
ref.child('widget').set({ title: 'all is blue', color: 'blue' });
But these are invalid according to the rules above:
ref.child('widget').set({ titel: 'all is blue' });
ref.child('widget').set({ title: 'all is blue', description: 'more...' });

Firebase: permission_denied -- cannot access newData.child()

This is the structure of my data
{
"projects" : {
"proj1" : {
"-JccS4StrTnJdTficR-u" : {
"name" : "consultation",
"status" : false
},
"-Jd6JlJUfyyZ2U0NTQEs" : {
"name" : "Words",
"status" : false
}
},
"proj2" : {
"-JccS6nwYHRrxvjZtCkt" : {
"name" : "Rework",
"status" : false
},
"-Jd6Jqa7-EPJuWxbtJAV" : {
"name" : "Review",
"status" : false
}
},
"proj3" : {
"-JccSJ5lEBQEg3XCbG-u" : {
"name" : "translation",
"status" : false
}
}
}
}
Here are my rules
{
"rules": {
".read": true,
"projects": {
"proj1": {
".write": "auth != null"
},
"proj2": {
".write": true
},
"proj3": {
".write": true,
".validate": "newData.child('name').isString()
&& newData.child('name').val().length < 10"
}
}
}
}
When I created the database, there was no rule. Now, I've created the rules. I want the length of the name to be less than 10 characters.
When I run the code, I'm getting the following error: FIREBASE WARNING: set at /projects/proj3/-Jd4n6XditTHLWKVmhC6 failed: permission_denied
I can't exactly tell why it's not working. I've also tried just this portion newData.child('name').isString(), but I'm still getting the same error.
Here is the code that push data to FireBase
function saveToFB(taskName, proj) {
// this will save data to Firebase
var project=projTasks.child(proj);
project.push({
name: taskName,
status: false
});
};
Looking at the structure of your data, as well as your rules, it looks like there is a missing level of data between "proj1"/"proj2"/"proj3" and the object that has name and status attributes.
Specifically, the .validate rules you have configured is checking the length of the name attribute for "proj3", not the new element added to the list there.
To get around this, try increasing the depth of the security rules definitions, and make use of the $wildcard functionality, where any security rules key prefixed with $ is treated as a wildcard with a name that you can reuse.
{
"rules": {
".read": true,
"projects": {
"proj1": {
".write": "auth != null"
},
"proj2": {
".write": true
},
"proj3": {
".write": true,
"$someChildElementHere": {
".validate": "newData.child('name').isString()
&& newData.child('name').val().length < 10"
}
}
}
}
}

Resources