I'm using a structure for saving the users friends in the realtime database like this:
friends
$user_id:
-$friend_id1
-name: ""
-id: ""
-$friend_id2
(...)
My rules look like this:
"friends":{
"$id": {
".read": "auth != null && $id === auth.uid",
".write": false,
},
},
Within my iOS App I can access the friends of others although I should not be able to do so.
Also this seems to mainly be an issue in one single view, since when I'm changing the
"read": false
I can still read this data in that specific view.
In all other views however I can not do that, although the code is nearly the same (except for observing (.childAdded) instead of (.value).
I´m calling
let friends_ref = Database.database().reference().child("friends").child(self.friend_id)
friends_ref.observeSingleEvent(of: .value, with: { (snapshot) in
//CODE
})
Also, the time it takes to load the friends, so to get the callback, is very long taking even about >5 Seconds to get 5 friends.
How can this happen?
Best regards
Related
I am facing a puzzling situation with Realtime Database Rules.
The rules below are working, they allow me to write data to FirstCollection:
{
"rules": {
"FirstCollection": {
".read": true,
"$Section": {
".write": "(auth!=null)"
}
}
}
}
This second set of rules used to work until yesterday, and it no longer works:
{
"rules": {
"FirstCollection": {
".read": true,
"$Section": {
".write": "(auth!=null)&&((auth.uid=='98ab..myOwnUID..23YZ')||(auth.uid=='98ab..aSecondUID..23YZ'))"
}
}
}
}
I have checked everything I could think about including the exact value of myOwnUID.
Can any experienced user spot the issue or any mistake I could be making (or could have made)?
Here is the issue I was having. The rules have in fact nothing wrong.
What happens is that the code in my app is creating a new user with the auth.createUserWithEmailAndPassword API function. And since this function has the "annoying side effect" of signing in as the newly created user, when I then hit the rules in the flow of the app my auth.uid is no longer what I expect it to be, thus explaining why the rules fires.
I m using firebase Database .Planning to have quite a large data collection , I'm trying to use indexes . Making some tests, i don t know if rules i implement are correct let alone improve the queries .Is there a way to have a feedback on those indexations (correct or not, improve or not)
right now i have one class as described in the picture and i have the created the following rule
{
"rules": {
".read": true,
".write": true,
"users": {
"$user_id": {
".indexOn": ["user_id", "username"]
}
},
}
Since i get no feedback from firebase, i don t know if this is correct and improves anything .
Firebase's server-side rules are meaningless without seeing the code that exercises them.
But at a first glance it seems you're defining your indexes too low in the tree: indexes need to be defined at the location where you run the query. So if you want to run a query on /users, you need to define the indexes on /users:
{
"rules": {
".read": true,
".write": true,
"users": {
".indexOn": ["user_id", "username"]
}
}
}
This is a rough example of what my database looks like.
"userA": {
"uf": {
"userB": "0"
}
},
"users": {
"userA": "0",
"userB": "0",
"userC": "0"
}
And this is a rough example of the rule I am trying to write.
//USER ID
"$uid": {
//USER FRIENDS
"uf": {
//FRIEND USER ID
"$fuid": {
".write": "$uid === auth.uid &&
root.child('users').hasChild($fuid)",
}
},
},
And this is what I am trying to get working in the simulator
//Location /userA/uf/
//Data { "userC": "0" }
It seems that the security rule will always deny a write when the "key" for a data key value pair is a variable in my rules, in this case "$fuid". The simulator will return the messages "Simulated set denied" and "Write denied" but won't give me any additional details. I could get around this by writing the following.
//Simulation Method set
//Location /userA/uf/userC/
//Data { "0": "0" }
But this feels like it's writing unnecessary data to my database. What is the best practice here? Thanks.
Your rules give access to {uid}/uf/{fuid} but you're trying to write at {uid}/uf.
That {"0": "0"} is indeed unnecessary, you can just write "0".
If you want to write multiple friends at once, you can perform a multipath update, or modify your rules to allow writing directly at {uid}/uf and ".validate" the children.
Side note: if your users can be deleted, if user A has user B as a friend and user B is deleted, your rules won't allow user A to remove user B from the friends list. You should take care of that by changing the rules to allow the deletion of friends that do not exist, or by setting up an onDelete() triggered cloud function that would do the cleanup.
This is an odd one! I had a couple of developers building a mobile app using Firebase and React Native. They had everything working fine and left the company at the end of January. I have since picked this up to get it in to the hands of our staff. However I am running in to issues!
Before the guys left they added me to the Firebase account, I then created an iOS application in there and have made sure that I have changed the React Native code to point to the new Firebase iOS app.
That seems to be fine as users can log in with Facebook, their credentials are added to the Authentication table and they are given a UID. That UID is then used in our database as a primary key and appears to be added just fine, however at the next read/write attempt we get a permission denied error:
Error onDBEvent: Error Domain=com.firebase Code=1 "Permission Denied" UserInfo={NSLocalizedDescription=Permission Denied}
As this is code that I have not written I'm stabbing in the dark a bit as to where the issue may be, I think it is in this function:
export function likeDestination (destinationKey, score, taggedImageSetIndex, imageTagIndex) {
return function (dispatch, getState) {
const user = getState().auth.auth
let iTagIndex = imageTagIndex + 1
let updateValue = {}
updateValue[destinationKey] = score
console.log('likeDestination:: userID=', user.uid);
console.log('likeDestination:: taggedImageSetIndex=', taggedImageSetIndex);
// Set the user's preference for this tag then update (increment) the imageTagIndex
return firestack.database.ref(`user-data/${user.uid}/tagSets/${taggedImageSetIndex}/userScores`)
.update(updateValue)
.then(() => {
return firestack.database.ref(`user-data/${user.uid}/tagSets/${taggedImageSetIndex}`).update({imageTagIndex: iTagIndex})
})
.catch(err => {
console.log('Error in setting destination "like" data to Firebase:', err)
RouterActions.ErrorPage({ error: err })
})
}
}
It's worth stating that the console.log statements above return the correct values.
The only reference I can find for the getState function is below, not sure what the .auth.auth calls will do in order to get the user from the database but it seems to work!
export function getState (toggle) {
return {
type: GET_STATE,
payload: toggle
}
}
I've had a look through various posts around similar problems and they all seem to point to the rules in Firebase. The rules haven't changed since it worked and if I run those queries through the simulator I get a big tick next to the relevant read and write rule. Here are the rules for the DB:
{
"rules": {
"destination-scores": {
".read": true,
".write": false
},
"destinations": {
".read": true,
".write": false
},
"tv-admins": {
".read": "auth != null",
".write": false
},
"tv-queues": {
".read": "auth != null",
".write": "auth != null"
},
"tv-screens": {
".read": "auth != null",
".write": "root.child('tv-admins').child('ids').val().contains(auth.uid)",
".indexOn": "status"
},
"user-data": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
The queries in the code sample above are targeting the user-data rules and in the simulator that works fine, just not from the app. As I mentioned, the rules have not changed. What has changed is that the code is now running on my machine, as opposed to the original developer's, and there is a new iOS app created in Firebase.
As I also mentioned, I have ensured that I have replaced the old Firebase API key, messaging sender ID, Auth domain, DB URL and storage bucket with the new details. I believe this is working as users can log in via Facebook and get to the first stage in the app... at which point their user data has been added to the user-data table.
I'm new to Firebase and React Native so I'm not entirely sure where, in the code, this is happening but I suspect it may be this function:
export function connectUserData (firedb, user, authProvider, onUserDataChanged) {
const now = new Date()
return firedb.ref(`user-data/${user.uid}`)
.update({ email: user.email, connectedAt: now.toISOString(), authProvider: authProvider })
.catch(err => {
console.log('Error in updating meta data in connectUserData():', err)
throw new Error('Error in updating meta data in connectUserData()!')
})
}
This is called as part of an init function that checks if a user is authenticated... as in, they exist in the Authentication table/list in Firebase
I simply do not understand why I'm getting permission denied when I had permission, literally, seconds before! Any help would be much appreciated
Last night I was trying to index a nested object in firebase's database. Below is my object data and rules. Currently on orderedBy locID it is returning index not defined. Would appreciate any help thanks!
My Data:
My Rules:
{
"rules": {
"locations": {
"$uid": {
".indexOn": ["locID"]
}
},
".read": true,
".write": true
}
}
The code that triggers the error:
locData = db.child("Locations").order_by_child("locID").equal_to(someID).get()
The above is returning index not defined, using the pyrebase wrapper.
You're skipping a level in your query.
Firebase will query the immediate children of the location on which you execute the query. So in your case, it will query items 10S and 12S and try to order/filter on locID. Neither of these nodes has a child locID, since that property is one level deeper in the tree.
Pyrebase likely talks against the Firebase REST API, which will fail when there is no index for the field you're trying to order/filter on.
It's a bit hard to be certain for your use-case, but in general the solution to this problem is to keep a reverse index. In this case that could be a list that keeps track of the 10S/12S thing for each locID.
locByLocID: {
5689: "10S",
8223: "12S"
}