Reputation: 749
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
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
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