From 66675864aefbfce663cefe1084925d6370ceb309 Mon Sep 17 00:00:00 2001 From: agrahn Date: Tue, 2 Jul 2024 11:37:39 +0200 Subject: clear passphrase cache, fix application crash on auto screen-off (#3108) clear passphrase chache on screen-off --- app/src/main/java/app/passwordstore/Application.kt | 32 +++++++--------------- .../app/passwordstore/ui/crypto/DecryptActivity.kt | 6 ++++ .../app/passwordstore/ui/settings/PGPSettings.kt | 16 +++++++++++ 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/app/passwordstore/Application.kt b/app/src/main/java/app/passwordstore/Application.kt index 414ef54e..ea730e7e 100644 --- a/app/src/main/java/app/passwordstore/Application.kt +++ b/app/src/main/java/app/passwordstore/Application.kt @@ -30,10 +30,6 @@ import io.sentry.Sentry import io.sentry.protocol.User import java.util.concurrent.Executors import javax.inject.Inject -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import logcat.AndroidLogcatLogger import logcat.LogPriority.DEBUG import logcat.LogPriority.VERBOSE @@ -76,27 +72,18 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere } scope.user = user } - setupPassphraseCacheClearAction() + setupScreenOffHandler() } - @OptIn(DelicateCoroutinesApi::class) - private fun setupPassphraseCacheClearAction() { - if (prefs.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, false)) { - val screenOffReceiver: BroadcastReceiver = - object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - if (intent.action == Intent.ACTION_SCREEN_OFF) { - GlobalScope.launch { - withContext(dispatcherProvider.main()) { - passphraseCache.clearAllCachedPassphrases(context) - } - } - } - } + private fun setupScreenOffHandler() { + val screenOffReceiver: BroadcastReceiver = + object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == Intent.ACTION_SCREEN_OFF) screenWasOff = true } - val filter = IntentFilter(Intent.ACTION_SCREEN_OFF) - registerReceiver(screenOffReceiver, filter) - } + } + val filter = IntentFilter(Intent.ACTION_SCREEN_OFF) + registerReceiver(screenOffReceiver, filter) } override fun onTerminate() { @@ -159,5 +146,6 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere companion object { lateinit var instance: Application + var screenWasOff: Boolean = true } } diff --git a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt index 6f14bdea..854ebabd 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt @@ -11,6 +11,7 @@ import android.view.Menu import android.view.MenuItem import androidx.fragment.app.setFragmentResultListener import androidx.lifecycle.lifecycleScope +import app.passwordstore.Application.Companion.screenWasOff import app.passwordstore.R import app.passwordstore.crypto.PGPIdentifier import app.passwordstore.crypto.errors.CryptoHandlerException @@ -167,6 +168,11 @@ class DecryptActivity : BasePGPActivity() { askPassphrase(isError, gpgIdentifiers, authResult) // is BiometricResult.Success -> { + // clear passphrase cache on first use after application startup or if screen was off + if (screenWasOff && settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, false)) { + passphraseCache.clearAllCachedPassphrases(this@DecryptActivity) + screenWasOff = false + } val cachedPassphrase = passphraseCache.retrieveCachedPassphrase(this@DecryptActivity, gpgIdentifiers.first()) if (cachedPassphrase != null) { diff --git a/app/src/main/java/app/passwordstore/ui/settings/PGPSettings.kt b/app/src/main/java/app/passwordstore/ui/settings/PGPSettings.kt index 09f81102..3a77255b 100644 --- a/app/src/main/java/app/passwordstore/ui/settings/PGPSettings.kt +++ b/app/src/main/java/app/passwordstore/ui/settings/PGPSettings.kt @@ -65,6 +65,22 @@ class PGPSettings( titleRes = R.string.pref_passphrase_cache_auto_clear_title summaryRes = R.string.pref_passphrase_cache_auto_clear_summary defaultValue = false + /* clear cache once when unchecking; this is to prevent a malicious user + * from bypassing cache clearing via the settings */ + onCheckedChange { checked -> + if (!checked && BiometricAuthenticator.canAuthenticate(activity)) { + BiometricAuthenticator.authenticate( + activity, + R.string.pref_passphrase_cache_authenticate_clear, + ) { + if (it is BiometricAuthenticator.Result.Success) + activity.lifecycleScope.launch { + passphraseCache.clearAllCachedPassphrases(activity) + } + } + } + true + } } } } -- cgit v1.2.3