aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorTad Fisher <tadfisher@gmail.com>2022-10-09 16:11:28 -0700
committerTad Fisher <tadfisher@gmail.com>2022-10-09 16:17:25 -0700
commita716ac9514577110481434ac2afdc64d97e02375 (patch)
tree92c310139cef2032d2c9b809648e92f50e24d10f /app
parent75040136ae5ca6108335975430b411f8a560d0ba (diff)
Quick and dirty hardware key import
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt37
-rw-r--r--app/src/main/res/values/strings.xml3
2 files changed, 34 insertions, 6 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 4c9060f7..b3edb1a9 100644
--- a/app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/pgp/PGPKeyImportActivity.kt
@@ -7,20 +7,26 @@
package app.passwordstore.ui.pgp
import android.os.Bundle
+import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts.OpenDocument
import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
import app.passwordstore.R
+import app.passwordstore.crypto.HWSecurityDeviceHandler
import app.passwordstore.crypto.KeyUtils.tryGetId
import app.passwordstore.crypto.PGPKey
import app.passwordstore.crypto.PGPKeyManager
import app.passwordstore.crypto.errors.KeyAlreadyExistsException
+import app.passwordstore.crypto.errors.NoSecretKeyException
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
+import com.github.michaelbull.result.getOrThrow
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
+import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@AndroidEntryPoint
@@ -32,9 +38,10 @@ class PGPKeyImportActivity : AppCompatActivity() {
*/
private var lastBytes: ByteArray? = null
@Inject lateinit var keyManager: PGPKeyManager
+ @Inject lateinit var deviceHandler: HWSecurityDeviceHandler
private val pgpKeyImportAction =
- registerForActivityResult(OpenDocument()) { uri ->
+ (this as ComponentActivity).registerForActivityResult(OpenDocument()) { uri ->
runCatching {
if (uri == null) {
return@runCatching null
@@ -50,6 +57,7 @@ class PGPKeyImportActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
pgpKeyImportAction.launch(arrayOf("*/*"))
}
@@ -68,6 +76,16 @@ class PGPKeyImportActivity : AppCompatActivity() {
return key
}
+ private fun pairDevice(bytes: ByteArray) {
+ lifecycleScope.launch {
+ val result = keyManager.addKey(
+ deviceHandler.pairWithPublicKey(PGPKey(bytes)).getOrThrow(),
+ replace = true
+ )
+ handleImportResult(result)
+ }
+ }
+
private fun handleImportResult(result: Result<PGPKey?, Throwable>) {
when (result) {
is Ok<PGPKey?> -> {
@@ -85,8 +103,8 @@ class PGPKeyImportActivity : AppCompatActivity() {
.setCancelable(false)
.show()
}
- is Err<Throwable> -> {
- if (result.error is KeyAlreadyExistsException && lastBytes != null) {
+ is Err<Throwable> -> when {
+ 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))
@@ -96,14 +114,21 @@ class PGPKeyImportActivity : AppCompatActivity() {
.setNegativeButton(R.string.dialog_no) { _, _ -> finish() }
.setCancelable(false)
.show()
- } else {
+ result.error is NoSecretKeyException && lastBytes != null ->
+ MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.pgp_key_import_failed_no_secret)
+ .setMessage(R.string.pgp_key_import_failed_no_secret_message)
+ .setPositiveButton(R.string.dialog_yes) { _, _ -> pairDevice(lastBytes!!) }
+ .setNegativeButton(R.string.dialog_no) { _, _ -> finish() }
+ .setCancelable(false)
+ .show()
+ else ->
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.pgp_key_import_failed))
- .setMessage(result.error.message)
+ .setMessage(result.error.message + "\n" + result.error.stackTraceToString())
.setPositiveButton(android.R.string.ok) { _, _ -> finish() }
.setCancelable(false)
.show()
- }
}
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9997f6aa..63f47f27 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -332,6 +332,7 @@
<string name="select_gpg_key_title">Select\nGPG Key</string>
<string name="select_gpg_key_message">Select a GPG key to initialize your store with</string>
<string name="gpg_key_select">Select key</string>
+ <string name="pair_hardware_key">Pair hardware key</string>
<!-- SSH port validation -->
<string name="ssh_scheme_needed_title">Potentially incorrect URL</string>
@@ -358,6 +359,8 @@
<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_failed_no_secret">No secret PGP key</string>
+ <string name="pgp_key_import_failed_no_secret_message">This is a public key. Would you like to pair a hardware security device?</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>