1

I have the following problem: client side I create a document containing the timestamp:

  db.collection('users')
  .doc(userId)
  .set({
    .....
    timestamp: firebase.firestore.FieldValue.serverTimestamp(),
  })

After that I update it via:

  db.collection('users')
  .doc(userId)
  .update({
    .....
    timestamp: firebase.firestore.FieldValue.serverTimestamp(),
  })

In Firestore rules I have done:

match /users/{userId}{
  allow create: .......
  allow update: if request.auth != null && request.auth.uid == userId && 
                (
                   (request.resource.data.diff(resource.data).affectedKeys().hasOnly(['name', 'description', 'timestamp'])
                      && (request.resource.data.name != resource.data.name || request.resource.data.description != resource.data.description)
                      && request.resource.data.name is string && request.resource.data.name.matches(".*<.*") == false
                      && request.resource.data.description is string && request.resource.data.description.matches(".*<.*") == false
                      && request.resource.data.timestamp>resource.data.timestamp
                 )

The problem is on the last line:

request.resource.data.timestamp>resource.data.timestamp

I would like not only the current timestamp to be greater than the timestamp saved in the document, but also for there to be a difference of at least one day, so as to prevent a user from continuously editing a document. How can I solve this problem?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
sirss
  • 171
  • 1
  • 9
  • 1
    Also see [How do I implement a write rate limit in Cloud Firestore security rules?](https://stackoverflow.com/questions/56487578/how-do-i-implement-a-write-rate-limit-in-cloud-firestore-security-rules) – Frank van Puffelen Nov 06 '22 at 15:17

1 Answers1

2

The request.resource.data.timestamp does not ensure that user has used serverTimestamp() and can by any timestamp. If you want to compare a the timestamp field with current time, it's best to use request.time. Try the following rule:

allow update: if request.time - resource.data.timestamp > duration.value(1, 'd') && ...other_conditions;

Checkout the documentation to learn more about rules.timestamp and rules.duration.

Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
  • I don't think OP has a requirement for the `timestamp` value to be *now*, as long as it's at least one day after its current value. So I actually recommend checking `request.resource.data.timestamp - resource.data.timestamp > duration.value(1, 'd')`. – Frank van Puffelen Nov 06 '22 at 15:16
  • 1
    @FrankvanPuffelen I thought it might prevent user from passing a future timestamp (even if it's been only 1 hour since last update) in request body for the rule to pass. – Dharmaraj Nov 06 '22 at 15:23
  • 1
    I agree it's a useful check, but the question seems to be about the date diff. You cover that too (hence my upvote), I just wanted to point out that the comparison to `request.time` is not strictly needed (and I'd typically separate that check - shown in my answer to the question I linked above). – Frank van Puffelen Nov 06 '22 at 15:32
  • thank you both , that was what I was looking for. And thanks also for the advice about the request.time – sirss Nov 06 '22 at 23:46