fix(app): ensure decryption errors are captured by UI

This commit is contained in:
Harsh Shandilya 2022-10-07 19:41:14 +05:30
parent f778eab94e
commit b313c4216e
No known key found for this signature in database
2 changed files with 36 additions and 35 deletions

View file

@ -8,6 +8,8 @@ package app.passwordstore.data.crypto
import app.passwordstore.crypto.GpgIdentifier
import app.passwordstore.crypto.PGPKeyManager
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.unwrap
import java.io.ByteArrayInputStream
@ -27,34 +29,30 @@ constructor(
password: String,
message: ByteArrayInputStream,
out: ByteArrayOutputStream,
) {
withContext(Dispatchers.IO) { decryptPgp(password, message, out) }
}
) = withContext(Dispatchers.IO) { decryptPgp(password, message, out) }
suspend fun encrypt(
identities: List<GpgIdentifier>,
content: ByteArrayInputStream,
out: ByteArrayOutputStream,
) {
withContext(Dispatchers.IO) { encryptPgp(identities, content, out) }
}
) = withContext(Dispatchers.IO) { encryptPgp(identities, content, out) }
private suspend fun decryptPgp(
password: String,
message: ByteArrayInputStream,
out: ByteArrayOutputStream,
) {
): Result<Unit, CryptoHandlerException> {
val keys = pgpKeyManager.getAllKeys().unwrap()
pgpCryptoHandler.decrypt(keys, password, message, out)
return pgpCryptoHandler.decrypt(keys, password, message, out)
}
private suspend fun encryptPgp(
identities: List<GpgIdentifier>,
content: ByteArrayInputStream,
out: ByteArrayOutputStream,
) {
val keys = identities.map { ident -> pgpKeyManager.getKeyById(ident) }.getAll()
pgpCryptoHandler.encrypt(
): Result<Unit, CryptoHandlerException> {
val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.getAll()
return pgpCryptoHandler.encrypt(
keys,
content,
out,

View file

@ -17,13 +17,13 @@ import app.passwordstore.data.password.FieldItem
import app.passwordstore.databinding.DecryptLayoutBinding
import app.passwordstore.ui.adapters.FieldItemAdapter
import app.passwordstore.util.extensions.getString
import app.passwordstore.util.extensions.isErr
import app.passwordstore.util.extensions.unsafeLazy
import app.passwordstore.util.extensions.viewBinding
import app.passwordstore.util.settings.Constants
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.unwrapError
import dagger.hilt.android.AndroidEntryPoint
import java.io.ByteArrayOutputStream
import java.io.File
@ -66,7 +66,7 @@ class DecryptActivity : BasePgpActivity() {
true
}
}
decrypt(isError = false)
askPassphrase(isError = false)
}
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) {
retries += 1
} else {
@ -150,10 +150,17 @@ class DecryptActivity : BasePgpActivity() {
lifecycleScope.launch(Dispatchers.Main) {
dialog.password.collectLatest { value ->
if (value != null) {
val res = runCatching { decrypt(value) }
if (res.isErr()) {
logcat(ERROR) { res.unwrapError().stackTraceToString() }
decrypt(isError = true)
when (val result = decryptWithPassphrase(value)) {
is Ok -> {
val entry = passwordEntryFactory.create(result.value.toByteArray())
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")
}
private suspend fun decrypt(password: String) {
private suspend fun decryptWithPassphrase(password: String) = runCatching {
val message = withContext(Dispatchers.IO) { File(fullPath).readBytes().inputStream() }
val result =
withContext(Dispatchers.IO) {
val outputStream = ByteArrayOutputStream()
val result =
repository.decrypt(
password,
message,
outputStream,
)
outputStream
when (result) {
is Ok -> 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) {
val showPassword = settings.getBoolean(PreferenceKeys.SHOW_PASSWORD, true)
invalidateOptionsMenu()