aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2022-07-17 22:21:55 +0530
committerHarsh Shandilya <me@msfjarvis.dev>2022-07-17 22:38:27 +0530
commit4ed98c9fda6e3121e5ba9d9d4b001e9512240fd0 (patch)
tree4766adea446a8ab71530c43f5c529318039bc981 /app
parentb9f4da71ea057df11c9da4ba41ce2e1836de2d51 (diff)
Refactor key import flow and implement support for replacing
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt92
-rw-r--r--app/src/main/res/values/strings.xml1
2 files changed, 67 insertions, 26 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt b/app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt
index cd4ab07f..4ea1d0b5 100644
--- a/app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt
@@ -13,7 +13,10 @@ import app.passwordstore.R
import app.passwordstore.crypto.KeyUtils.tryGetId
import app.passwordstore.crypto.PGPKey
import app.passwordstore.crypto.PGPKeyManager
-import com.github.michaelbull.result.mapBoth
+import app.passwordstore.crypto.errors.KeyAlreadyExistsException
+import com.github.michaelbull.result.Err
+import com.github.michaelbull.result.Ok
+import com.github.michaelbull.result.Result
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
@@ -23,6 +26,11 @@ import kotlinx.coroutines.runBlocking
@AndroidEntryPoint
class PGPKeyImportActivity : AppCompatActivity() {
+ /**
+ * A [ByteArray] containing the contents of the previously selected file. This is necessary for
+ * the replacement case where we do not want users to have to pick the file again.
+ */
+ private var lastBytes: ByteArray? = null
@Inject lateinit var keyManager: PGPKeyManager
private val pgpKeyImportAction =
@@ -35,36 +43,68 @@ class PGPKeyImportActivity : AppCompatActivity() {
contentResolver.openInputStream(uri)
?: throw IllegalStateException("Failed to open selected file")
val bytes = keyInputStream.use { `is` -> `is`.readBytes() }
- val (key, error) = runBlocking { keyManager.addKey(PGPKey(bytes)) }
- if (error != null) throw error
- key
+ importKey(bytes, false)
}
- .mapBoth(
- { key ->
- if (key != null) {
- MaterialAlertDialogBuilder(this)
- .setTitle(getString(R.string.pgp_key_import_succeeded))
- .setMessage(getString(R.string.pgp_key_import_succeeded_message, tryGetId(key)))
- .setPositiveButton(android.R.string.ok) { _, _ -> finish() }
- .setOnCancelListener { finish() }
- .show()
- } else {
- finish()
- }
- },
- { throwable ->
- MaterialAlertDialogBuilder(this)
- .setTitle(getString(R.string.pgp_key_import_failed))
- .setMessage(throwable.message)
- .setPositiveButton(android.R.string.ok) { _, _ -> finish() }
- .setOnCancelListener { finish() }
- .show()
- }
- )
+ .run(::handleImportResult)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pgpKeyImportAction.launch(arrayOf("*/*"))
}
+
+ override fun onDestroy() {
+ lastBytes = null
+ super.onDestroy()
+ }
+
+ private fun importKey(bytes: ByteArray, replace: Boolean): PGPKey? {
+ lastBytes = bytes
+ val (key, error) = runBlocking { keyManager.addKey(PGPKey(bytes), replace = replace) }
+ if (replace) {
+ lastBytes = null
+ }
+ if (error != null) throw error
+ return key
+ }
+
+ private fun handleImportResult(result: Result<PGPKey?, Throwable>) {
+ when (result) {
+ is Ok<PGPKey?> -> {
+ val key = result.value
+ if (key == null) {
+ finish()
+ // This return convinces Kotlin that the control flow for `key == null` definitely
+ // terminates here and allows for a smart cast below.
+ return
+ }
+ MaterialAlertDialogBuilder(this)
+ .setTitle(getString(R.string.pgp_key_import_succeeded))
+ .setMessage(getString(R.string.pgp_key_import_succeeded_message, tryGetId(key)))
+ .setPositiveButton(android.R.string.ok) { _, _ -> finish() }
+ .setOnCancelListener { finish() }
+ .show()
+ }
+ is Err<Throwable> -> {
+ if (result.error is KeyAlreadyExistsException && lastBytes != null) {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(getString(R.string.pgp_key_import_failed))
+ .setMessage(getString(R.string.pgp_key_import_failed_replace_message))
+ .setPositiveButton(R.string.dialog_yes) { _, _ ->
+ handleImportResult(runCatching { importKey(lastBytes!!, replace = true) })
+ }
+ .setNegativeButton(R.string.dialog_no) { _, _ -> finish() }
+ .setOnCancelListener { finish() }
+ .show()
+ } else {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(getString(R.string.pgp_key_import_failed))
+ .setMessage(result.error.message)
+ .setPositiveButton(android.R.string.ok) { _, _ -> finish() }
+ .setOnCancelListener { finish() }
+ .show()
+ }
+ }
+ }
+ }
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index adac6d51..b9b90294 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -372,6 +372,7 @@
<string name="place_shortcut_on_home_screen">Place shortcut on home screen</string>
<string name="password_list_fab_content_description">Create new password or folder</string>
<string name="pgp_key_import_failed">Failed to import PGP key</string>
+ <string name="pgp_key_import_failed_replace_message">An existing key with this ID was found, do you want to replace it?</string>
<string name="pgp_key_import_succeeded">Successfully imported PGP key</string>
<string name="pgp_key_import_succeeded_message">The key ID of the imported key is given below, please review it for correctness:\n%1$s</string>
<string name="pref_category_pgp_title">PGP settings</string>