Unkn0wn0x
Unkn0wn0x

Reputation: 1167

Firebase Database Rules Timestamp Issue

Since the time shift at the 29th of October 2017 I'm running in some really strange behaviours while developing with the firebase products.

I'm developing a hybrid app with Ionic (3). While I'm developing and testing in the browser (mobile emulated device) everything works fine. As soon as I switch to my real device (Samsung Galaxy S7, no root, modded or something else), all writes to the database with a timestamp are failing.

In my code I create a timestamp like this: Date.now()

In my firebase rules I validate timestamps usualy like this:

"timestamp": { ".validate": "newData.isNumber() && newData.val() <= now" }

For me this rule means, that the new data, which wants to be written into the database, must be a number and the value of the new data must be less than or equal to the current server timestamp. If one of these conditions doesn't match, it will throw a warning at the client.

I've spent a whole day debugging my code and finding the bug. When I remove (comment out) the .validate key on the timestamp related rules, everything works fine.

So I played a little bit with the timestamp values in the firebase rules. For example I added a little buffer to the server timestamp like: (now + 10000) (10secs).

Suddenly it worked. I decreased the value until it stopped working on my real device. I stopped at (now + 5000) (5secs).

So now my question is, why this behavior is the way it is.

Before the time shift, everything worked fine. In my understanding it couldn't be possible that a client timestamp is ahead of the server timestamps. (except the local time on the real device was modified by the user itself).

Looking for some help, the workaround with the additional 5 secs seems a bit dirty.

Cheers Unkn0wn0x

BTW: Each time I modified the firebase rules and deployed them to the server(s), I've waited for about five minutes.

Upvotes: 2

Views: 1491

Answers (1)

Unkn0wn0x
Unkn0wn0x

Reputation: 1167

Thanks for Your annotation.

I've played one more time with the timestamps and figured out the unwanted behaviour.

This is the code, I've added to my function with wants to write a timestamp to the database:

const test  = Date.now();
const test2 = new Date().getTime();
console.log('server offset: ', snap.val());
console.log('Date.now(): ', test);
console.log('new Date().getTime(): ', test2);
console.log('estimated server timestamp (new Date().getTime() + offset): ', (test2 + snap.val()));
console.log('client timestamp (Date.now() - offset): ', (test - snap.val()));

The output of the above code:

server offset: -2427
Date.now(): 1509730244926
new Date().getTime():  1509730244926
estimated server timestamp (new Date().getTime() + offset): 1509730242499
client timestamp (Date.now() - offset): 1509730247353

The crux here is the negative offset. I've substracted the server offset from the client timestamp to get a timestamp, which is smaller then the estimated server timestamp.

But: - and - is +. So I accidentally added them both together instead of subtract from one another.

I've executed my function a few times and could determine, that the offset is from execution to execution different. One time +77 ms the other time -2427ms, etc..

So I added a little code snippet, which checks if the returned server offset is a postive or negative number, to be able to calculate the client timestamp correctly.

const serverOffset: number = snap.val();
let clientTimestamp: number = null;

if (Math.sign(serverOffset) === 1){
    clientTimestamp = Date.now() - serverOffset;
} else if (Math.sign(serverOffset) === -1){
    clientTimestamp = Date.now() + serverOffset;
}

clientTimestamp works now as expected.

This behaviour can also be achieved if the offset is just added up to the client timestamp as mentioned in the Firebase Docs.

Maybe it should be mentioned in the Firebase Docs, that the offset can also be negative instead of just postive. This behaviour can be easily reproduced, if the local device time runs just a second later than the time, which is fetched from the internet.

But why does this suddenly occur and never before?

Upvotes: 1

Related Questions