From 4b14ee4695b452cd24353f05809f64d0b0ee4b6d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:34:05 +0100 Subject: [PATCH] Partial implementation of QR login logic --- .../src/main/res/values/strings.xml | 1 + .../login/qr/QrCodeLoginConnectionStatus.kt | 4 +- .../features/login/qr/QrCodeLoginErrorType.kt | 23 ----- .../login/qr/QrCodeLoginStatusFragment.kt | 12 +-- .../features/login/qr/QrCodeLoginViewModel.kt | 86 +++++++++++++------ 5 files changed, 73 insertions(+), 53 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginErrorType.kt diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 8fb019dcd8..68e8b495f8 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3344,6 +3344,7 @@ Linking with this device is not supported. The linking wasn’t completed in the required time. The request was denied on the other device. + The request failed. Open ${app_name} on your other device Go to Settings -> Security & Privacy -> Show All Sessions Select \'Show QR code\' diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt index 330562b874..4de191f863 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt @@ -16,9 +16,11 @@ package im.vector.app.features.login.qr +import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason + sealed class QrCodeLoginConnectionStatus { object ConnectingToDevice : QrCodeLoginConnectionStatus() data class Connected(val securityCode: String, val canConfirmSecurityCode: Boolean) : QrCodeLoginConnectionStatus() object SigningIn : QrCodeLoginConnectionStatus() - data class Failed(val errorType: QrCodeLoginErrorType, val canTryAgain: Boolean) : QrCodeLoginConnectionStatus() + data class Failed(val errorType: RendezvousFailureReason, val canTryAgain: Boolean) : QrCodeLoginConnectionStatus() } diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginErrorType.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginErrorType.kt deleted file mode 100644 index 9a6cc13de0..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginErrorType.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2022 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.app.features.login.qr - -enum class QrCodeLoginErrorType { - DEVICE_IS_NOT_SUPPORTED, - TIMEOUT, - REQUEST_WAS_DENIED, -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt index c1db1832ef..da539b8ede 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt @@ -27,6 +27,7 @@ import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentQrCodeLoginStatusBinding import im.vector.app.features.themes.ThemeUtils +import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason @AndroidEntryPoint class QrCodeLoginStatusFragment : VectorBaseFragment() { @@ -77,11 +78,12 @@ class QrCodeLoginStatusFragment : VectorBaseFragment getString(R.string.qr_code_login_header_failed_device_is_not_supported_description) - QrCodeLoginErrorType.TIMEOUT -> getString(R.string.qr_code_login_header_failed_timeout_description) - QrCodeLoginErrorType.REQUEST_WAS_DENIED -> getString(R.string.qr_code_login_header_failed_denied_description) + private fun getErrorCode(reason: RendezvousFailureReason): String { + return when (reason) { + RendezvousFailureReason.UnsupportedAlgorithm, RendezvousFailureReason.UnsupportedTransport -> getString(R.string.qr_code_login_header_failed_device_is_not_supported_description) + RendezvousFailureReason.Expired -> getString(R.string.qr_code_login_header_failed_timeout_description) + RendezvousFailureReason.UserDeclined -> getString(R.string.qr_code_login_header_failed_denied_description) + else -> getString(R.string.qr_code_login_header_failed_other_description) } } diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt index da3348653c..d0c34b83af 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt @@ -23,13 +23,19 @@ import dagger.assisted.AssistedInject import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel -import kotlinx.coroutines.delay +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.internal.rendezvous.Rendezvous +import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason +import timber.log.Timber class QrCodeLoginViewModel @AssistedInject constructor( - @Assisted private val initialState: QrCodeLoginViewState, + @Assisted private val initialState: QrCodeLoginViewState ) : VectorViewModel(initialState) { + val TAG: String = QrCodeLoginViewModel::class.java.simpleName + @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { override fun create(initialState: QrCodeLoginViewState): QrCodeLoginViewModel @@ -59,32 +65,64 @@ class QrCodeLoginViewModel @AssistedInject constructor( } private fun handleOnQrCodeScanned(action: QrCodeLoginAction.OnQrCodeScanned) { - if (isValidQrCode(action.qrCode)) { - setState { - copy( - connectionStatus = QrCodeLoginConnectionStatus.ConnectingToDevice - ) - } - _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) + Timber.tag(TAG).d("Scanned code: ${action.qrCode}") + + val rendezvous = Rendezvous.buildChannelFromCode(action.qrCode) { reason -> + Timber.tag(TAG).d("Rendezvous cancelled: $reason") + onFailed(reason) } - // TODO. UI test purpose. Fixme remove! - viewModelScope.launch { - delay(3000) - onFailed(QrCodeLoginErrorType.TIMEOUT, true) - delay(3000) - onConnectionEstablished("1234-ABCD-5678-EFGH") - delay(3000) - onSigningIn() - delay(3000) - onFailed(QrCodeLoginErrorType.DEVICE_IS_NOT_SUPPORTED, false) - } - } - - private fun onFailed(errorType: QrCodeLoginErrorType, canTryAgain: Boolean) { setState { copy( - connectionStatus = QrCodeLoginConnectionStatus.Failed(errorType, canTryAgain) + connectionStatus = QrCodeLoginConnectionStatus.ConnectingToDevice + ) + } + + _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) + + viewModelScope.launch(Dispatchers.IO) { + val confirmationCode = rendezvous.startAfterScanningCode() + Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") + confirmationCode ?.let { + onConnectionEstablished(it) + } + rendezvous.completeOnNewDevice() + } + // if (isValidQrCode(action.qrCode)) { +// setState { +// copy( +// connectionStatus = QrCodeLoginConnectionStatus.ConnectingToDevice +// ) +// } +// _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) +// } +// + +// // TODO. UI test purpose. Fixme remove! +// viewModelScope.launch { +// delay(3000) +// onFailed(QrCodeLoginErrorType.TIMEOUT, true) +// delay(3000) +// onConnectionEstablished("1234-ABCD-5678-EFGH") +// delay(3000) +// onSigningIn() +// delay(3000) +// onFailed(QrCodeLoginErrorType.DEVICE_IS_NOT_SUPPORTED, false) +// } +// // TODO. UI test purpose. Fixme remove! +// viewModelScope.launch { +// delay(3000) +// onConnectionEstablished("1234-ABCD-5678-EFGH") +// delay(3000) +// onSigningIn() +// } + } + + + private fun onFailed(reason: RendezvousFailureReason) { + setState { + copy( + connectionStatus = QrCodeLoginConnectionStatus.Failed(reason, reason.canRetry) ) } }