diff --git a/app/src/main/java/io/github/vvb2060/keyattestation/attestation/AuthorizationList.java b/app/src/main/java/io/github/vvb2060/keyattestation/attestation/AuthorizationList.java index 5d371bc..10b66de 100644 --- a/app/src/main/java/io/github/vvb2060/keyattestation/attestation/AuthorizationList.java +++ b/app/src/main/java/io/github/vvb2060/keyattestation/attestation/AuthorizationList.java @@ -532,8 +532,10 @@ private static String joinStrings(Collection collection) { } public static String formatDate(Date date) { - return DateFormat.getDateTimeInstance().format(date); - } + java.text.DateFormat df = java.text.DateFormat.getDateTimeInstance(); + df.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); + return df.format(date) + " UTC"; + } public static String paddingModesToString(final Set paddingModes) { return joinStrings(transform(paddingModes, forMap(paddingMap, "Unknown"))); @@ -942,4 +944,4 @@ public String toString() { } return s.toString(); } -} +} \ No newline at end of file diff --git a/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RevocationList.java b/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RevocationList.java index 6420f2e..b7110e5 100644 --- a/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RevocationList.java +++ b/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RevocationList.java @@ -21,13 +21,14 @@ import io.github.vvb2060.keyattestation.R; public record RevocationList(String status, String reason, DataSource source) { - public enum DataSource { + public enum DataSource { + NETWORK_INITIAL, NETWORK_UPDATE, NETWORK_UP_TO_DATE, CACHE, BUNDLED } - + private static final String TAG = "RevocationList"; private static final String CACHE_FILE = "revocation_cache.json"; private static final String PREFS_NAME = "revocation_prefs"; @@ -83,6 +84,15 @@ private static NetworkResult fetchFromNetwork(String statusUrl, long cachedTime) connection.setReadTimeout(10000); connection.setRequestProperty("User-Agent", "KeyAttestation"); + double rand = Math.round(Math.random() * 1000.0) / 1000.0; + + // Force the CDN to bypass edge caches + connection.setRequestProperty("Cache-Control", "no-cache, no-store, no-transform, max-age=0"); + connection.setRequestProperty("Accept", "application/json, */*;q=" + rand); + connection.setRequestProperty("Accept-Encoding", "identity, *;q=" + rand); + connection.setRequestProperty("Accept-Ranges", "bytes"); + + // Standard conditional GET for bandwidth saving (if the node IS synced) if (cachedTime != 0) { connection.setIfModifiedSince(cachedTime); } @@ -160,7 +170,8 @@ private static StatusResult getStatus() { } else if (networkResult != null && networkResult.json() != null) { saveToCache(networkResult.json()); try { - return new StatusResult(networkResult.json().getJSONObject("entries"), DataSource.NETWORK_UPDATE); + DataSource successState = (cachedTime == 0) ? DataSource.NETWORK_INITIAL : DataSource.NETWORK_UPDATE; + return new StatusResult(networkResult.json().getJSONObject("entries"), successState); } catch (JSONException ignored) {} } @@ -198,7 +209,7 @@ public static void refresh() { // If we successfully fetched a brand new file this session, // don't let a subsequent UI refresh overwrite our status with a 304! - if (currentSource == DataSource.NETWORK_UPDATE && result.source() == DataSource.NETWORK_UP_TO_DATE) { + if ((currentSource == DataSource.NETWORK_UPDATE || currentSource == DataSource.NETWORK_INITIAL) && result.source() == DataSource.NETWORK_UP_TO_DATE) { Log.i(TAG, "Preserving NETWORK_UPDATE status across multiple refreshes"); } else { currentSource = result.source(); @@ -213,7 +224,7 @@ public static RevocationList get(BigInteger serialNumber) { StatusResult result = getStatus(); data = result.json(); - if (currentSource == DataSource.NETWORK_UPDATE && result.source() == DataSource.NETWORK_UP_TO_DATE) { + if ((currentSource == DataSource.NETWORK_UPDATE || currentSource == DataSource.NETWORK_INITIAL) && result.source() == DataSource.NETWORK_UP_TO_DATE) { Log.i(TAG, "Preserving NETWORK_UPDATE status in get()"); } else { currentSource = result.source(); @@ -234,4 +245,4 @@ public static RevocationList get(BigInteger serialNumber) { public String toString() { return "status: " + status + ", source: " + source; } -} +} \ No newline at end of file diff --git a/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt b/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt index 963cb91..0c96189 100644 --- a/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt +++ b/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt @@ -113,6 +113,7 @@ class HomeAdapter(listener: Listener) : IdBasedRecyclerViewAdapter() { } val statusLine = when (source) { + RevocationList.DataSource.NETWORK_INITIAL -> context.getString(R.string.revocation_status_initial) RevocationList.DataSource.NETWORK_UPDATE -> context.getString(R.string.revocation_status_new_fetch) RevocationList.DataSource.NETWORK_UP_TO_DATE -> context.getString(R.string.revocation_status_up_to_date) RevocationList.DataSource.CACHE -> context.getString(R.string.revocation_status_offline_cached) @@ -458,4 +459,4 @@ class HomeAdapter(listener: Listener) : IdBasedRecyclerViewAdapter() { R.string.authorization_list_moduleHash_description, ) } -} +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 18d3451..64d08fc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,7 +57,8 @@ Revocation list publish time The revocation list is used to check if certificates have been revoked. This shows the publication time of the currently used revocation list. - ℹ️ New CRL Fetched! + ⚙️ Initial list downloaded + ✨ New list fetched! ✅ CRL Up-to-date ⚠️ Device offline - using cached CRL ❌ Offline - CRL Out-of-date