I'm using Firebase Real-Time Database as backend.
I want it to increase by 1 max for each request
For example:
"Counter":{
".write":"true",
".read":"true,
".validate":"data.val()+1"
}
This is not working.
On the frontend, I'm sending "data+1". How should i create ".validate" rules?
To validate that the new value is one higher than the existing value:
".validate":"newData.val() === data.val() + 1"
Also see the Firebase documentation on Existing Data vs. New Data.
Related
I am developing a simple chat website using Firebase Firestore. And it obvious to store the message time .
Now the thing is that document is added from client side. So malcius user can add document with fake time. Is there any way avoid the scenario.
I have tried using cloud functions but it's taking too long lo send message..
You want to set the message time property to equal Firebase Server timestamp which on submit will set it on the creation of the message using request.time you can validate it equals now.
Security Rules
allow create: if request.resource.data.messageTime == request.time &&
// other rules for the message body
Client side JS code
const message = {
text: 'Hello',
messageTime: firebase.firestore.FieldValue.serverTimestamp();
}
I want to send the creation time of a Firestore document through the client and verify the time with Firestore Rules to avoid Cloud Functions calls (pricing).
Scenario
I am testing requests from clients against Firestore rules like this:
allow create: if request.resource.data.TIMEFIELD == request.time;
The request contains a TIMEFIELD that has a timestamp, just like request.time.
Problem
Apparently the request time and the time I am setting as a field right before sending the request are not equivalent, which makes this comparison impossible.
The following is the defition of request.time from the documentation.
When the request was received by the service.
I wonder if there is a way to set a field in a document equal to request.time.
I am unable to use server side timestamps because of an issue with Flutter.
Because of that I need to know how I could possibly validate client side timestamps like time.now with Firestore Rules.
You can use the Timestamp to add constraints to the time field (docs).
Here is an example of how to ensure that the change was within a certain amount of seconds:
function withinSeconds(secs) {
return request.resource.data.TIMEFIELD.seconds() - request.time.seconds() <= secs
&& request.resource.data.TIMEFIELD.seconds() - request.time.seconds() >= -secs
}
Edit
The above is for setting the value within a threshold of the request.time.
You can also just use the REST API in the mean time. Just make a write request that includes an update and a transform. The transform is where you would set the server timestamp. Here is a tool to help understand how to build the requests.
This has been implemented into the Flutter plugin for Cloud Firestore:
FieldValue.serverTimestamp()
Using this as a field's value will assign a timestamp equal to request.time to the field, server-side.
You can find out more about it in the API reference for cloud_firestore.
you'd first have to remember the creation (or last updated) timestamp:
firestore().collection("items").add({
....
created: firebase.firestore.FieldValue.serverTimestamp()
});
in order to let the client know of the timestamp, which you are trying to compare later on.
I'm building a very simple JavaScript-based Firebase app that increments a key's value by 1 whenever my webpage is loaded. I don't want any authentication friction, so want to use either an open database, or one restricted to anonymous authentications. So, for example's sake:
$(document).ready(function() {
// after config and initialize...
var fb = firebase.database();
var fbCount = fb.ref("count");
fbCount.transaction(function(current) {
return current + 1;
});
});
In either case, as I understand it, there is nothing to stop anyone who can access the page from copying my code (including my initialization config) and using it on their own server--with adjustments--to not only increment the value (fbCount above), but to change the code in any other way they like (e.g. letting them increment the value by 100, 1000, or changing it to something else entirely).
My further understanding is that the best way to deal with this potential is through security rules. So what I'm trying to figure out is whether there's a way, through the security rules, to limit any write to only an increment by 1 of the current value?
If not, is there another method I should be investigating?
You'll want to make use of predefined variables. Your validation rule will look something like this (at the location of the field you want to protect):
".validate": "newData.val() == data.val() + 1"
This talk mentions time-expiring data using Firebase rules at 22:55
https://www.youtube.com/watch?v=PUBnlbjZFAI
How can one do this ?
I didn't find any information regarding this.
I recommend two solutions.
1) Use cloud functions to record a message path and the date it was posted. Then every hour sort that list by date, pick all the expired ones, and create a deep update object to null out every expired message. Nowadays you can use Cron Scheduler to handle the periodic flush.
2) Make a rule that says anyone can delete expired messages and make it so that clients automatically delete expired messages when they are in a chat room.
Written here: https://firebase.google.com/docs/database/security/securing-data
You can't have it auto delete your data but you can make them unreadable (which is the same thing from the user standpoint). Just send a timestamp child field with you data and check against it.
{
"rules": {
"messages": {
"$message": {
// only messages from the last ten minutes can be read
".read": "data.child('timestamp').val() > (now - 600000)",
// new messages must have a string content and a number timestamp
".validate": "newData.hasChildren(['content', 'timestamp']) && newData.child('content').isString() && newData.child('timestamp').isNumber()"
}
}
}
}
Same question here.
You can't do it using firebase rules. You should either have a NodeJS backend removing your old data or clients doing it for you. For example, before a client retrieves data, he could remove old data.
Is it possible to check how many posts a user already have associated to them, and if that count exceeds a certain limit, then invalidate the request to create a new post?
I was thinking about having some basic settings at: /settings/limits/posts = 5.
And in the rules have something like:
".write": "root.child('settings/limits/posts').val() <= root.child('users/' + auth.id + 'posts').numChildren()"
That doesn't work, because numChildren isn't available. So how do you do such a check?
The only solution I've come up with, is to have a external server to do a count of a user's existing posts and only allow the server to write new posts.
Anybody else got any suggestions?