wordpress-mobile / WordPress-Android

WordPress for Android
http://android.wordpress.org
GNU General Public License v2.0
2.97k stars 1.32k forks source link

Posts with future publish dates are not scheduled if the device's date is set in the future #20914

Open fluiddot opened 4 months ago

fluiddot commented 4 months ago

Expected behavior

The post is scheduled.

Actual behavior

The post is published at the current date and time (i.e. now).

Steps to reproduce the behavior

  1. Set the device's date and time to the future.
  2. Open the app.
  3. Create a draft post.
  4. Tap on Publish and Publish Date option.
  5. Set the publish date to be in the future but before the device's date and time previously set.
  6. Observe the publish button says "PUBLISH NOW". This is somewhat expected as the device's date is in the future.
  7. Publish the post.
  8. Observe that the post is under the Published section instead of being scheduled.
  9. Open the post and navigate to the post settings.
  10. Observe that the publish date is different from the one set and matches the actual "now" date and time.

[!NOTE] This case works as expected when publishing on the browser and the iOS app. The post is scheduled.

Tested on Samsung Galaxy S20 FE 5G, Android 13, JPAndroid / WPAndroid 24.9
dangermattic commented 4 months ago

Thanks for reporting! 👍

zwarm commented 4 months ago

During Hack Week, I investigated an issue and found some interesting results. When a device's date is set to the future, the app consistently encounters the following Volley error on any "post" REST call (e.g., login, post uploads, media uploads):

com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: Chain validation failed
Caused by: java.security.cert.CertPathValidatorException: Response is unreliable: its validity interval is out-of-date

The root cause appears to be the device's date being set to the future, though this might also indicate an SSL certificate issue. I observed that setting the date more than 5 days ahead triggers this problem on both physical devices and emulators. This Volley error is transformed into a "generic_error," resulting in the following user message:

"There was an error uploading this post: We couldn't complete the action, and didn't publish this post."

(There are similar variations for media uploads and different messages for login errors.) The error message is accurate, reflecting the app's best response to the situation. Unfortunately, there is no way to recover from this type of error.

As part of my investigation, I developed a proof of concept (POC) that sends a request to the "time.google.com" NTP server and compares the response against System.currentTimeMillis(). This method can then be used to inform users if their device date is not set automatically, which could prevent these errors.

What are your thoughts on implementing this solution?

Tested with: Pixel 3XL, Android 12. And numerous emulators running up to API 34.

This case works as expected when publishing on the browser and the iOS app. The post is scheduled.

Red herring. This is strictly an Android networking issue. :(

Recreate the issue
**Steps to recreate the post failure** - Navigate to device settings and make sure the device date/time is "Set automatically" - Install the app (use production build) - Login, navigate to post, create a new post, and and tap publish > publish now - The post should be published - Open the device settings again - Navigate to settings > set the date/time to manual and select a date 5 days in the future (If I test on 5 June, then I set the date >= 10 June) - Navigate to App Info for the App and **Force Stop the app** - Relaunch the app - Navigate to post, create a new post, and tap publish > publish now - The post will fail - You can try to upload media at this point, and it too will fail **Steps to recreate the login failure** - Uninstall the Jetpack app - Navigate to device settings > set the date/time to manual and select a date 5 days in the future (If I test on 5 June, then I set the date >= 10 June) - Install the app (use production build) - Attempt to login - The login will fail I did experience instances were if you don't "Force stop the app" the connection will still allow "post" rest call to go through, but eventually it will stop working.
zwarm commented 4 months ago

Update: Following a chat with @AjeshRPai, he proposed an alternative approach: rather than validating the date against an NTP server, we could ensure that the device's date and time are set to automatic. This idea sounds promising and I believe it's the one we should move forward with. By combining this idea with capturing the volley error, we can effectively communicate with the user and significantly reduce the occurrence of network error messages.

fluiddot commented 4 months ago

This idea sounds promising and I believe it's the one we should move forward with. By combining this idea with capturing the volley error, we can effectively communicate with the user and significantly reduce the occurrence of network error messages.

Great idea. Communicating to the user that the date and time are incorrect will solve this problem but also probably other issues they might have elsewhere 👍 .

zwarm commented 4 months ago

I didn't get a chance to address this during hackweek, and I'm uncertain when I'll have the time to do so, so I'm sharing a few notes.

In the context of SSL/TLS certificate validation, the date/time discrepancy can lead to issues because SSL certificates have a validity period, which consists of a "not before" and "not after" date and time. These dates define the range of time during which the certificate is considered valid. In the scenario where the user has the disabled the date/time automatically setting, the date can be set to the future, the past, or even align with the current date; however it must be a in the valid range for the certificate or we won't be able to communicate with the server. When that happens we experience an error like the one in the description above.

This network (volley) error is captured in the base layers; however, the messages are not propagated down the line nor are they captured in the logs. Consequently, the caller receives a "generic error", which is not sufficiently informative for them to use it as a basis to check whether the "automatic date/time" setting is enabled on the device.

There are a few things to consider before diving into an implementation:

One potential solution is to specifically handle this error for post updates and login (the two most critical areas), and leave other areas as they are. Alternatively, we could implement a check for the device settings and display a popup notification, similar to what we do for no network connection upon app launch.