Firestore rule allow read condition timestamp problem - firebase

I am using firestore for the first time and I have a problem, I want to allow read if the message was send less than 5 minutes but it doesn't work.
service cloud.firestore {
match /databases/{database}/documents {
match /locations/{allDocuments=**} {
allow read: if request.time < Timestamp.fromMillis(resource.data.timestamp) + duration.time(0, 5, 0, 0)
allow write: if true;
}
}
}
Every data has a child call "timestamp" and the value is a number like "1554710156002"
With this read condition my app can't read anything but it can write.
Does someone know what the problem is?

Try using duration.time(hours, minutes, seconds, nanos) (documented here) to manipulate timestamps:
duration.time(0, 5, 0, 0)
Also, my personal preference is to put the duration after the (fixed) resource creation time, which makes reasoning about it a bit easier for me.
Your code would become
allow read: if request.time < resource.data.timestamp + duration.time(0, 5, 0, 0);
(NB: I did not verify this, and this is assuming your timestamp is actually a timestamp)

The controlling of read/write/update rights for users within a Firestore database is achieved via Firestore security rules that you would configure from within the Firebase console.

Related

Confused as to what this firebase rule means? Data not displaying from firestore database

The rule is
match /{document=**} {
allow read, write: if request.time <= timestamp.date(2022, 1, 31);
}
Does it mean that read and write permissions are valid only till Jan 31 2022?
The data is not displaying in UI anymore.
Yes, as long as request.time <= timestamp.date(2022, 1, 31) is true, users can read and write to Firestore. Those are the default rules so just in case you forget to secure your database, access will be denied after that time. You can always update that and extend the data or even better write security rules that match your needs.
Checkout Security rules - Get to know Cloud Firestore

Firestore security rules - read count in a batch

If in a batch I update documents A and B and the rule for A does a getAfter(B) and the rule for B does a getAfter(A), am I charged with 2 reads for these or not? As they are part of the batch anyway.
Example rules:
match /collA/{docAid} {
allow update: if getAfter(/databases/$(database)/documents/collA/${docAid}/collB/{request.resource.data.lastdocBidupdated}).data.timestamp == request.time
&& ...
}
match /collA/{docAid}/collB/{docBid} {
allow update: if getAfter(/databases/$(database)/documents/collA/${docAid}).data.timestamp == request.time
&& getAfter(/databases/$(database)/documents/collA/${docAid}).data.lastdocBidupdated == docBid
&& ...
}
So are these 2 reads, 1 per rule, or no reads at all?
firebaser here
I had to check with our team for this. The first feedback is that it doesn't count against the maximum number of calls you can make in a single security rule evaluation run.
So the thinking is that it likely also won't count against documents read, since it doesn't actually read the document. That said: I'm asking around a bit more to see if I can get this confirmed, so hold on tight.
Are you using two different documents?
If it is the case, then two reads will be performed.

Firestore request produces unexpected number of reads

After i execute my Firestore-Test-App made with Flutter i look at the Firestore analytics to see how many request my Test-App made. It shows me that i make a minimum of 20 up to 60 document reads with 1 start of the Test. The problem is, the test should result in a maximum of ~1-3 reads as i understand it.
I've read https://firebase.google.com/docs/firestore/pricing. It did help to understand the billing logic of firestore, but following that logic in the article i should be making a maximum of ~5 reads.
This thread: Firestore - unexpected reads also suggests that maybe, the document reads come from the opened Firebase console, viewing the documents. So i closed it before the test and opened it 30 min after. This did not change the result. I also set breakpoints and the code did only execute once.
I opened a completly new Flutter Project to test it.
This is the only part making read requests:
CollectionReference dbUsers = dbInstance.collection("Users");
var user = dbUsers
.where("docId", isEqualTo: fireAppUser.user.uid)
.limit(1)
.snapshots();
var _userSub = user.listen((value) {
if (value.documents.isNotEmpty && value.documents.first.data != null)
print(value.documents.first.data);
});
_userSub.cancel()
Below my firestore rule, which is on default settings for now.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
I have exactly 5 documents in my Database.
I expect to have a maximum of ~5 document reads. Please help me to undestand why this Snippet causes an unexpected number of reads. What could cause it?
Edit: forgot to append the cancel() to the snippet
That code can make a nearly unlimited number of reads, since it's adding a listener to the document. It will cost 1 read the first time you run it, and continue to incur reads as the listener remains added, as the document changes over time.
If the accounting doesn't make sense to you, contact Firebase support with your exact reproduction instructions.

