diff options
Diffstat (limited to 'app/src/main')
-rw-r--r-- | app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt | 92 | ||||
-rw-r--r-- | app/src/main/res/values/strings.xml | 1 |
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> |