Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,10 @@ private static String joinStrings(Collection<String> 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<Integer> paddingModes) {
return joinStrings(transform(paddingModes, forMap(paddingMap, "Unknown")));
Expand Down Expand Up @@ -942,4 +944,4 @@ public String toString() {
}
return s.toString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {}
}

Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand All @@ -234,4 +245,4 @@ public static RevocationList get(BigInteger serialNumber) {
public String toString() {
return "status: " + status + ", source: " + source;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -458,4 +459,4 @@ class HomeAdapter(listener: Listener) : IdBasedRecyclerViewAdapter() {
R.string.authorization_list_moduleHash_description,
)
}
}
}
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
<string name="revocation_list_publish_time">Revocation list publish time</string>
<string name="revocation_list_description">The revocation list is used to check if certificates have been revoked. This shows the publication time of the currently used revocation list.</string>

<string name="revocation_status_new_fetch">ℹ️ New CRL Fetched!</string>
<string name="revocation_status_initial">⚙️ Initial list downloaded</string>
<string name="revocation_status_new_fetch">✨ New list fetched!</string>
<string name="revocation_status_up_to_date">✅ CRL Up-to-date</string>
<string name="revocation_status_offline_cached">⚠️ Device offline - using cached CRL</string>
<string name="revocation_status_offline_bundled">❌ Offline - CRL Out-of-date</string>
Expand Down
Loading