fix(app): ensure decryption errors are captured by UI
This commit is contained in:
parent
f778eab94e
commit
b313c4216e
2 changed files with 36 additions and 35 deletions
|
@ -8,6 +8,8 @@ package app.passwordstore.data.crypto
|
||||||
import app.passwordstore.crypto.GpgIdentifier
|
import app.passwordstore.crypto.GpgIdentifier
|
||||||
import app.passwordstore.crypto.PGPKeyManager
|
import app.passwordstore.crypto.PGPKeyManager
|
||||||
import app.passwordstore.crypto.PGPainlessCryptoHandler
|
import app.passwordstore.crypto.PGPainlessCryptoHandler
|
||||||
|
import app.passwordstore.crypto.errors.CryptoHandlerException
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
import com.github.michaelbull.result.getAll
|
import com.github.michaelbull.result.getAll
|
||||||
import com.github.michaelbull.result.unwrap
|
import com.github.michaelbull.result.unwrap
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
@ -27,34 +29,30 @@ constructor(
|
||||||
password: String,
|
password: String,
|
||||||
message: ByteArrayInputStream,
|
message: ByteArrayInputStream,
|
||||||
out: ByteArrayOutputStream,
|
out: ByteArrayOutputStream,
|
||||||
) {
|
) = withContext(Dispatchers.IO) { decryptPgp(password, message, out) }
|
||||||
withContext(Dispatchers.IO) { decryptPgp(password, message, out) }
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun encrypt(
|
suspend fun encrypt(
|
||||||
identities: List<GpgIdentifier>,
|
identities: List<GpgIdentifier>,
|
||||||
content: ByteArrayInputStream,
|
content: ByteArrayInputStream,
|
||||||
out: ByteArrayOutputStream,
|
out: ByteArrayOutputStream,
|
||||||
) {
|
) = withContext(Dispatchers.IO) { encryptPgp(identities, content, out) }
|
||||||
withContext(Dispatchers.IO) { encryptPgp(identities, content, out) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun decryptPgp(
|
private suspend fun decryptPgp(
|
||||||
password: String,
|
password: String,
|
||||||
message: ByteArrayInputStream,
|
message: ByteArrayInputStream,
|
||||||
out: ByteArrayOutputStream,
|
out: ByteArrayOutputStream,
|
||||||
) {
|
): Result<Unit, CryptoHandlerException> {
|
||||||
val keys = pgpKeyManager.getAllKeys().unwrap()
|
val keys = pgpKeyManager.getAllKeys().unwrap()
|
||||||
pgpCryptoHandler.decrypt(keys, password, message, out)
|
return pgpCryptoHandler.decrypt(keys, password, message, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun encryptPgp(
|
private suspend fun encryptPgp(
|
||||||
identities: List<GpgIdentifier>,
|
identities: List<GpgIdentifier>,
|
||||||
content: ByteArrayInputStream,
|
content: ByteArrayInputStream,
|
||||||
out: ByteArrayOutputStream,
|
out: ByteArrayOutputStream,
|
||||||
) {
|
): Result<Unit, CryptoHandlerException> {
|
||||||
val keys = identities.map { ident -> pgpKeyManager.getKeyById(ident) }.getAll()
|
val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.getAll()
|
||||||
pgpCryptoHandler.encrypt(
|
return pgpCryptoHandler.encrypt(
|
||||||
keys,
|
keys,
|
||||||
content,
|
content,
|
||||||
out,
|
out,
|
||||||
|
|
|
@ -17,13 +17,13 @@ import app.passwordstore.data.password.FieldItem
|
||||||
import app.passwordstore.databinding.DecryptLayoutBinding
|
import app.passwordstore.databinding.DecryptLayoutBinding
|
||||||
import app.passwordstore.ui.adapters.FieldItemAdapter
|
import app.passwordstore.ui.adapters.FieldItemAdapter
|
||||||
import app.passwordstore.util.extensions.getString
|
import app.passwordstore.util.extensions.getString
|
||||||
import app.passwordstore.util.extensions.isErr
|
|
||||||
import app.passwordstore.util.extensions.unsafeLazy
|
import app.passwordstore.util.extensions.unsafeLazy
|
||||||
import app.passwordstore.util.extensions.viewBinding
|
import app.passwordstore.util.extensions.viewBinding
|
||||||
import app.passwordstore.util.settings.Constants
|
import app.passwordstore.util.settings.Constants
|
||||||
import app.passwordstore.util.settings.PreferenceKeys
|
import app.passwordstore.util.settings.PreferenceKeys
|
||||||
|
import com.github.michaelbull.result.Err
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
import com.github.michaelbull.result.runCatching
|
import com.github.michaelbull.result.runCatching
|
||||||
import com.github.michaelbull.result.unwrapError
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -66,7 +66,7 @@ class DecryptActivity : BasePgpActivity() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decrypt(isError = false)
|
askPassphrase(isError = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
@ -137,7 +137,7 @@ class DecryptActivity : BasePgpActivity() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decrypt(isError: Boolean) {
|
private fun askPassphrase(isError: Boolean) {
|
||||||
if (retries < MAX_RETRIES) {
|
if (retries < MAX_RETRIES) {
|
||||||
retries += 1
|
retries += 1
|
||||||
} else {
|
} else {
|
||||||
|
@ -150,10 +150,17 @@ class DecryptActivity : BasePgpActivity() {
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
dialog.password.collectLatest { value ->
|
dialog.password.collectLatest { value ->
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
val res = runCatching { decrypt(value) }
|
when (val result = decryptWithPassphrase(value)) {
|
||||||
if (res.isErr()) {
|
is Ok -> {
|
||||||
logcat(ERROR) { res.unwrapError().stackTraceToString() }
|
val entry = passwordEntryFactory.create(result.value.toByteArray())
|
||||||
decrypt(isError = true)
|
passwordEntry = entry
|
||||||
|
createPasswordUI(entry)
|
||||||
|
startAutoDismissTimer()
|
||||||
|
}
|
||||||
|
is Err -> {
|
||||||
|
logcat(ERROR) { result.error.stackTraceToString() }
|
||||||
|
askPassphrase(isError = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,26 +168,22 @@ class DecryptActivity : BasePgpActivity() {
|
||||||
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
|
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun decrypt(password: String) {
|
private suspend fun decryptWithPassphrase(password: String) = runCatching {
|
||||||
val message = withContext(Dispatchers.IO) { File(fullPath).readBytes().inputStream() }
|
val message = withContext(Dispatchers.IO) { File(fullPath).readBytes().inputStream() }
|
||||||
|
val outputStream = ByteArrayOutputStream()
|
||||||
val result =
|
val result =
|
||||||
withContext(Dispatchers.IO) {
|
repository.decrypt(
|
||||||
val outputStream = ByteArrayOutputStream()
|
password,
|
||||||
repository.decrypt(
|
message,
|
||||||
password,
|
outputStream,
|
||||||
message,
|
)
|
||||||
outputStream,
|
when (result) {
|
||||||
)
|
is Ok -> outputStream
|
||||||
outputStream
|
is Err -> throw result.error
|
||||||
}
|
}
|
||||||
startAutoDismissTimer()
|
|
||||||
|
|
||||||
val entry = passwordEntryFactory.create(result.toByteArray())
|
|
||||||
passwordEntry = entry
|
|
||||||
createPasswordUi(entry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createPasswordUi(entry: PasswordEntry) =
|
private suspend fun createPasswordUI(entry: PasswordEntry) =
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val showPassword = settings.getBoolean(PreferenceKeys.SHOW_PASSWORD, true)
|
val showPassword = settings.getBoolean(PreferenceKeys.SHOW_PASSWORD, true)
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
|
Loading…
Reference in a new issue