Skip to content

Commit

Permalink
Handled the case "no private key available for account(create a new k…
Browse files Browse the repository at this point in the history
…ey for email)".| #597
  • Loading branch information
DenBond7 committed Apr 8, 2024
1 parent 398ca73 commit 391ab6d
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ fun LifecycleOwner.showActionDialogFragment(
requestKey: String,
dialogTitle: String? = null,
isCancelable: Boolean = true,
items: List<DialogItem>
items: List<DialogItem>,
bundle: Bundle? = null
) {
showDialogFragment(navController) {
return@showDialogFragment object : NavDirections {
Expand All @@ -177,7 +178,8 @@ fun LifecycleOwner.showActionDialogFragment(
requestKey = requestKey,
dialogTitle = dialogTitle,
isCancelable = isCancelable,
items = items.toTypedArray()
items = items.toTypedArray(),
bundle = bundle
).toBundle()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import com.flowcrypt.email.extensions.showActionDialogFragment
import com.flowcrypt.email.extensions.showChoosePublicKeyDialogFragment
import com.flowcrypt.email.extensions.showDialogFragment
import com.flowcrypt.email.extensions.showInfoDialog
import com.flowcrypt.email.extensions.showInfoDialogWithExceptionDetails
import com.flowcrypt.email.extensions.showKeyboard
import com.flowcrypt.email.extensions.showNeedPassphraseDialog
import com.flowcrypt.email.extensions.supportActionBar
Expand All @@ -82,6 +83,7 @@ import com.flowcrypt.email.jetpack.lifecycle.CustomAndroidViewModelFactory
import com.flowcrypt.email.jetpack.viewmodel.AccountAliasesViewModel
import com.flowcrypt.email.jetpack.viewmodel.ComposeMsgViewModel
import com.flowcrypt.email.jetpack.viewmodel.DraftViewModel
import com.flowcrypt.email.jetpack.viewmodel.PrivateKeysViewModel
import com.flowcrypt.email.jetpack.viewmodel.RecipientsAutoCompleteViewModel
import com.flowcrypt.email.jetpack.viewmodel.RecipientsViewModel
import com.flowcrypt.email.model.DialogItem
Expand Down Expand Up @@ -111,6 +113,7 @@ import com.flowcrypt.email.util.UIUtil
import com.flowcrypt.email.util.exception.DecryptionException
import com.flowcrypt.email.util.exception.ExceptionUtil
import com.flowcrypt.email.util.exception.NoKeyAvailableException
import com.flowcrypt.email.util.exception.SavePrivateKeyToDatabaseException
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
Expand Down Expand Up @@ -154,6 +157,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}
}
protected val privateKeysViewModel: PrivateKeysViewModel by viewModels()

private val draftViewModel: DraftViewModel by viewModels {
object : CustomAndroidViewModelFactory(requireActivity().application) {
Expand Down Expand Up @@ -330,6 +334,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
setupRecipientsAutoCompleteViewModel()
setupAccountAliasesViewModel()
setupPrivateKeysViewModel()
observePrivateKeysChanges()

subscribeToSetWebPortalPassword()
subscribeToSelectRecipients()
Expand All @@ -342,6 +347,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
subscribeToChoosePrivateKeysDialogFragment()
subscribeToAddNewUserIdToPrivateKeyDialogFragment()
subscribeToCreateOutgoingMessageDialogFragment()
subscribeToCreatePrivateKey()

val isEncryptedMode =
composeMsgViewModel.msgEncryptionType === MessageEncryptionType.ENCRYPTED
Expand Down Expand Up @@ -1123,7 +1129,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}

private fun setupPrivateKeysViewModel() {
private fun observePrivateKeysChanges() {
KeysStorageImpl.getInstance(requireContext()).secretKeyRingsLiveData
.observe(viewLifecycleOwner) {
updateFromAddressAdapter(it)
Expand Down Expand Up @@ -1389,7 +1395,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
btnName = getString(R.string.fix),
duration = Snackbar.LENGTH_LONG
) {
fixNoKeyAvailableIssue(text)
fixNoKeyAvailableIssue(text, email)
}
}
}
Expand Down Expand Up @@ -1467,7 +1473,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
binding?.spinnerFrom?.selectedItemPosition ?: Spinner.INVALID_POSITION
) ?: ""
val text = getString(R.string.no_key_available, email)
fixNoKeyAvailableIssue(text)
fixNoKeyAvailableIssue(text, email)
return false
}

