add checkbox in passphrase dialog to clear cache (#3127)
* add checkbox in passphrase dialog to clear cache * instantiating PasswordDialog via newInstance, passing args as Bundle * refactor: put checkbox directly in the layout --------- Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
457ecade9c
commit
080387ce75
5 changed files with 60 additions and 7 deletions
|
@ -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() }
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue