clear passphrase cache, fix application crash on auto screen-off (#3108)

clear passphrase chache on screen-off
This commit is contained in:
agrahn 2024-07-02 11:37:39 +02:00 committed by GitHub
parent 2820f0ed63
commit 66675864ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 32 additions and 22 deletions

View file

@ -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
}
}

View file

@ -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) {

View file

@ -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
}
}
}
}