Expand Down Expand Up @@ -1691,6 +1697,10 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
ActionsDialogFragment.KEY_REQUEST_RESULT
) ?: return@setFragmentResultListener

val email = bundle.getBundle(
ActionsDialogFragment.KEY_REQUEST_INCOMING_BUNDLE
)?.getString(EMAIL) ?: binding?.editTextFrom?.text.toString()

when (item.id) {
RESULT_CODE_IMPORT_PRIVATE_KEY -> {
account?.let { accountEntity ->
Expand Down Expand Up @@ -1719,6 +1729,23 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}
}

RESULT_CODE_CREATE_NEW_PRIVATE_KEY -> {
val existingAccount = account
if (existingAccount != null) {
navController?.navigate(
object : NavDirections {
override val actionId = R.id.create_new_private_key_graph
override val arguments = CreatePrivateKeyFirstFragmentArgs(
requestKey = REQUEST_KEY_CREATE_NEW_KEY,
accountEntity = existingAccount.copy(email = email)
).toBundle()
}
)
} else {
toast(R.string.unknown_error)
}
}
}
}
}
Expand Down Expand Up @@ -1826,6 +1853,15 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}

private fun subscribeToCreatePrivateKey() {
setFragmentResultListener(REQUEST_KEY_CREATE_NEW_KEY) { _, bundle ->
val pgpKeyRingDetails = bundle.getParcelableViaExt<PgpKeyRingDetails>(
CreatePrivateKeyFirstFragment.KEY_CREATED_KEY
) ?: return@setFragmentResultListener
importCreatedPrivateKey(listOf(pgpKeyRingDetails))
}
}

private fun setupRecipientsAutoCompleteViewModel() {
launchAndRepeatWithViewLifecycle {
recipientsAutoCompleteViewModel.autoCompleteResultStateFlow.collect {
Expand Down Expand Up @@ -1896,6 +1932,42 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}

private fun setupPrivateKeysViewModel() {
privateKeysViewModel.savePrivateKeysLiveData.observe(viewLifecycleOwner) {
it?.let {
when (it.status) {
Result.Status.LOADING -> {
toast(R.string.processing)
}

Result.Status.SUCCESS -> {
it.data?.let { pair ->
if (pair.second.isNotEmpty()) {
toast(R.string.created_key_was_imported)
}
}
}

Result.Status.ERROR, Result.Status.EXCEPTION -> {
val exception = it.exception
if (exception is SavePrivateKeyToDatabaseException) {
showSnackbar(
msgText = exception.message ?: exception.javaClass.simpleName,
btnName = getString(R.string.retry),
duration = Snackbar.LENGTH_INDEFINITE,
onClickListener = { importCreatedPrivateKey(exception.keys) }
)
} else {
showInfoDialogWithExceptionDetails(it.exception, it.exceptionMsg)
}
}

else -> {}
}
}
}
}

private fun tryToSendMessage() {
snackBar?.dismiss()

Expand Down Expand Up @@ -1933,7 +2005,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}

private fun fixNoKeyAvailableIssue(text: String) {
private fun fixNoKeyAvailableIssue(text: String, email: String) {
if (account?.clientConfiguration?.usesKeyManager() == true) {
toast(getString(R.string.no_prv_keys_ask_admin))
} else {
Expand All @@ -1952,8 +2024,14 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
iconResourceId = R.drawable.ic_edit_key_add_user_id,
title = getString(R.string.add_email_to_existing_key),
id = RESULT_CODE_ADD_USER_ID_TO_EXISTING_PRIVATE_KEY
),
DialogItem(
iconResourceId = R.drawable.ic_create_new_key,
title = getString(R.string.create_a_new_key),
id = RESULT_CODE_CREATE_NEW_PRIVATE_KEY
)
)
),
bundle = Bundle().apply { putString(EMAIL, email) }
)
}
}
Expand All @@ -1979,9 +2057,18 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
}
}

private fun importCreatedPrivateKey(keys: List<PgpKeyRingDetails>) {
privateKeysViewModel.encryptAndSaveKeysToDatabase(
accountEntity = account,
keys = keys
)
}

companion object {
private val TAG = CreateMessageFragment::class.java.simpleName

private const val EMAIL = "email"

private val REQUEST_KEY_CHOOSE_PUBLIC_KEY = GeneralUtil.generateUniqueExtraKey(
"REQUEST_KEY_CHOOSE_PUBLIC_KEY",
CreateMessageFragment::class.java
Expand Down Expand Up @@ -2035,8 +2122,13 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
CreateMessageFragment::class.java
)

private val REQUEST_KEY_CREATE_NEW_KEY = GeneralUtil.generateUniqueExtraKey(
"REQUEST_KEY_CREATE_NEW_KEY", CreateMessageFragment::class.java
)

private const val RESULT_CODE_IMPORT_PRIVATE_KEY = 1
private const val RESULT_CODE_ADD_USER_ID_TO_EXISTING_PRIVATE_KEY = 2
private const val RESULT_CODE_CREATE_NEW_PRIVATE_KEY = 3

private const val REQUEST_CODE_FIX_MISSING_PASSPHRASE_FOR_PRIVATE_KEY_BY_SENDER_EMAIL = 1
private const val REQUEST_CODE_FIX_MISSING_PASSPHRASE_FOR_PRIVATE_KEY_BY_FINGERPRINT = 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.annotation.IntDef
import androidx.core.os.bundleOf
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.setFragmentResultListener
import androidx.navigation.NavDirections
import androidx.navigation.fragment.navArgs
import com.flowcrypt.email.R
import com.flowcrypt.email.api.retrofit.response.model.ClientConfiguration
Expand Down Expand Up @@ -68,11 +69,13 @@ class CreateOrImportPrivateKeyDuringSetupFragment :
} else {
binding?.buttonCreateNewKey?.setOnClickListener {
navController?.navigate(
CreateOrImportPrivateKeyDuringSetupFragmentDirections
.actionCreateOrImportPrivateKeyDuringSetupFragmentToCreatePrivateKeyFirstFragment(
object : NavDirections {
override val actionId = R.id.create_new_private_key_graph
override val arguments = CreatePrivateKeyFirstFragmentArgs(
requestKey = REQUEST_KEY_CREATE_KEY,
accountEntity = args.accountEntity
)
).toBundle()
}
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class ActionsDialogFragment : BaseDialogFragment() {
setFragmentResult(
args.requestKey,
bundleOf(
KEY_REQUEST_RESULT to args.items[which]
KEY_REQUEST_RESULT to args.items[which],
KEY_REQUEST_INCOMING_BUNDLE to args.bundle
)
)
}
Expand All @@ -51,5 +52,9 @@ class ActionsDialogFragment : BaseDialogFragment() {
val KEY_REQUEST_RESULT = GeneralUtil.generateUniqueExtraKey(
"KEY_REQUEST_RESULT", ActionsDialogFragment::class.java
)

val KEY_REQUEST_INCOMING_BUNDLE = GeneralUtil.generateUniqueExtraKey(
"KEY_REQUEST_INCOMING_BUNDLE", ActionsDialogFragment::class.java
)
}
}
22 changes: 22 additions & 0 deletions FlowCrypt/src/main/res/drawable/ic_create_new_key.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!--
~ © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
~ Contributors: denbond7
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:tint="@color/gray"
android:viewportWidth="960"
android:viewportHeight="960">

<path
android:fillColor="@android:color/white"
android:pathData="M654.45,443.76L654.45,323.76L534.45,323.76v-80h120v-120h80v120h120v80L734.45,323.76v120z" />

<path
android:fillColor="@android:color/white"
android:pathData="m324.77,836.24 l-82.21,-82.21v-254.85c-40.19,-11.87 -73.07,-34.48 -98.65,-67.82 -25.58,-33.34 -38.36,-71.93 -38.36,-115.78 0,-52.98 18.73,-98.19 56.18,-135.65C199.17,142.49 244.39,123.76 297.37,123.76c52.98,0 98.19,18.73 135.65,56.18 37.45,37.45 56.18,82.67 56.18,135.65 0,41.1 -11.65,77.64 -34.94,109.61 -23.29,31.97 -52.75,54.81 -88.37,68.51l68.51,68.51 -82.21,82.21 82.21,82.21zM297.37,342.98c15.53,0 28.54,-5.25 39.05,-15.76 10.5,-10.5 15.76,-23.52 15.76,-39.05 0,-15.53 -5.25,-28.54 -15.76,-39.05 -10.5,-10.5 -23.52,-15.76 -39.05,-15.76 -15.53,0 -28.54,5.25 -39.05,15.76 -10.5,10.5 -15.76,23.52 -15.76,39.05 0,15.53 5.25,28.54 15.76,39.05 10.5,10.5 23.52,15.76 39.05,15.76z"
android:strokeWidth="1.37015" />

</vector>
5 changes: 5 additions & 0 deletions FlowCrypt/src/main/res/navigation/actions_dialog_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@
<argument
android:name="items"
app:argType="com.flowcrypt.email.model.DialogItem[]" />
<argument
android:name="bundle"
app:argType="android.os.Bundle"
app:nullable="true"
android:defaultValue="@null" />
</dialog>
</navigation>
1 change: 1 addition & 0 deletions FlowCrypt/src/main/res/navigation/create_msg_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<include app:graph="@navigation/check_keys_graph" />
<include app:graph="@navigation/pass_phrase_strength_graph" />
<include app:graph="@navigation/add_new_userid_to_private_key_dialog_graph" />
<include app:graph="@navigation/create_new_private_key_graph" />

<fragment
android:id="@+id/createMessageFragment"
Expand Down
58 changes: 58 additions & 0 deletions FlowCrypt/src/main/res/navigation/create_new_private_key_graph.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
~ Contributors: denbond7
-->

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/create_new_private_key_graph"
app:startDestination="@id/createPrivateKeyFirstFragment">

<fragment
android:id="@+id/createPrivateKeyFirstFragment"
android:name="com.flowcrypt.email.ui.activity.fragment.CreatePrivateKeyFirstFragment"
tools:layout="@layout/fragment_create_private_key_first">
<argument
android:name="requestKey"
app:argType="string" />
<argument
android:name="accountEntity"
app:argType="com.flowcrypt.email.database.entity.AccountEntity" />
<action
android:id="@+id/action_createPrivateKeyFirstFragment_to_createPrivateKeySecondFragment"
app:destination="@id/createPrivateKeySecondFragment" />
</fragment>

<fragment
android:id="@+id/createPrivateKeySecondFragment"
android:name="com.flowcrypt.email.ui.activity.fragment.CreatePrivateKeySecondFragment"
android:label="@string/security"
tools:layout="@layout/fragment_create_private_key_second">
<argument
android:name="accountEntity"
app:argType="com.flowcrypt.email.database.entity.AccountEntity" />
<argument
android:name="passphrase"
app:argType="integer[]" />
<action
android:id="@+id/action_createPrivateKeySecondFragment_to_createPrivateKeyDialogFragment"
app:destination="@id/createPrivateKeyDialogFragment" />
</fragment>

<dialog
android:id="@+id/createPrivateKeyDialogFragment"
android:name="com.flowcrypt.email.ui.activity.fragment.dialog.CreatePrivateKeyDialogFragment"
tools:layout="@layout/fragment_create_private_key_dialog">
<argument
android:name="requestKey"
app:argType="string" />
<argument
android:name="accountEntity"
app:argType="com.flowcrypt.email.database.entity.AccountEntity" />
<argument
android:name="passphrase"
app:argType="string" />
</dialog>

</navigation>
Loading

0 comments on commit 391ab6d

Please sign in to comment.