From b313c4216ea86d6202e2730b26e4fc3924d731eb Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Fri, 7 Oct 2022 19:41:14 +0530 Subject: fix(app): ensure decryption errors are captured by UI --- .../passwordstore/data/crypto/CryptoRepository.kt | 20 ++++----- .../app/passwordstore/ui/crypto/DecryptActivity.kt | 51 ++++++++++++---------- 2 files changed, 36 insertions(+), 35 deletions(-) (limited to 'app') diff --git a/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt b/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt index d52574c9..b673e94c 100644 --- a/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt +++ b/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt @@ -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, 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 { val keys = pgpKeyManager.getAllKeys().unwrap() - pgpCryptoHandler.decrypt(keys, password, message, out) + return pgpCryptoHandler.decrypt(keys, password, message, out) } private suspend fun encryptPgp( identities: List, content: ByteArrayInputStream, out: ByteArrayOutputStream, - ) { - val keys = identities.map { ident -> pgpKeyManager.getKeyById(ident) }.getAll() - pgpCryptoHandler.encrypt( + ): Result { + val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.getAll() + return pgpCryptoHandler.encrypt( keys, content, out, diff --git a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt index dfe9f8bc..bb3d2fdf 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt @@ -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 outputStream = ByteArrayOutputStream() val result = - withContext(Dispatchers.IO) { - val outputStream = ByteArrayOutputStream() - repository.decrypt( - password, - message, - outputStream, - ) - outputStream - } - startAutoDismissTimer() - - val entry = passwordEntryFactory.create(result.toByteArray()) - passwordEntry = entry - createPasswordUi(entry) + repository.decrypt( + password, + message, + outputStream, + ) + when (result) { + is Ok -> outputStream + is Err -> throw result.error + } } - private suspend fun createPasswordUi(entry: PasswordEntry) = + private suspend fun createPasswordUI(entry: PasswordEntry) = withContext(Dispatchers.Main) { val showPassword = settings.getBoolean(PreferenceKeys.SHOW_PASSWORD, true) invalidateOptionsMenu() -- cgit v1.2.3