data
data

Reputation: 749

Firebase: Allow access depending on time difference (server-side-time)

So I have a database that looks like this:

Posts
|
|
|----post_id_1
     |
     |---post_title = "...."
     |---post_body = "...."
     |---post_time = "ServerValue.TIME_STAMP"
|
|----post_id_2
     |.......
     |.......

What I want to do:

I want to prevent a user to read a post that is greater than or equal a month from the day that it was posted?

What I tried:

I tried to use this method by android:

//current time of device
long current_time = System.currentTimeMillis();
//month in millisecond
long month = .....;

if(curent_time - post_time >= month){

//this post was there for a month from the time that it was posted.

}

Problem:

If I use the above method then if a user was smart enough he/she will change the time of the device to enter a post (when they shouldn't).

Question:

Any stable way of doing this?

Thanks.

NOTE: WITHOUT GETTING THE TIME STAMP FROM THE SERVER.

Upvotes: 1

Views: 103

Answers (2)

Gastón Saillén
Gastón Saillén

Reputation: 13129

I have been through the same issue, how I solved that was pinging Google for the time, and then just store that time in Firebase, that way I can compare the last time the user did something and that time will be server time and can't be changed.

So, in my case I upload that server time each time my app enters in the onStop or onDestroy method, but you can use it anywhere you need to save to your database.

Here is the snippet to get server time, I use an asyncTask in order to fetch the server time and then just post it in my reference. Just call the asyncTask where you want to update something with server time.

public class getGoogleTime extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... voids) {
        try {

            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(new HttpGet("https://google.com/"));
            StatusLine statusLine = response.getStatusLine();
            if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
                DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.ENGLISH);
                dateStr = response.getFirstHeader("Date").getValue();
                Date startDate = df.parse(dateStr);
                dateStr = String.valueOf(startDate.getTime() / 1000);
                long actualTime = java.lang.Long.parseLong(dateStr);
                //Here I do something with the Date String

            } else {
                //Closes the connection.
                response.getEntity().getContent().close();
                throw new IOException(statusLine.getReasonPhrase());
            }
        } catch (IOException e) {
            Log.d("SAF_GTG_Response", e.getMessage());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    // can use UI thread here
    protected void onPostExecute(final Void unused) {

        mDatabase.child("Posts").child(post_id_1).child("currentTime").setValue(dateStr, new DatabaseReference.CompletionListener() {
            @Override
            public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {

                Log.d("SAF_GTG_TAG", "Success");

            }
        });


    }
}

To work with Firebase you can do this:

 ref = FirebaseDatabase.getInstance().getReference();    

    ref.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            Long timestamp = (Long) snapshot.getValue();
            System.out.println(timestamp);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

    ref.setValue(ServerValue.TIMESTAMP);

NOTE: this method just returns UTC time, you can convert it the way you want to display it to each user.

If you are worried about network usage, just ping Google and see how many bytes and packages are being used.

Pinging google.com [172.217.162.14] with 32 bytes of data:
Reply from 172.217.162.14: bytes=32 time=17ms TTL=53
Reply from 172.217.162.14: bytes=32 time=17ms TTL=53
Reply from 172.217.162.14: bytes=32 time=17ms TTL=53
Reply from 172.217.162.14: bytes=32 time=16ms TTL=53

Ping statistics for 172.217.162.14:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 16ms, Maximum = 17ms, Average = 16ms

From the docs:

The bandwidth consumption of a simple ping command, being run one time per second, is relatively small. The smallest ping packet possible (including the Ethernet frame header and the IP + ICMP headers, plus the minimum 32 bytes of the ICMP payload) takes 74 bytes

around 0,074 kilobytes.

Upvotes: 1

Adrian Rosca
Adrian Rosca

Reputation: 7412

I would store the TIME_STAMP as UTC and get the time from the server, not use the time from the device.

In that case the user cannot change the time on the device to modify the output from the database.

I would recommend to always store all dates as UTC and just convert them to the user timezone when the user views them.

Upvotes: 1

Related Questions