I was testing some changes to my firebase and accidently submitted 100's of updates to a reference. Now when I try and delete the reference it then creates a new reference with different data.
I have tried deleting everything in the firebase but it will just keep creating a new reference.
In this specific example I used set() to add 5 random values to a user name Michael. The 5 random values were called 100's of times and now when I delete the Michael user to test again it already has a value queued up and recreates itself immediately. I looked at my upload usage and it showed a huge amount of data being uploaded at one point that coincides with this error.
Any idea how to remove these queued up changes?
Make sure to disconnect the client that is writing this data. I suspect somewhere you have a process running that is generating these writes.
If you can't stop the offending process for some reason, you could always modify your security rules to deny access to the client that's doing the writes (or if it's a server using a Firebase Secret to authenticate, you could revoke its secret).
I've had a similar issue - think it has to do with your session / caching.
Try logging out of firebase and back in - if the records are still there, make a backup of your security rules, then use:
{
"rules": {
".read": false,
".write": false
}
}
and delete them.
Related
In my Flutter/Dart mobile app I make use of Firebase RTDB persistence to enable offline use of the app.
My understanding is that to enable persistence you have to make the call, as per the following piece of code, before using any database references to eg. query the database. I use the following piece of code to enable persistence immediately after loading the app and it works fine:
FirebaseDatabase firebaseDatabase = FirebaseDatabase.instance;
bool _success = await firebaseDatabase.setPersistenceEnabled(true);
print(_success); // Prints true, so persistence is set 'on'.
When I logout of the app I attempt to turn persistence off with:
bool _success = await firebaseDatabase.setPersistenceEnabled(false);
print(_success); // Prints false, so persistence is still 'on', ie. the call failed.
I assume the reason persistence cannot be turned off is because there have been calls to db references prior to trying to switch it off.
This leads to three questions, I guess:
Should I be worried about turning it off at all, when I logout? The reason I attempt it is good house-keeping, mainly. I clean up shared preferences, close keepsyncd's, etc when logout is run. Also, though, the user can have multiple userids to login and I want to make sure that I am not retaining persisted data from their previous login id.
Related to 1, does setting persistence to false clear the cache of
data and potential queued calls to the db?
If the answers to 1 and 2 are 'yes', how can I switch persistence off given the code I'm using to do so keeps telling me it failed?
The typical way to handle this is to enable persistence once a user logs in.
Once disk persistence has been enabled and your app has used the database, it cannot be turned off. The documentation says this about it:
The returned Future will complete with true if the operation was successful or false if the persistence could not be set (because database references have already been created).
That last bit is clearly the case for you: you've been using the database already, which means that disk persistence is on.
To your specific questions:
Unfortunately the data in the local cache cannot be cleared up through the API at the moment. It is a valid feature request, but for now you'll have to assume that any data on the device can be seen by any user on that device (or device profile).
Disabling disk persistence keep the client from adding data to the cache. It does not clear any existing data in the cache.
Good morning!
I am working on a Firebase project in my Unity game and am working on securing the data in the database, however whenever I update the rules, it breaks my (otherwise working) handlevaluechanged function.
The data structure looks like this:
User_List ->
Firebase_User_ID ->
Health: 100,
Name: Foo,
etc ....
I want the rules (at a minimum, I'll add validation later) for this data to be:
"USER_LIST":
{
"$UID" :
{
".read": "auth.uid === $UID",
".write" : "auth.uid === $UID",
}
},
Locally in the game, I get a reference with this call:
FirebaseDatabase.DefaultInstance.GetReference("USER_LIST").Child(USER_ID).ValueChanged += HandleValueChanged;
If I set the rules to:
".read": true,
".write" : true
everything works as expected. The client can update the database, and handlevaluechanged does its job of keeping the local data synced. When I switch the to the rules above where I verify the auth ID, the client still works. It can update the database no issues, provided the correct user ID is signed in. However, my Handlevaluechanged gets a permission denied error from firebase, as if the handlevaluechanged listener does not supply the proper user ID when it attempts a read from the DB.
I'm puzzeled because the rules allow me to get the reference in the first place, and update the database from the client, but I can't update the client from the database? What am I missing?
I have also tried to GetReference at the USER_LIST node instead of the USER_ID node with the same result.
Any insight would be greatly appreciated! Thank you in advance.
After ignoring this issue for a while and working on other bugs, I discovered the true issue and wanted to post in case anyone else finds themselves in this pickle.
I had a Unity scene dedicated to signing in users that created the authenticated Firebase user, then jumped to a new scene. In that new scene, I searched for the local user object created by when the user logged in, and then I set up the database reference and the handleValueChanged listener.
I think the issue was that searching for the user was being done asynchronously (I have not done more research to confirm this, but my testing in this specific case seems to suggest this is the case), so the task was started, and while it was looking for the user credentials, it created the DB reference and added a listener with a null user. Afterwards, the task completes and the user is no longer null, but the listener is already listening.
Then, if I did a database read or write, the call for read or write was from an authenticated user and would execute provided the RTB rules were satisfied. Successful writes would trigger the handlevaluechanged listener and draw up a permission denied error due to the listener not having an authenticated user ID associated with it (again, I reached this conclusion based on observation and testing with this specific project, not research).
Simply adding the DB reference to my local user object after it was created instead of searching for the user and then establishing the reference solved all of my issues.
I hope this helps!
How could I set rules to restrict someone access child node form machine?
for example :
00041802000001,00041802000002,00041802000003,...etc
My rules are:
{
"rules": {
"machine":{
"$machine":{
".read": "data.child('giftIn').val() >10"
}
}
}
}
But it don't work, permission problem happened:
Listener at /machine failed: permission_denied
what rules could make someone access 00041802000002 only?
You're granting access to each specific individual machine. This means that you can access each machine once you know its key (e.g 00041802000002).
But you're then trying to read all machines: /machine. Since you don't have read permission there, the read is rejected.
You will either need to grant access to read all machines, or read a specific machine.
If you were expecting that reading /machine would filter the child nodes to only return the ones with a giftIn value of greater than 10, you're unfortunately in for a disappointment. Firebase security rules cannot be used to filter out data. The reason for this is that the rules are enforced when you attach a listener, not for every individual child node.
If this fact that rules cannot filter data is new to you, I recommend you study the documentation section on it as well as some of the many previous questions on the topic.
I would like to increment a count in Firebase, but without exposing the the current count to client.
I have read numerous helpful answers about using transactions to increment counters in Firebase, but all of these assume that the client has "read" access to the counter element. What if the client shouldn't have read access to the count, but I want to increment the value based on the user's actions?
Example:
Suppose I want to track views or impressions (or some other user action) on a specific piece of content. The counts are for internal eyes only, and perhaps to be shared privately with advertisers and partners -- but not shown to the users themselves, and we don't want to share that data with competitors by exposing it to the browser.
For cases like this, I could route things through a server process, in which the server process fetches the count and increments it, but that kinda defeats the purpose of using Firebase in the first place. Are there any other options to increment a "private" counter from the browser?
I'm not sure why you're getting downvoted, as it seems like a valid question to me.
There is no server-side way to increment a counter in Firebase. With that knowledge, the only way to currently increment a counter is to have the client perform the increment. While you can secure that with rules to ensure that each user can only increment once, that each increment is a single step and many other things, the client-app will have to be able to read the current value.
The common solution to your problem would be to introduce a tally server. Each client can write it's "I've viewed this content" record into the database and then you have a server that listens to this queue and updates the count.
viewQueue
$pushId
uid: <uid>
itemId: <itemId>
viewCounts
$itemId: <totalViewCount>
You could secure this so that users can only write to the view queue and only the server (which likely will run under a service account can access the view counts:
{
"rules": {
"viewQueue": {
".read": false, // only the server can read this
"$pushid": {
".write": "newData.exists() && !data.exists()"
}
},
"viewCounts": {
// only the server can access this
".read": false,
".write": false
}
}
}
Is there any way to write a security rule or is there any other approach that would make possible only for currently connected (not authenticated) user to write/read certain location - admin should also be able to write/read?
Can a rule be written that disallows users to read of complete list of entries and let them read only entry that matches some identifier that was passed from client?
I'm trying to exchange some data between user and Node.js application through Firebase and that data shouldn't be able to read or write by anyone else other than user and/or admin.
I know that one solution would be that user requests auth token on my server and uses it to authenticate on Firebase and that would make it possible to write rule which prevents reads and writes. However, I'm trying to avoid user connecting to my server so this solution is not first option.
This is in a way session based scenario which is not available in Firebase but I have
some ideas that could solve this kind of problem - if implemented before session management:
maybe letting admin write into /.info/ location which is observed by client for every change and can be read only by active connection - if I understood correctly how .info works
maybe creating .temp location for that purpose
maybe letting admin and connected client could have more access to connection information which would contain some connection unique id, that can be used to create location with that name and use it inside rule to prevent reading and listing to other users
Thanks
This seems like a classic XY problem (i.e. trying to solve the attempted solution instead of the actual problem).
If I understand your constraints correctly, the underlying issue is that you do not wish to have direct connections to your server. This is currently the model we're using with Firebase and I can think of two simple patterns to accomplish this.
1) Store the data in an non-guessable path
Create a UUID or GID or, assuming we're not talking bank level security here, just a plain Firebase ID ( firebaseRef.push().name() ). Then have the server and client communicate via this path.
This avoids the need for security rules since the URLs are unguessable, or close enough to it, in the case of the Firebase ID, for normal uses.
Client example:
var fb = new Firebase(MY_INSTANCE_URL+'/connect');
var uniquePath = fb.push();
var myId = uniquePath.name();
// send a message to the server
uniquePath.push('hello world');
From the server, simply monitor connect, each one that connects is a new client:
var fb = new Firebase(MY_INSTANCE_URL+'/connect');
fb.on('child_added', newClientConnected);
function newClientConnected(snapshot) {
snapshot.ref().on('child_added', function(ss) {
// when the client sends me a message, log it and then return "goodbye"
console.log('new message', ss.val());
ss.ref().set('goodbye');
});
};
In your security rules:
{
"rules": {
// read/write are false by default
"connect": {
// contents cannot be listed, no way to find out ids other than guessing
"$client": {
".read": true,
".write": true
}
}
}
}
2) Use Firebase authentication
Instead of expending so much effort to avoid authentication, just use a third party service, like Firebase's built-in auth, or Singly (which supports Firebase). This is the best of both worlds, and the model I use for most cases.
Your client can authenticate directly with one of these services, never touching your server, and then authenticate to Firebase with the token, allowing security rules to take effect.