Firestore rules, using short circuit to squeeze out reads

Are these two Firestore rules different at all in the number of reads that they spend from my quota? Note that isWebAdmin() does an exists(), which eats away from my read quota.
// example 1
match /companies/{company} {
// rule 1
allow list, write: if isWebAdmin();
// rule 2
allow get: if isInCompany(company)
// when isInCompany is true, this is short-circuited away
|| isWebAdmin();
}
vs.
// example 2
match /companies/{company} {
// rule 1
allow read, write: if isWebAdmin();
// rule 2
allow get: if isInCompany(company);
}
Here is my (possibly faulty) reasoning: For most get requests isInCompany(company) will be true and isWebAdmin() will be false. Therefore, in example 2, even though the user is authorized to get with rule 2, rule 1 will also execute because get is also a read. So, while trying to give the admin access, I'm spending more reads for regular users who have access.
In example 1, I separate out get and list and treat them separately. In get requests, it will not run rule 1 at all. When running rule 2, since isInCompany(company) is true, isWebAdmin() won't execute because of short circuiting. So, in the common case I saved a read by avoiding calling isWebAdmin().
Is this correct? If so, simply slapping admin privileges adds gets for each user's regular operation. I find this a bit inconvenient. I guess if this is not the case, we should be billed by only the "effective" rule, not everything that was tested. Is that the case instead?
With Firebase security rules, boolean expressions do short circuit, which is a valid way of optimizing the costs of your rules. Use the more granular rules in example 1 for that.

Firestore where query does not work [duplicate]

I want to create a FireStore rule that grantes read privilages to documents after the current date has surpassed a timestamp value in the document.
This is for a blog web application.
E.G a blogger sets a blog post to be available to the public on a certain date.
From reading the documentation this should work, but It dosn't.
service cloud.firestore {
match /databases/{database}/documents {
match /Articles/{article}{
allow read: if request.time.date() < resource.data.date
}
}
}
What I am i missing ??
firebaser here
I tried the same thing a while ago, and found out it isn't currently possible.
It is possible to allow/deny read to a specific document based on a property of that document.
It is possible to allow a query that filters documents based on a property in that document, but currently that is only possible based on request.auth.
This means that unfortunately your filter currently can't be implemented with security rules. I recommend you file a feature request to chime in.
Update (2018-04-24): this might now be possible with request.time, but I haven't had a chance to test yet. Have a look here.
NOTE: As this is my first answer on Stack Overflow, I wasn't allowed to comment on Frank van Pueffelen's answer, so just as a heads-up, the credits for this solution are his!
The request has a request.time which is a timestamp, and Firestore allows for basic math operators on timestamp <> timestamp operations, so your request.time < resource.data.date will work ;)
service cloud.firestore {
match /databases/{database}/documents {
match /Articles/{article}{
allow read: if request.time < resource.data.date
}
}
}
This is based on my personal testing on 2018.09.29
trying switching the < to >.
request.time will be the time of accessing the document while resource.data.date should be the creation timestamp of the document.
try using this for your security rules:
allow read: if request.time > (resource.data.timestampPropertyName + duration.time(1, 0, 0, 0));
duration.time(4, 3, 2, 1) will create a four hour, three minute, two second, one nanosecond duration.
More information can be found at:
https://firebase.google.com/docs/firestore/reference/security/#timestamp
Do remember to wait for sometime after saving your security rules for it to take effect!
Answer of #user776914 is nice but what if there are diff timezones
Lets add +- 27 hours to be sure it was e.g. created in that day +- 1
duration.abs(request.time - request.resource.data.created) < duration.value(27, 'h')
What's max timezone offset
I wanted to do a similar thing for a game. I wanted to activate and deactivate a game object only after a particular date. I used google's cloud functions to do it. I deployed a function that runs every day to check the firestore documents and changes values according to the script.

Resources