Let’s say for instance a user writes about an event to the Firebase database, what the user writes has a time stamp attached to it and other users are able to read what was
There's a big difference here between whether you have a single item, or a list of items.
If you have a single node like this in your database:
"content": {
"expiresAt": 1565275079920,
"content": "This content is only readable until Thu Aug 08 2019 07:37:59 GMT-0700"
}
You can ensure this node is only readable until its expiry timestamp with these rules:
{
"rules": {
"content": {
".read": "data.child('expiresAt').val() < now"
}
}
}
When somebody attaches a listener to /content
up until the expiry timestamp it will be allowed, after that any new listeners will be rejected.
But things get more complicated when you have a list of data as:
Combined these two fact mean that security rules cannot be used to filter data.
So if you have a list of these nodes above:
"content": {
"-Ldshdh13...": {
"expiresAt": 1565275079920,
"content": "This content is only readable until Thu Aug 08 2019 07:37:59 GMT-0700"
},
"-Ldshdh13...": {
"expiresAt": 1565277079920,
"content": "This content is only readable until Thu Aug 08 2019 08:11:19 GMT-0700"
},
...
}
In order to be able to query this data, the user must have read permission on /content
. And as soon as they have full read permission on /content
, you can't keep them from reading certain nodes under there.
The only way to make this scenario work is to use a combination of a query and a security rule that validates this query.
Step 1: query for only the data that you're allowed to read
So if you should only be able to read data that expires in the future:
var ref = firebase.database().ref('content');
ref.orderByChild('expiresAt').startAt(Date.now()).once('value',...
Step 2: use security rules to only allow reads with this query
The security rules will now check whether the user is passing the correct orderBy
and value in to their query so that they're only accessing non-expired data:
{
"rules": {
"content": {
".read": "query.orderByChild == 'expiresAt' &&
query.startAt >= now"
}
}
}
A few things still to note:
now
is only checked at that moment, it doesn't get modified in any way after that. This is usually not a security problem, but means you will need to remove outdated data in the application code too after attaching the listener.Date.now()
in the client and the now
in the rules may not be exactly the same. Adding a few seconds in the security rule may be a good idea.For further reading, I highly recommend: