Refactor key import flow and implement support for replacing
This commit is contained in:
parent
b9f4da71ea
commit
4ed98c9fda
2 changed files with 67 additions and 26 deletions
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue