From 369f40c804ae1af27ed7d7cce0f2e92b6fc388a4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 16 Jun 2020 16:09:27 +0200 Subject: [PATCH] Remove developer mode option to set up cross-signing --- .../CrossSigningEpoxyController.kt | 163 ------------------ .../CrossSigningSettingsAction.kt | 23 +++ .../CrossSigningSettingsController.kt | 139 +++++++++++++++ .../CrossSigningSettingsFragment.kt | 36 ++-- .../CrossSigningSettingsViewEvents.kt | 1 - .../CrossSigningSettingsViewModel.kt | 83 +-------- .../CrossSigningSettingsViewState.kt | 27 +++ 7 files changed, 202 insertions(+), 270 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningEpoxyController.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsAction.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsController.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewState.kt diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningEpoxyController.kt deleted file mode 100644 index 5b7875d0ce..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningEpoxyController.kt +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2020 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package im.vector.riotx.features.settings.crosssigning - -import com.airbnb.epoxy.TypedEpoxyController -import im.vector.riotx.R -import im.vector.riotx.core.epoxy.loadingItem -import im.vector.riotx.core.resources.ColorProvider -import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.core.ui.list.genericItem -import im.vector.riotx.core.ui.list.genericItemWithValue -import im.vector.riotx.core.utils.DimensionConverter -import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem -import im.vector.riotx.features.settings.VectorPreferences -import me.gujun.android.span.span -import javax.inject.Inject - -class CrossSigningEpoxyController @Inject constructor( - private val stringProvider: StringProvider, - private val colorProvider: ColorProvider, - private val dimensionConverter: DimensionConverter, - private val vectorPreferences: VectorPreferences -) : TypedEpoxyController() { - - interface InteractionListener { - fun onInitializeCrossSigningKeys() - fun verifySession() - } - - var interactionListener: InteractionListener? = null - - override fun buildModels(data: CrossSigningSettingsViewState?) { - if (data == null) return - if (data.xSigningKeyCanSign) { - genericItem { - id("can") - titleIconResourceId(R.drawable.ic_shield_trusted) - title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete)) - } - } else if (data.xSigningKeysAreTrusted) { - genericItem { - id("trusted") - titleIconResourceId(R.drawable.ic_shield_custom) - title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted)) - } - if (!data.isUploadingKeys) { - bottomSheetVerificationActionItem { - id("verify") - title(stringProvider.getString(R.string.crosssigning_verify_this_session)) - titleColor(colorProvider.getColor(R.color.riotx_positive_accent)) - iconRes(R.drawable.ic_arrow_right) - iconColor(colorProvider.getColor(R.color.riotx_positive_accent)) - listener { - interactionListener?.verifySession() - } - } - } - } else if (data.xSigningIsEnableInAccount) { - genericItem { - id("enable") - titleIconResourceId(R.drawable.ic_shield_black) - title(stringProvider.getString(R.string.encryption_information_dg_xsigning_not_trusted)) - } - bottomSheetVerificationActionItem { - id("verify") - title(stringProvider.getString(R.string.crosssigning_verify_this_session)) - titleColor(colorProvider.getColor(R.color.riotx_positive_accent)) - iconRes(R.drawable.ic_arrow_right) - iconColor(colorProvider.getColor(R.color.riotx_positive_accent)) - listener { - interactionListener?.verifySession() - } - } - } else { - genericItem { - id("not") - title(stringProvider.getString(R.string.encryption_information_dg_xsigning_disabled)) - } - if (vectorPreferences.developerMode() && !data.isUploadingKeys) { - bottomSheetVerificationActionItem { - id("initKeys") - title(stringProvider.getString(R.string.initialize_cross_signing)) - titleColor(colorProvider.getColor(R.color.riotx_positive_accent)) - iconRes(R.drawable.ic_arrow_right) - iconColor(colorProvider.getColor(R.color.riotx_positive_accent)) - listener { - interactionListener?.onInitializeCrossSigningKeys() - } - } - } - } - - if (data.isUploadingKeys) { - loadingItem { - id("loading") - } - } else { - val crossSigningKeys = data.crossSigningInfo - - crossSigningKeys?.masterKey()?.let { - genericItemWithValue { - id("msk") - titleIconResourceId(R.drawable.key_small) - title( - span { - +"Master Key:\n" - span { - text = it.unpaddedBase64PublicKey ?: "" - textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) - textSize = dimensionConverter.spToPx(12) - } - } - ) - } - } - crossSigningKeys?.userKey()?.let { - genericItemWithValue { - id("usk") - titleIconResourceId(R.drawable.key_small) - title( - span { - +"User Key:\n" - span { - text = it.unpaddedBase64PublicKey ?: "" - textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) - textSize = dimensionConverter.spToPx(12) - } - } - ) - } - } - crossSigningKeys?.selfSigningKey()?.let { - genericItemWithValue { - id("ssk") - titleIconResourceId(R.drawable.key_small) - title( - span { - +"Self Signed Key:\n" - span { - text = it.unpaddedBase64PublicKey ?: "" - textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) - textSize = dimensionConverter.spToPx(12) - } - } - ) - } - } - } - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsAction.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsAction.kt new file mode 100644 index 0000000000..8b92227465 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsAction.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.settings.crosssigning + +import im.vector.riotx.core.platform.VectorViewModelAction + +sealed class CrossSigningSettingsAction : VectorViewModelAction { + object VerifySession : CrossSigningSettingsAction() +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsController.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsController.kt new file mode 100644 index 0000000000..274f7c0933 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsController.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.riotx.features.settings.crosssigning + +import com.airbnb.epoxy.TypedEpoxyController +import im.vector.riotx.R +import im.vector.riotx.core.resources.ColorProvider +import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.core.ui.list.genericItem +import im.vector.riotx.core.ui.list.genericItemWithValue +import im.vector.riotx.core.utils.DimensionConverter +import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem +import me.gujun.android.span.span +import javax.inject.Inject + +class CrossSigningSettingsController @Inject constructor( + private val stringProvider: StringProvider, + private val colorProvider: ColorProvider, + private val dimensionConverter: DimensionConverter +) : TypedEpoxyController() { + + interface InteractionListener { + fun verifySession() + } + + var interactionListener: InteractionListener? = null + + override fun buildModels(data: CrossSigningSettingsViewState?) { + if (data == null) return + if (data.xSigningKeyCanSign) { + genericItem { + id("can") + titleIconResourceId(R.drawable.ic_shield_trusted) + title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete)) + } + } else if (data.xSigningKeysAreTrusted) { + genericItem { + id("trusted") + titleIconResourceId(R.drawable.ic_shield_custom) + title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted)) + } + bottomSheetVerificationActionItem { + id("verify") + title(stringProvider.getString(R.string.crosssigning_verify_this_session)) + titleColor(colorProvider.getColor(R.color.riotx_positive_accent)) + iconRes(R.drawable.ic_arrow_right) + iconColor(colorProvider.getColor(R.color.riotx_positive_accent)) + listener { + interactionListener?.verifySession() + } + } + } else if (data.xSigningIsEnableInAccount) { + genericItem { + id("enable") + titleIconResourceId(R.drawable.ic_shield_black) + title(stringProvider.getString(R.string.encryption_information_dg_xsigning_not_trusted)) + } + bottomSheetVerificationActionItem { + id("verify") + title(stringProvider.getString(R.string.crosssigning_verify_this_session)) + titleColor(colorProvider.getColor(R.color.riotx_positive_accent)) + iconRes(R.drawable.ic_arrow_right) + iconColor(colorProvider.getColor(R.color.riotx_positive_accent)) + listener { + interactionListener?.verifySession() + } + } + } else { + genericItem { + id("not") + title(stringProvider.getString(R.string.encryption_information_dg_xsigning_disabled)) + } + } + + val crossSigningKeys = data.crossSigningInfo + + crossSigningKeys?.masterKey()?.let { + genericItemWithValue { + id("msk") + titleIconResourceId(R.drawable.key_small) + title( + span { + +"Master Key:\n" + span { + text = it.unpaddedBase64PublicKey ?: "" + textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) + textSize = dimensionConverter.spToPx(12) + } + } + ) + } + } + crossSigningKeys?.userKey()?.let { + genericItemWithValue { + id("usk") + titleIconResourceId(R.drawable.key_small) + title( + span { + +"User Key:\n" + span { + text = it.unpaddedBase64PublicKey ?: "" + textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) + textSize = dimensionConverter.spToPx(12) + } + } + ) + } + } + crossSigningKeys?.selfSigningKey()?.let { + genericItemWithValue { + id("ssk") + titleIconResourceId(R.drawable.key_small) + title( + span { + +"Self Signed Key:\n" + span { + text = it.unpaddedBase64PublicKey ?: "" + textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary) + textSize = dimensionConverter.spToPx(12) + } + } + ) + } + } + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt index 1f81fd7c7b..e9ab3dfab6 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt @@ -21,7 +21,6 @@ import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.riotx.R -import im.vector.riotx.core.dialogs.PromptPasswordDialog import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith import im.vector.riotx.core.extensions.exhaustive @@ -31,9 +30,9 @@ import kotlinx.android.synthetic.main.fragment_generic_recycler.* import javax.inject.Inject class CrossSigningSettingsFragment @Inject constructor( - private val epoxyController: CrossSigningEpoxyController, + private val controller: CrossSigningSettingsController, val viewModelFactory: CrossSigningSettingsViewModel.Factory -) : VectorBaseFragment(), CrossSigningEpoxyController.InteractionListener { +) : VectorBaseFragment(), CrossSigningSettingsController.InteractionListener { override fun getLayoutResId() = R.layout.fragment_generic_recycler @@ -43,7 +42,7 @@ class CrossSigningSettingsFragment @Inject constructor( super.onActivityCreated(savedInstanceState) viewModel.observeViewEvents { when (it) { - is CrossSigningSettingsViewEvents.Failure -> { + is CrossSigningSettingsViewEvents.Failure -> { AlertDialog.Builder(requireContext()) .setTitle(R.string.dialog_title_error) .setMessage(errorFormatter.toHumanReadable(it.throwable)) @@ -51,13 +50,8 @@ class CrossSigningSettingsFragment @Inject constructor( .show() Unit } - is CrossSigningSettingsViewEvents.RequestPassword -> { - requestPassword() - } - CrossSigningSettingsViewEvents.VerifySession -> { - (requireActivity() as? VectorBaseActivity)?.let { activity -> - activity.navigator.waitSessionVerification(activity) - } + CrossSigningSettingsViewEvents.VerifySession -> { + navigator.waitSessionVerification(requireActivity()) } }.exhaustive } @@ -74,31 +68,21 @@ class CrossSigningSettingsFragment @Inject constructor( } override fun invalidate() = withState(viewModel) { state -> - epoxyController.setData(state) + controller.setData(state) } private fun setupRecyclerView() { - recyclerView.configureWith(epoxyController, hasFixedSize = false, disableItemAnimation = true) - epoxyController.interactionListener = this + recyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + controller.interactionListener = this } override fun onDestroyView() { recyclerView.cleanup() - epoxyController.interactionListener = null + controller.interactionListener = null super.onDestroyView() } - private fun requestPassword() { - PromptPasswordDialog().show(requireActivity()) { password -> - viewModel.handle(CrossSigningAction.PasswordEntered(password)) - } - } - - override fun onInitializeCrossSigningKeys() { - viewModel.handle(CrossSigningAction.InitializeCrossSigning) - } - override fun verifySession() { - viewModel.handle(CrossSigningAction.VerifySession) + viewModel.handle(CrossSigningSettingsAction.VerifySession) } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt index 65a4a18485..0f5b1ff6f6 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt @@ -24,6 +24,5 @@ import im.vector.riotx.core.platform.VectorViewEvents sealed class CrossSigningSettingsViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : CrossSigningSettingsViewEvents() - object RequestPassword : CrossSigningSettingsViewEvents() object VerifySession : CrossSigningSettingsViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index f21a9c69d4..89a6aa9ef2 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -16,40 +16,19 @@ package im.vector.riotx.features.settings.crosssigning import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject -import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.auth.data.LoginFlowTypes -import im.vector.matrix.android.api.failure.toRegistrationFlowResponse import im.vector.matrix.android.api.session.Session -import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo import im.vector.matrix.android.internal.crypto.crosssigning.isVerified -import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth import im.vector.matrix.rx.rx import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorViewModel -import im.vector.riotx.core.platform.VectorViewModelAction - -data class CrossSigningSettingsViewState( - val crossSigningInfo: MXCrossSigningInfo? = null, - val xSigningIsEnableInAccount: Boolean = false, - val xSigningKeysAreTrusted: Boolean = false, - val xSigningKeyCanSign: Boolean = true, - val isUploadingKeys: Boolean = false -) : MvRxState - -sealed class CrossSigningAction : VectorViewModelAction { - object InitializeCrossSigning : CrossSigningAction() - object VerifySession : CrossSigningAction() - data class PasswordEntered(val password: String) : CrossSigningAction() -} class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted private val initialState: CrossSigningSettingsViewState, private val session: Session) - : VectorViewModel(initialState) { + : VectorViewModel(initialState) { init { session.rx().liveCrossSigningInfo(session.myUserId) @@ -67,75 +46,19 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat } } - // Storage when password is required - private var _pendingSession: String? = null - @AssistedInject.Factory interface Factory { fun create(initialState: CrossSigningSettingsViewState): CrossSigningSettingsViewModel } - override fun handle(action: CrossSigningAction) { + override fun handle(action: CrossSigningSettingsAction) { when (action) { - is CrossSigningAction.InitializeCrossSigning -> { - initializeCrossSigning(null) - } - is CrossSigningAction.PasswordEntered -> { - initializeCrossSigning(UserPasswordAuth( - session = _pendingSession, - user = session.myUserId, - password = action.password - )) - } - CrossSigningAction.VerifySession -> { + CrossSigningSettingsAction.VerifySession -> { _viewEvents.post(CrossSigningSettingsViewEvents.VerifySession) } }.exhaustive } - private fun initializeCrossSigning(auth: UserPasswordAuth?) { - _pendingSession = null - - setState { - copy(isUploadingKeys = true) - } - session.cryptoService().crossSigningService().initializeCrossSigning(auth, object : MatrixCallback { - override fun onSuccess(data: Unit) { - _pendingSession = null - - setState { - copy(isUploadingKeys = false) - } - } - - override fun onFailure(failure: Throwable) { - _pendingSession = null - - val registrationFlowResponse = failure.toRegistrationFlowResponse() - if (registrationFlowResponse != null) { - // Retry with authentication - if (registrationFlowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } == true) { - _pendingSession = registrationFlowResponse.session ?: "" - _viewEvents.post(CrossSigningSettingsViewEvents.RequestPassword) - } else { - // can't do this from here - _viewEvents.post(CrossSigningSettingsViewEvents.Failure(Throwable("You cannot do that from mobile"))) - - setState { - copy(isUploadingKeys = false) - } - } - } else { - _viewEvents.post(CrossSigningSettingsViewEvents.Failure(failure)) - - setState { - copy(isUploadingKeys = false) - } - } - } - }) - } - companion object : MvRxViewModelFactory { @JvmStatic diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewState.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewState.kt new file mode 100644 index 0000000000..769e110410 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewState.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.settings.crosssigning + +import com.airbnb.mvrx.MvRxState +import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo + +data class CrossSigningSettingsViewState( + val crossSigningInfo: MXCrossSigningInfo? = null, + val xSigningIsEnableInAccount: Boolean = false, + val xSigningKeysAreTrusted: Boolean = false, + val xSigningKeyCanSign: Boolean = true +) : MvRxState