aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt16
-rw-r--r--app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt16
-rw-r--r--app/src/main/java/app/passwordstore/ui/crypto/PasswordDialog.kt29
-rw-r--r--app/src/main/res/layout/dialog_password_entry.xml5
-rw-r--r--app/src/main/res/values/strings.xml1
5 files changed, 60 insertions, 7 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt
index b6e82b7a..c6441283 100644
--- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt
@@ -11,6 +11,7 @@ import android.content.IntentSender
import android.os.Build
import android.os.Bundle
import android.view.autofill.AutofillManager
+import androidx.core.content.edit
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope
import app.passwordstore.Application.Companion.screenWasOff
@@ -53,6 +54,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
@Inject lateinit var passphraseCache: PGPPassphraseCache
private lateinit var directoryStructure: DirectoryStructure
+ private var clearCache = true
override fun onStart() {
super.onStart()
@@ -114,7 +116,8 @@ class AutofillDecryptActivity : BasePGPActivity() {
is Result.Success -> {
/* clear passphrase cache on first use after application startup or if screen was off;
also make sure to purge a stale cache after caching has been disabled via PGP settings */
- if (screenWasOff && settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)) {
+ clearCache = settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)
+ if (screenWasOff && clearCache) {
passphraseCache.clearAllCachedPassphrases(this@AutofillDecryptActivity)
screenWasOff = false
}
@@ -149,11 +152,16 @@ class AutofillDecryptActivity : BasePGPActivity() {
decryptWithPassphrase(File(filePath), identifiers, clientState, action, password = "")
return
}
- val dialog = PasswordDialog()
+ val dialog =
+ PasswordDialog.newInstance(
+ cacheEnabled = features.isEnabled(EnablePGPPassphraseCache),
+ clearCache = clearCache,
+ )
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
dialog.setFragmentResultListener(PasswordDialog.PASSWORD_RESULT_KEY) { key, bundle ->
if (key == PasswordDialog.PASSWORD_RESULT_KEY) {
- val value = bundle.getString(PasswordDialog.PASSWORD_RESULT_KEY)!!
+ val value = bundle.getString(PasswordDialog.PASSWORD_PHRASE_KEY)!!
+ clearCache = bundle.getBoolean(PasswordDialog.PASSWORD_CLEAR_KEY)
lifecycleScope.launch(dispatcherProvider.main()) {
decryptWithPassphrase(File(filePath), identifiers, clientState, action, value)
}
@@ -185,6 +193,8 @@ class AutofillDecryptActivity : BasePGPActivity() {
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) },
)
}
+ if (features.isEnabled(EnablePGPPassphraseCache))
+ settings.edit { putBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, clearCache) }
}
withContext(dispatcherProvider.main()) { finish() }
}
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 405d6f4e..88d31dec 100644
--- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt
@@ -9,6 +9,7 @@ import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
+import androidx.core.content.edit
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope
import app.passwordstore.Application.Companion.screenWasOff
@@ -56,6 +57,7 @@ class DecryptActivity : BasePGPActivity() {
private val relativeParentPath by unsafeLazy { getParentPath(fullPath, repoPath) }
private var passwordEntry: PasswordEntry? = null
private var retries = 0
+ private var clearCache = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -170,7 +172,8 @@ class DecryptActivity : BasePGPActivity() {
is BiometricResult.Success -> {
/* clear passphrase cache on first use after application startup or if screen was off;
also make sure to purge a stale cache after caching has been disabled via PGP settings */
- if (screenWasOff && settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)) {
+ clearCache = settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)
+ if (screenWasOff && clearCache) {
passphraseCache.clearAllCachedPassphrases(this@DecryptActivity)
screenWasOff = false
}
@@ -200,14 +203,19 @@ class DecryptActivity : BasePGPActivity() {
decryptWithPassphrase(passphrase = "", gpgIdentifiers, authResult)
return
}
- val dialog = PasswordDialog()
+ val dialog =
+ PasswordDialog.newInstance(
+ cacheEnabled = features.isEnabled(EnablePGPPassphraseCache),
+ clearCache = clearCache,
+ )
if (isError) {
dialog.setError()
}
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
dialog.setFragmentResultListener(PasswordDialog.PASSWORD_RESULT_KEY) { key, bundle ->
if (key == PasswordDialog.PASSWORD_RESULT_KEY) {
- val passphrase = bundle.getString(PasswordDialog.PASSWORD_RESULT_KEY)!!
+ val passphrase = bundle.getString(PasswordDialog.PASSWORD_PHRASE_KEY)!!
+ clearCache = bundle.getBoolean(PasswordDialog.PASSWORD_CLEAR_KEY)
lifecycleScope.launch(dispatcherProvider.main()) {
decryptWithPassphrase(passphrase, gpgIdentifiers, authResult) {
if (authResult is BiometricResult.Success) {
@@ -231,6 +239,8 @@ class DecryptActivity : BasePGPActivity() {
) {
val result = decryptPGPStream(passphrase, identifiers)
if (result.isOk) {
+ if (features.isEnabled(EnablePGPPassphraseCache))
+ settings.edit { putBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, clearCache) }
val entry = passwordEntryFactory.create(result.value.toByteArray())
passwordEntry = entry
createPasswordUI(entry)
diff --git a/app/src/main/java/app/passwordstore/ui/crypto/PasswordDialog.kt b/app/src/main/java/app/passwordstore/ui/crypto/PasswordDialog.kt
index c1dcd2d9..f65a7305 100644
--- a/app/src/main/java/app/passwordstore/ui/crypto/PasswordDialog.kt
+++ b/app/src/main/java/app/passwordstore/ui/crypto/PasswordDialog.kt
@@ -25,11 +25,21 @@ class PasswordDialog : DialogFragment() {
private val binding by unsafeLazy { DialogPasswordEntryBinding.inflate(layoutInflater) }
private var isError: Boolean = false
+ private var clearCacheChecked: Boolean = true
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
builder.setView(binding.root)
builder.setTitle(R.string.password)
+
+ if (requireArguments().getBoolean(CACHE_ENABLED_EXTRA, false)) {
+ clearCacheChecked = requireArguments().getBoolean(AUTO_CLEAR_CACHE_EXTRA)
+ binding.autoClearCache.isChecked = clearCacheChecked
+ binding.autoClearCache.setOnCheckedChangeListener { _, isChecked ->
+ clearCacheChecked = isChecked
+ }
+ }
+
builder.setPositiveButton(android.R.string.ok) { _, _ -> setPasswordAndDismiss() }
val dialog = builder.create()
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
@@ -64,11 +74,28 @@ class PasswordDialog : DialogFragment() {
private fun setPasswordAndDismiss() {
val password = binding.passwordEditText.text.toString()
- setFragmentResult(PASSWORD_RESULT_KEY, bundleOf(PASSWORD_RESULT_KEY to password))
+ setFragmentResult(
+ PASSWORD_RESULT_KEY,
+ bundleOf(PASSWORD_PHRASE_KEY to password, PASSWORD_CLEAR_KEY to clearCacheChecked),
+ )
dismissAllowingStateLoss()
}
companion object {
+
+ private const val CACHE_ENABLED_EXTRA = "CACHE_ENABLED"
+ private const val AUTO_CLEAR_CACHE_EXTRA = "AUTO_CLEAR_CACHE"
+
const val PASSWORD_RESULT_KEY = "password_result"
+ const val PASSWORD_PHRASE_KEY = "password_phrase"
+ const val PASSWORD_CLEAR_KEY = "password_clear"
+
+ fun newInstance(cacheEnabled: Boolean, clearCache: Boolean): PasswordDialog {
+ val extras =
+ bundleOf(CACHE_ENABLED_EXTRA to cacheEnabled, AUTO_CLEAR_CACHE_EXTRA to clearCache)
+ val fragment = PasswordDialog()
+ fragment.arguments = extras
+ return fragment
+ }
}
}
diff --git a/app/src/main/res/layout/dialog_password_entry.xml b/app/src/main/res/layout/dialog_password_entry.xml
index 0072d491..e2ad5a2f 100644
--- a/app/src/main/res/layout/dialog_password_entry.xml
+++ b/app/src/main/res/layout/dialog_password_entry.xml
@@ -27,4 +27,9 @@
<requestFocus />
</com.google.android.material.textfield.TextInputLayout>
+ <com.google.android.material.checkbox.MaterialCheckBox
+ android:id="@+id/auto_clear_cache"
+ android:layout_width="match_parent"
+ android:text="@string/clear_cached_password_on_screen_off"
+ android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 07a9661b..404339ce 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -381,4 +381,5 @@
<string name="biometric_prompt_title_gpg_passphrase_cache">Unlock passphrase cache</string>
<string name="aead_detect_title">AEAD encryption detected</string>
<string name="aead_detect_message">%1$s, see https://passwordstore.app/fix-aead for more information</string>
+ <string name="clear_cached_password_on_screen_off">Clear cached password on screen-off</string>
</resources>