Fix empty usage-history chart + externalize signing secrets
Build APK / build (push) Successful in 2m18s
Build APK / build (push) Successful in 2m18s
History chart: recordHistory() threw away the previous point whenever a new reading landed within the 2-min de-dup window, but the foreground loop refreshes every 30s — so history could never grow past one point while the app was open and the chart stayed stuck on 'Collecting history…'. Now it throttles by SKIPPING a too-soon reading instead of replacing the last one, so points accumulate during normal use. Security: - Remove hardcoded release keystore passwords from build.gradle.kts; read from env vars / gitignored keystore.properties; CI injects from Gitea secrets (KEYSTORE_PASSWORD/KEY_PASSWORD). Signing identity unchanged. - Make the cookie-never-plaintext invariant explicit on the read path. - Drop custom ACTION_REFRESH from the exported widget intent-filter so other apps can't trigger refreshes; internal explicit PendingIntent still works. - Gate an unguarded Log.w behind BuildConfig.DEBUG.
This commit is contained in:
@@ -32,9 +32,11 @@
|
||||
<receiver
|
||||
android:name=".ClaudeUsageWidget"
|
||||
android:exported="true">
|
||||
<!-- Only the system APPWIDGET_UPDATE action is exposed. ACTION_REFRESH is delivered via
|
||||
the widget's own explicit PendingIntent (explicit broadcasts need no intent-filter),
|
||||
so other apps can no longer trigger refreshes by sending that action externally. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
<action android:name="me.khodak.claudeusage.ACTION_REFRESH" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
|
||||
@@ -87,7 +87,7 @@ class UsageRepository(private val prefs: PreferencesManager) {
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "/usage failed: ${e.message}")
|
||||
if (BuildConfig.DEBUG) Log.w(TAG, "/usage failed: ${e.message}")
|
||||
}
|
||||
|
||||
// Step 3: fallback endpoints (message-count style)
|
||||
|
||||
@@ -24,9 +24,14 @@ class PreferencesManager(context: Context) {
|
||||
} catch (_: Exception) {}
|
||||
}
|
||||
|
||||
fun getCookies(): String? = try {
|
||||
securePrefs.getString(KEY_COOKIES, null)
|
||||
} catch (_: Exception) { null }
|
||||
fun getCookies(): String? {
|
||||
// Cookies are never written in fallback (plaintext) mode — make that invariant explicit on
|
||||
// the read side too, so any future write that bypasses the guard still can't surface here.
|
||||
if (usingFallbackPrefs) return null
|
||||
return try {
|
||||
securePrefs.getString(KEY_COOKIES, null)
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun clearSession() {
|
||||
try { securePrefs.edit().clear().apply() } catch (_: Exception) {}
|
||||
@@ -98,9 +103,11 @@ class PreferencesManager(context: Context) {
|
||||
if (data.fiveHourUtilization < 0f && data.weeklyUtilization < 0f) return
|
||||
val now = System.currentTimeMillis()
|
||||
val history = getHistory().toMutableList()
|
||||
if (history.isNotEmpty() && now - history.last().epochMs < MIN_HISTORY_GAP_MS) {
|
||||
history.removeAt(history.size - 1) // collapse near-simultaneous readings
|
||||
}
|
||||
// Throttle to at most one point per MIN_HISTORY_GAP_MS by SKIPPING a too-soon reading.
|
||||
// (Previously we deleted the last point and re-added in place — but the foreground loop
|
||||
// refreshes every 30s, well inside this 2-min window, so history could never grow past a
|
||||
// single point while the app was open and the chart stayed on "Collecting history…".)
|
||||
if (history.isNotEmpty() && now - history.last().epochMs < MIN_HISTORY_GAP_MS) return
|
||||
history.add(
|
||||
UsageSnapshot(
|
||||
epochMs = now,
|
||||
|
||||
Reference in New Issue
Block a user