Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit 080387c

Browse files
agrahnmsfjarvis
andauthored
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 <[email protected]>
1 parent 457ecad commit 080387c

File tree

5 files changed

+60
-7
lines changed

5 files changed

+60
-7
lines changed

app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import android.content.IntentSender
1111
import android.os.Build
1212
import android.os.Bundle
1313
import android.view.autofill.AutofillManager
14+
import androidx.core.content.edit
1415
import androidx.fragment.app.setFragmentResultListener
1516
import androidx.lifecycle.lifecycleScope
1617
import app.passwordstore.Application.Companion.screenWasOff
@@ -53,6 +54,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
5354
@Inject lateinit var passphraseCache: PGPPassphraseCache
5455

5556
private lateinit var directoryStructure: DirectoryStructure
57+
private var clearCache = true
5658

5759
override fun onStart() {
5860
super.onStart()
@@ -114,7 +116,8 @@ class AutofillDecryptActivity : BasePGPActivity() {
114116
is Result.Success -> {
115117
/* clear passphrase cache on first use after application startup or if screen was off;
116118
also make sure to purge a stale cache after caching has been disabled via PGP settings */
117-
if (screenWasOff && settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)) {
119+
clearCache = settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)
120+
if (screenWasOff && clearCache) {
118121
passphraseCache.clearAllCachedPassphrases(this@AutofillDecryptActivity)
119122
screenWasOff = false
120123
}
@@ -149,11 +152,16 @@ class AutofillDecryptActivity : BasePGPActivity() {
149152
decryptWithPassphrase(File(filePath), identifiers, clientState, action, password = "")
150153
return
151154
}
152-
val dialog = PasswordDialog()
155+
val dialog =
156+
PasswordDialog.newInstance(
157+
cacheEnabled = features.isEnabled(EnablePGPPassphraseCache),
158+
clearCache = clearCache,
159+
)
153160
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
154161
dialog.setFragmentResultListener(PasswordDialog.PASSWORD_RESULT_KEY) { key, bundle ->
155162
if (key == PasswordDialog.PASSWORD_RESULT_KEY) {
156-
val value = bundle.getString(PasswordDialog.PASSWORD_RESULT_KEY)!!
163+
val value = bundle.getString(PasswordDialog.PASSWORD_PHRASE_KEY)!!
164+
clearCache = bundle.getBoolean(PasswordDialog.PASSWORD_CLEAR_KEY)
157165
lifecycleScope.launch(dispatcherProvider.main()) {
158166
decryptWithPassphrase(File(filePath), identifiers, clientState, action, value)
159167
}
@@ -185,6 +193,8 @@ class AutofillDecryptActivity : BasePGPActivity() {
185193
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) },
186194
)
187195
}
196+
if (features.isEnabled(EnablePGPPassphraseCache))
197+
settings.edit { putBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, clearCache) }
188198
}
189199
withContext(dispatcherProvider.main()) { finish() }
190200
}

app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.content.Intent
99
import android.os.Bundle
1010
import android.view.Menu
1111
import android.view.MenuItem
12+
import androidx.core.content.edit
1213
import androidx.fragment.app.setFragmentResultListener
1314
import androidx.lifecycle.lifecycleScope
1415
import app.passwordstore.Application.Companion.screenWasOff
@@ -56,6 +57,7 @@ class DecryptActivity : BasePGPActivity() {
5657
private val relativeParentPath by unsafeLazy { getParentPath(fullPath, repoPath) }
5758
private var passwordEntry: PasswordEntry? = null
5859
private var retries = 0
60+
private var clearCache = true
5961

6062
override fun onCreate(savedInstanceState: Bundle?) {
6163
super.onCreate(savedInstanceState)
@@ -170,7 +172,8 @@ class DecryptActivity : BasePGPActivity() {
170172
is BiometricResult.Success -> {
171173
/* clear passphrase cache on first use after application startup or if screen was off;
172174
also make sure to purge a stale cache after caching has been disabled via PGP settings */
173-
if (screenWasOff && settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)) {
175+
clearCache = settings.getBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, true)
176+
if (screenWasOff && clearCache) {
174177
passphraseCache.clearAllCachedPassphrases(this@DecryptActivity)
175178
screenWasOff = false
176179
}
@@ -200,14 +203,19 @@ class DecryptActivity : BasePGPActivity() {
200203
decryptWithPassphrase(passphrase = "", gpgIdentifiers, authResult)
201204
return
202205
}
203-
val dialog = PasswordDialog()
206+
val dialog =
207+
PasswordDialog.newInstance(
208+
cacheEnabled = features.isEnabled(EnablePGPPassphraseCache),
209+
clearCache = clearCache,
210+
)
204211
if (isError) {
205212
dialog.setError()
206213
}
207214
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
208215
dialog.setFragmentResultListener(PasswordDialog.PASSWORD_RESULT_KEY) { key, bundle ->
209216
if (key == PasswordDialog.PASSWORD_RESULT_KEY) {
210-
val passphrase = bundle.getString(PasswordDialog.PASSWORD_RESULT_KEY)!!
217+
val passphrase = bundle.getString(PasswordDialog.PASSWORD_PHRASE_KEY)!!
218+
clearCache = bundle.getBoolean(PasswordDialog.PASSWORD_CLEAR_KEY)
211219
lifecycleScope.launch(dispatcherProvider.main()) {
212220
decryptWithPassphrase(passphrase, gpgIdentifiers, authResult) {
213221
if (authResult is BiometricResult.Success) {
@@ -231,6 +239,8 @@ class DecryptActivity : BasePGPActivity() {
231239
) {
232240
val result = decryptPGPStream(passphrase, identifiers)
233241
if (result.isOk) {
242+
if (features.isEnabled(EnablePGPPassphraseCache))
243+
settings.edit { putBoolean(PreferenceKeys.CLEAR_PASSPHRASE_CACHE, clearCache) }
234244
val entry = passwordEntryFactory.create(result.value.toByteArray())
235245
passwordEntry = entry
236246
createPasswordUI(entry)

app/src/main/java/app/passwordstore/ui/crypto/PasswordDialog.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,21 @@ class PasswordDialog : DialogFragment() {
2525

2626
private val binding by unsafeLazy { DialogPasswordEntryBinding.inflate(layoutInflater) }
2727
private var isError: Boolean = false
28+
private var clearCacheChecked: Boolean = true
2829

2930
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
3031
val builder = MaterialAlertDialogBuilder(requireContext())
3132
builder.setView(binding.root)
3233
builder.setTitle(R.string.password)
34+
35+
if (requireArguments().getBoolean(CACHE_ENABLED_EXTRA, false)) {
36+
clearCacheChecked = requireArguments().getBoolean(AUTO_CLEAR_CACHE_EXTRA)
37+
binding.autoClearCache.isChecked = clearCacheChecked
38+
binding.autoClearCache.setOnCheckedChangeListener { _, isChecked ->
39+
clearCacheChecked = isChecked
40+
}
41+
}
42+
3343
builder.setPositiveButton(android.R.string.ok) { _, _ -> setPasswordAndDismiss() }
3444
val dialog = builder.create()
3545
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
@@ -64,11 +74,28 @@ class PasswordDialog : DialogFragment() {
6474

6575
private fun setPasswordAndDismiss() {
6676
val password = binding.passwordEditText.text.toString()
67-
setFragmentResult(PASSWORD_RESULT_KEY, bundleOf(PASSWORD_RESULT_KEY to password))
77+
setFragmentResult(
78+
PASSWORD_RESULT_KEY,
79+
bundleOf(PASSWORD_PHRASE_KEY to password, PASSWORD_CLEAR_KEY to clearCacheChecked),
80+
)
6881
dismissAllowingStateLoss()
6982
}
7083

7184
companion object {
85+
86+
private const val CACHE_ENABLED_EXTRA = "CACHE_ENABLED"
87+
private const val AUTO_CLEAR_CACHE_EXTRA = "AUTO_CLEAR_CACHE"
88+
7289
const val PASSWORD_RESULT_KEY = "password_result"
90+
const val PASSWORD_PHRASE_KEY = "password_phrase"
91+
const val PASSWORD_CLEAR_KEY = "password_clear"
92+
93+
fun newInstance(cacheEnabled: Boolean, clearCache: Boolean): PasswordDialog {
94+
val extras =
95+
bundleOf(CACHE_ENABLED_EXTRA to cacheEnabled, AUTO_CLEAR_CACHE_EXTRA to clearCache)
96+
val fragment = PasswordDialog()
97+
fragment.arguments = extras
98+
return fragment
99+
}
73100
}
74101
}

app/src/main/res/layout/dialog_password_entry.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,9 @@
2727
<requestFocus />
2828
</com.google.android.material.textfield.TextInputLayout>
2929

30+
<com.google.android.material.checkbox.MaterialCheckBox
31+
android:id="@+id/auto_clear_cache"
32+
android:layout_width="match_parent"
33+
android:text="@string/clear_cached_password_on_screen_off"
34+
android:layout_height="wrap_content" />
3035
</LinearLayout>

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,5 @@
381381
<string name="biometric_prompt_title_gpg_passphrase_cache">Unlock passphrase cache</string>
382382
<string name="aead_detect_title">AEAD encryption detected</string>
383383
<string name="aead_detect_message">%1$s, see https://passwordstore.app/fix-aead for more information</string>
384+
<string name="clear_cached_password_on_screen_off">Clear cached password on screen-off</string>
384385
</resources>

0 commit comments

Comments
 (0)