From 21ae4c6ddbf29bd33f3888788717f0cbd06d74b5 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:11:15 +0100 Subject: [PATCH 01/93] Support for login by m.login.token during QR code sign in --- .../sdk/api/auth/AuthenticationService.kt | 14 +++ .../matrix/android/sdk/api/auth/LoginType.kt | 4 +- .../auth/DefaultAuthenticationService.kt | 15 +++- .../sdk/internal/auth/data/LoginParams.kt | 2 + .../internal/auth/data/PasswordLoginParams.kt | 4 +- .../internal/auth/data/TokenLoginParams.kt | 4 +- .../internal/auth/login/QrLoginTokenTask.kt | 88 +++++++++++++++++++ 7 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 5ae70e1978c..8f2a784d49b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -124,4 +124,18 @@ interface AuthenticationService { initialDeviceName: String, deviceId: String? = null ): Session + + /** + * Authenticate using m.login.token method during sign in with QR code. + * @param homeServerConnectionConfig the information about the homeserver and other configuration + * @param loginToken the m.login.token + * @param initialDeviceName the initial device name + * @param deviceId the device id, optional. If not provided or null, the server will generate one. + */ + suspend fun loginUsingQrLoginToken( + homeServerConnectionConfig: HomeServerConnectionConfig, + loginToken: String, + initialDeviceName: String, + deviceId: String? = null + ): Session } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt index 627a8256799..991b7b654d5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt @@ -22,7 +22,8 @@ enum class LoginType { UNSUPPORTED, CUSTOM, DIRECT, - UNKNOWN; + UNKNOWN, + QR; companion object { @@ -32,6 +33,7 @@ enum class LoginType { UNSUPPORTED.name -> UNSUPPORTED CUSTOM.name -> CUSTOM DIRECT.name -> DIRECT + QR.name -> QR else -> UNKNOWN } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 446f9318479..90dc57b4f0b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -39,6 +39,7 @@ import org.matrix.android.sdk.internal.auth.data.WebClientConfig import org.matrix.android.sdk.internal.auth.db.PendingSessionData import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard import org.matrix.android.sdk.internal.auth.login.DirectLoginTask +import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard import org.matrix.android.sdk.internal.auth.version.Versions import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices @@ -62,7 +63,8 @@ internal class DefaultAuthenticationService @Inject constructor( private val sessionCreator: SessionCreator, private val pendingSessionStore: PendingSessionStore, private val getWellknownTask: GetWellknownTask, - private val directLoginTask: DirectLoginTask + private val directLoginTask: DirectLoginTask, + private val loginTokenAuthTask: QrLoginTokenTask ) : AuthenticationService { private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData() @@ -404,6 +406,17 @@ internal class DefaultAuthenticationService @Inject constructor( ) } + override suspend fun loginUsingQrLoginToken(homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, initialDeviceName: String, deviceId: String?): Session { + return loginTokenAuthTask.execute( + QrLoginTokenTask.Params( + homeServerConnectionConfig = homeServerConnectionConfig, + loginToken = loginToken, + deviceName = initialDeviceName, + deviceId = deviceId + ) + ) + } + private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI { val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString()) return retrofit.create(AuthAPI::class.java) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt index ea8578ed8c5..86467520837 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt @@ -18,4 +18,6 @@ package org.matrix.android.sdk.internal.auth.data internal interface LoginParams { val type: String + val deviceDisplayName: String? + val deviceId: String? } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt index 5f0a2298cb6..062b2466e55 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt @@ -30,8 +30,8 @@ internal data class PasswordLoginParams( @Json(name = "identifier") val identifier: Map, @Json(name = "password") val password: String, @Json(name = "type") override val type: String, - @Json(name = "initial_device_display_name") val deviceDisplayName: String?, - @Json(name = "device_id") val deviceId: String? + @Json(name = "initial_device_display_name") override val deviceDisplayName: String?, + @Json(name = "device_id") override val deviceId: String? ) : LoginParams { companion object { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt index 0c6fb45e788..22cc185fa75 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt @@ -23,5 +23,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes @JsonClass(generateAdapter = true) internal data class TokenLoginParams( @Json(name = "type") override val type: String = LoginFlowTypes.TOKEN, - @Json(name = "token") val token: String + @Json(name = "token") val token: String, + @Json(name = "initial_device_display_name") override val deviceDisplayName: String?, + @Json(name = "device_id") override val deviceId: String? ) : LoginParams diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt new file mode 100644 index 00000000000..477719f607a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.auth.login + +import dagger.Lazy +import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.internal.auth.AuthAPI +import org.matrix.android.sdk.internal.auth.SessionCreator +import org.matrix.android.sdk.internal.auth.data.TokenLoginParams +import org.matrix.android.sdk.internal.di.Unauthenticated +import org.matrix.android.sdk.internal.network.RetrofitFactory +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.network.httpclient.addSocketFactory +import org.matrix.android.sdk.internal.network.ssl.UnrecognizedCertificateException +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface QrLoginTokenTask : Task { + data class Params( + val homeServerConnectionConfig: HomeServerConnectionConfig, + val loginToken: String, + val deviceName: String?, + val deviceId: String? + ) +} + +internal class DefaultQrLoginTokenTask @Inject constructor( + @Unauthenticated + private val okHttpClient: Lazy, + private val retrofitFactory: RetrofitFactory, + private val sessionCreator: SessionCreator, +) : QrLoginTokenTask { + + override suspend fun execute(params: QrLoginTokenTask.Params): Session { + val client = buildClient(params.homeServerConnectionConfig) + val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString() + + val authAPI = retrofitFactory.create(client, homeServerUrl) + .create(AuthAPI::class.java) + + val loginParams = TokenLoginParams( + token = params.loginToken, + deviceDisplayName = params.deviceName, + deviceId = params.deviceId + ) + + val credentials = try { + executeRequest(null) { + authAPI.login(loginParams) + } + } catch (throwable: Throwable) { + throw when (throwable) { + is UnrecognizedCertificateException -> Failure.UnrecognizedCertificateFailure( + homeServerUrl, + throwable.fingerprint + ) + else -> throwable + } + } + + return sessionCreator.createSession(credentials, params.homeServerConnectionConfig, LoginType.QR) + } + + private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient { + return okHttpClient.get() + .newBuilder() + .addSocketFactory(homeServerConnectionConfig) + .build() + } +} From 098c268af3c348ce8ce7ef088047e907cd1efe83 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:18:31 +0100 Subject: [PATCH 02/93] Changelog --- changelog.d/7358.sdk | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7358.sdk diff --git a/changelog.d/7358.sdk b/changelog.d/7358.sdk new file mode 100644 index 00000000000..3d17076a445 --- /dev/null +++ b/changelog.d/7358.sdk @@ -0,0 +1 @@ +Add support for `m.login.token` auth during QR code based sign in From a71ecee44a5b39d1ac13faa0078e0349d0bbf901 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:19:39 +0100 Subject: [PATCH 03/93] Linting --- .../sdk/internal/auth/DefaultAuthenticationService.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 90dc57b4f0b..7fd730bece4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -406,7 +406,12 @@ internal class DefaultAuthenticationService @Inject constructor( ) } - override suspend fun loginUsingQrLoginToken(homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, initialDeviceName: String, deviceId: String?): Session { + override suspend fun loginUsingQrLoginToken( + homeServerConnectionConfig: HomeServerConnectionConfig, + loginToken: String, + initialDeviceName: String, + deviceId: String?, + ): Session { return loginTokenAuthTask.execute( QrLoginTokenTask.Params( homeServerConnectionConfig = homeServerConnectionConfig, From 0d245657e1fd50596397e4dd48d70c24c8661fba Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:32:49 +0100 Subject: [PATCH 04/93] Retry scanning if not a QR code From 1c70d455fbfda7a301ed01f1f18eef1ddf2aa902 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:33:30 +0100 Subject: [PATCH 05/93] Implementations of MSC3886 and MSC3903 From b192fdb0a89b1aa922440ae3dda3bf288a8b7611 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:34:05 +0100 Subject: [PATCH 06/93] Partial implementation of QR login logic --- .../features/login/qr/QrCodeLoginViewModel.kt | 2 +- .../voicebroadcast/VoiceBroadcastConstants.kt | 20 ------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt 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 f97a59b4328..d0c34b83afc 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 @@ -85,8 +85,8 @@ class QrCodeLoginViewModel @AssistedInject constructor( Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") confirmationCode ?.let { onConnectionEstablished(it) - rendezvous.completeOnNewDevice() } + rendezvous.completeOnNewDevice() } // if (isValidQrCode(action.qrCode)) { // setState { diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt deleted file mode 100644 index d7d74b08e97..00000000000 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt +++ /dev/null @@ -1,20 +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.voicebroadcast - -/** Voice Broadcast State Event. */ -const val STATE_ROOM_VOICE_BROADCAST_INFO = "io.element.voice_broadcast_info" From 6e09d900070319b356a2b10a1769af8da97a2aef Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 12 Oct 2022 14:32:09 +0300 Subject: [PATCH 07/93] Merge branch 'develop' into feature/ons/qr_code_login_ui # Conflicts: # library/ui-strings/src/main/res/values/strings.xml # library/ui-styles/src/main/res/values/stylable_sessions_list_header_view.xml # vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt # vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt # vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt # vector/src/main/java/im/vector/app/features/VectorFeatures.kt # vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt # vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionsListHeaderView.kt # vector/src/main/res/layout/fragment_other_sessions.xml # vector/src/main/res/layout/fragment_settings_devices.xml --- .../voicebroadcast/VoiceBroadcastConstants.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt new file mode 100644 index 00000000000..d7d74b08e97 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt @@ -0,0 +1,20 @@ +/* + * 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.voicebroadcast + +/** Voice Broadcast State Event. */ +const val STATE_ROOM_VOICE_BROADCAST_INFO = "io.element.voice_broadcast_info" From 86090086b1344a8e80f8bd3accb1cbbf26a2eab2 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 12 Oct 2022 13:08:01 +0100 Subject: [PATCH 08/93] Only do completeOnNewDevice if we received a confirmation code --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d0c34b83afc..f97a59b4328 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 @@ -85,8 +85,8 @@ class QrCodeLoginViewModel @AssistedInject constructor( Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") confirmationCode ?.let { onConnectionEstablished(it) + rendezvous.completeOnNewDevice() } - rendezvous.completeOnNewDevice() } // if (isValidQrCode(action.qrCode)) { // setState { From ebb3d201c18efba47ec546d778c2f311f266ff9e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:35:45 +0100 Subject: [PATCH 09/93] Make initialDeviceName optional --- .../org/matrix/android/sdk/api/auth/AuthenticationService.kt | 2 +- .../android/sdk/internal/auth/DefaultAuthenticationService.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 8f2a784d49b..c8065e4524f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -135,7 +135,7 @@ interface AuthenticationService { suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, - initialDeviceName: String, + initialDeviceName: String?, deviceId: String? = null ): Session } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 7fd730bece4..6c3622ed5d0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -409,7 +409,7 @@ internal class DefaultAuthenticationService @Inject constructor( override suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, - initialDeviceName: String, + initialDeviceName: String?, deviceId: String?, ): Session { return loginTokenAuthTask.execute( From 5843c3832b6e654a813dde273c75cf9e68497e63 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:58:19 +0100 Subject: [PATCH 10/93] Use correct var name --- .../android/sdk/internal/auth/DefaultAuthenticationService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 6c3622ed5d0..5b12e3bdc3d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -64,7 +64,7 @@ internal class DefaultAuthenticationService @Inject constructor( private val pendingSessionStore: PendingSessionStore, private val getWellknownTask: GetWellknownTask, private val directLoginTask: DirectLoginTask, - private val loginTokenAuthTask: QrLoginTokenTask + private val qrLoginTokenTask: QrLoginTokenTask ) : AuthenticationService { private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData() @@ -412,7 +412,7 @@ internal class DefaultAuthenticationService @Inject constructor( initialDeviceName: String?, deviceId: String?, ): Session { - return loginTokenAuthTask.execute( + return qrLoginTokenTask.execute( QrLoginTokenTask.Params( homeServerConnectionConfig = homeServerConnectionConfig, loginToken = loginToken, From 579df742579f19fda49913d031759f26ea61c841 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:02:57 +0100 Subject: [PATCH 11/93] Add missing binding --- .../java/org/matrix/android/sdk/internal/auth/AuthModule.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt index 463692e574c..b1f65194f1e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt @@ -29,7 +29,9 @@ import org.matrix.android.sdk.internal.auth.db.AuthRealmModule import org.matrix.android.sdk.internal.auth.db.RealmPendingSessionStore import org.matrix.android.sdk.internal.auth.db.RealmSessionParamsStore import org.matrix.android.sdk.internal.auth.login.DefaultDirectLoginTask +import org.matrix.android.sdk.internal.auth.login.DefaultQrLoginTokenTask import org.matrix.android.sdk.internal.auth.login.DirectLoginTask +import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask import org.matrix.android.sdk.internal.database.RealmKeysUtils import org.matrix.android.sdk.internal.di.AuthDatabase import org.matrix.android.sdk.internal.legacy.DefaultLegacySessionImporter @@ -94,4 +96,7 @@ internal abstract class AuthModule { @Binds abstract fun bindHomeServerHistoryService(service: DefaultHomeServerHistoryService): HomeServerHistoryService + + @Binds + abstract fun bindQrLoginTokenTask(task: DefaultQrLoginTokenTask): QrLoginTokenTask } From b5e81d27d65bb8dc5819250c29035e004c24121f Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:08:50 +0100 Subject: [PATCH 12/93] Set default value for optional params --- .../matrix/android/sdk/internal/auth/data/TokenLoginParams.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt index 22cc185fa75..52045a1d7a8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt @@ -24,6 +24,6 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes internal data class TokenLoginParams( @Json(name = "type") override val type: String = LoginFlowTypes.TOKEN, @Json(name = "token") val token: String, - @Json(name = "initial_device_display_name") override val deviceDisplayName: String?, - @Json(name = "device_id") override val deviceId: String? + @Json(name = "initial_device_display_name") override val deviceDisplayName: String? = null, + @Json(name = "device_id") override val deviceId: String? = null ) : LoginParams From 22b344c43a224a52d45be8087a7ead5678d6b38f Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:11:41 +0100 Subject: [PATCH 13/93] Another default value fix --- .../org/matrix/android/sdk/api/auth/AuthenticationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index c8065e4524f..e490311b916 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -135,7 +135,7 @@ interface AuthenticationService { suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, - initialDeviceName: String?, + initialDeviceName: String? = null, deviceId: String? = null ): Session } From 8dbb1b830ef8c508190b0367501a1ef441c717c6 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:28:47 +0100 Subject: [PATCH 14/93] Map for soft logout --- .../im/vector/app/features/signout/soft/SoftLogoutController.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt index b1a240e9421..a1ed27df1d8 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt @@ -152,6 +152,7 @@ class SoftLogoutController @Inject constructor( LoginType.SSO -> buildLoginSSOForm() LoginType.DIRECT, LoginType.CUSTOM, + LoginType.QR, LoginType.UNSUPPORTED -> buildLoginUnsupportedForm() LoginType.UNKNOWN -> Unit } From 0111b932dea08e98362182165a23d717bea68592 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:08:45 +0100 Subject: [PATCH 15/93] Support for navigation to home screen --- .../im/vector/app/features/login/qr/QrCodeLoginActivity.kt | 7 +++++++ .../vector/app/features/login/qr/QrCodeLoginViewEvents.kt | 1 + 2 files changed, 8 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt index e0323fdc2d8..3c7b0a47293 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt @@ -26,6 +26,7 @@ import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.platform.SimpleFragmentActivity +import im.vector.app.features.home.HomeActivity import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber @@ -75,6 +76,7 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { when (it) { QrCodeLoginViewEvents.NavigateToStatusScreen -> handleNavigateToStatusScreen() QrCodeLoginViewEvents.NavigateToShowQrCodeScreen -> handleNavigateToShowQrCodeScreen() + QrCodeLoginViewEvents.NavigateToHomeScreen -> handleNavigateToHomeScreen() } } } @@ -95,6 +97,11 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { ) } + private fun handleNavigateToHomeScreen() { + val intent = HomeActivity.newIntent(this, firstStartMainActivity = false, existingSession = true) + startActivity(intent) + } + companion object { private const val FRAGMENT_QR_CODE_INSTRUCTIONS_TAG = "FRAGMENT_QR_CODE_INSTRUCTIONS_TAG" diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt index dc258408e7c..0f282fee380 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt @@ -21,4 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents sealed class QrCodeLoginViewEvents : VectorViewEvents { object NavigateToStatusScreen : QrCodeLoginViewEvents() object NavigateToShowQrCodeScreen : QrCodeLoginViewEvents() + object NavigateToHomeScreen : QrCodeLoginViewEvents() } From 1ed082d3cb16943a15664dbb862126942f5539d3 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:15:52 +0100 Subject: [PATCH 16/93] QR login + E2EE set up --- .../sdk/internal/rendezvous/Rendezvous.kt | 97 +++++++++---------- .../features/login/qr/QrCodeLoginViewModel.kt | 73 ++++++-------- 2 files changed, 75 insertions(+), 95 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt index dd7b91582be..2f85a97c558 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt @@ -16,8 +16,11 @@ package org.matrix.android.sdk.internal.rendezvous +import android.net.Uri import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel @@ -56,9 +59,12 @@ internal data class Payload( private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value -data class Rendezvous( +/** + * Implementation of MSC3906 to sign in + E2EE set up using a QR code. + */ +class Rendezvous( val channel: RendezvousChannel, - val theirIntent: RendezvousIntent + val theirIntent: RendezvousIntent, ) { companion object { fun buildChannelFromCode(code: String, onCancelled: (reason: RendezvousFailureReason) -> Unit): Rendezvous { @@ -116,7 +122,7 @@ data class Rendezvous( return checksum } - suspend fun completeOnNewDevice(): Session? { + suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session? { Timber.tag(TAG).i("Waiting for login_token"); val loginToken = receive() @@ -143,59 +149,46 @@ data class Rendezvous( Timber.tag(TAG).i("Got login_token: $login_token for $homeserver"); - // TODO: set view to be state logging in? - - // use token to login -// const login = await sendLoginRequest(homeserver, undefined, "m.login.token", { token: login_token }); -// -// await setLoggedIn(login); -// -// const { deviceId, userId } = login; -// -// const client = MatrixClientPeg.get(); -// - - val newSession: Session? = null - - newSession ?.let { - session -> - val userId = session.myUserId - val crypto = session.cryptoService() - val deviceId = crypto.getMyDevice().deviceId - val deviceKey = crypto.getMyDevice().fingerprint() - send(Payload(PayloadType.Progress, outcome = "success", device_id = deviceId, device_key = deviceKey)) - - // await confirmation of verification - - val verificationResponse = receive() - val verifyingDeviceId = verificationResponse?.verifying_device_id ?: throw RuntimeException("No verifying device id returned") - val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) - if (verifyingDeviceFromServer?.fingerprint() == verificationResponse.verifying_device_key) { - // set other device as verified - Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified"); - crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - - verificationResponse.master_key ?.let { - // set master key as trusted - crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, it) + val hsConfig = HomeServerConnectionConfig(homeServerUri = Uri.parse(homeserver)) + return authenticationService.loginUsingQrLoginToken(hsConfig, login_token) + } - } + suspend fun completeVerificationOnNewDevice(session: Session) { + val userId = session.myUserId + val crypto = session.cryptoService() + val deviceId = crypto.getMyDevice().deviceId + val deviceKey = crypto.getMyDevice().fingerprint() + send(Payload(PayloadType.Progress, outcome = "success", device_id = deviceId, device_key = deviceKey)) + + // await confirmation of verification + + val verificationResponse = receive() + val verifyingDeviceId = verificationResponse?.verifying_device_id ?: throw RuntimeException("No verifying device id returned") + val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) + if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifying_device_key) { + Timber.tag(TAG).w("Verifying device $verifyingDeviceId doesn't match: $verifyingDeviceFromServer") + return; + } - // request secrets from the verifying device - Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") + // set other device as verified + Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified"); + crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - session.sharedSecretStorageService() .let { - it.requestSecret(verifyingDeviceId, MASTER_KEY_SSSS_NAME) - it.requestSecret(verifyingDeviceId, SELF_SIGNING_KEY_SSSS_NAME) - it.requestSecret(verifyingDeviceId, USER_SIGNING_KEY_SSSS_NAME) - it.requestSecret(verifyingDeviceId, KEYBACKUP_SECRET_SSSS_NAME) - } - } else { - Timber.tag(TAG).i("Verifying device $verifyingDeviceId doesn't match: $verifyingDeviceFromServer") - } - } + // TODO: what do we do with the master key? +// verificationResponse.master_key ?.let { +// // set master key as trusted +// crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, it) +// } - return newSession + // request secrets from the verifying device + Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") + + session.sharedSecretStorageService() .let { + it.requestSecret(MASTER_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(SELF_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(USER_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(KEYBACKUP_SECRET_SSSS_NAME, verifyingDeviceId) + } } private suspend fun receive(): Payload? { 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 f97a59b4328..c729152e44e 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 @@ -16,24 +16,31 @@ package im.vector.app.features.login.qr +import android.content.Context import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.home.HomeActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.auth.AuthenticationService 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, + private val applicationContext: Context, + private val authenticationService: AuthenticationService, + private val activeSessionHolder: ActiveSessionHolder, ) : VectorViewModel(initialState) { - val TAG: String = QrCodeLoginViewModel::class.java.simpleName @AssistedFactory @@ -81,44 +88,31 @@ class QrCodeLoginViewModel @AssistedInject constructor( _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() + try { + val confirmationCode = rendezvous.startAfterScanningCode() + Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") + confirmationCode?.let { + onConnectionEstablished(it) + val session = rendezvous.waitForLoginOnNewDevice(authenticationService) + onSigningIn() + session?.let { + activeSessionHolder.setActiveSession(session) + authenticationService.reset() + + session.configureAndStart(applicationContext) + + rendezvous.completeVerificationOnNewDevice(session) + + _viewEvents.post(QrCodeLoginViewEvents.NavigateToHomeScreen) + } + } + } catch (failure: Throwable) { + Timber.tag(TAG).e(failure, "Error occurred during sign in") + onFailed(RendezvousFailureReason.Unknown) } } - // 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( @@ -144,13 +138,6 @@ class QrCodeLoginViewModel @AssistedInject constructor( } } - /** - * TODO. UI test purpose. Fixme accordingly. - */ - private fun isValidQrCode(qrCode: String): Boolean { - return qrCode.startsWith("http") - } - /** * TODO. UI test purpose. Fixme accordingly. */ From 560fda51d163695d1c4878751d9f2f0ab92014b7 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:26:22 +0100 Subject: [PATCH 17/93] Reduce logging --- .../rendezvous/channels/ECDHRendezvousChannel.kt | 16 ++++++++-------- .../transports/SimpleHttpRendezvousTransport.kt | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt index 33837bc4254..cced29aab45 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt @@ -94,7 +94,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu val isInitiator = theirPublicKey == null if (isInitiator) { - Timber.tag(TAG).i("Waiting for other device to send their public key") +// Timber.tag(TAG).i("Waiting for other device to send their public key") val res = this.receiveAsPayload() ?: throw RuntimeException("No reply from other device") if (res.key == null) { @@ -106,7 +106,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) } else { // send our public key unencrypted - Timber.tag(TAG).i("Sending public key") +// Timber.tag(TAG).i("Sending public key") send(ECDHPayload( algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) @@ -121,10 +121,10 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu aesKey = olmSAS!!.generateShortCode(aesInfo, 32) - Timber.tag(TAG).i("Our public key: ${Base64.encodeToString(ourPublicKey, Base64.NO_WRAP)}") - Timber.tag(TAG).i("Their public key: ${Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)}") - Timber.tag(TAG).i("AES info: $aesInfo") - Timber.tag(TAG).i("AES key: ${Base64.encodeToString(aesKey, Base64.NO_WRAP)}") +// Timber.tag(TAG).i("Our public key: ${Base64.encodeToString(ourPublicKey, Base64.NO_WRAP)}") +// Timber.tag(TAG).i("Their public key: ${Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)}") +// Timber.tag(TAG).i("AES info: $aesInfo") +// Timber.tag(TAG).i("AES key: ${Base64.encodeToString(aesKey, Base64.NO_WRAP)}") val rawChecksum = olmSAS!!.generateShortCode(aesInfo, 5) return getDecimalCodeRepresentation(rawChecksum) @@ -180,7 +180,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } private fun encrypt(plainText: ByteArray): ECDHPayload { - Timber.tag(TAG).i("Encrypting: ${plainText.toString(Charsets.UTF_8)}") +// Timber.tag(TAG).d("Encrypting: ${plainText.toString(Charsets.UTF_8)}") val iv = ByteArray(16) SecureRandom().nextBytes(iv) @@ -212,7 +212,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu val plainTextBytes = plainText.toByteArray() - Timber.tag(TAG).i("Decrypted: ${plainTextBytes.toString(Charsets.UTF_8)}") +// Timber.tag(TAG).d("Decrypted: ${plainTextBytes.toString(Charsets.UTF_8)}") return plainTextBytes } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 3e5e1121ea1..cc4346d55ef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -67,7 +67,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo // TODO: properly determine endpoint val uri = if (uri != null) uri!! else "https://rendezvous.lab.element.dev" - Timber.tag(TAG).i("Sending data: ${data.toString(Charsets.UTF_8)} to $uri") +// Timber.tag(TAG).i("Sending data: ${data.toString(Charsets.UTF_8)} to $uri") val httpClient = okhttp3.OkHttpClient.Builder().build() @@ -123,8 +123,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo val response = httpClient.newCall(request.build()).execute() try { - - Timber.tag(TAG).i("Received polling response: ${response.code} from $uri") +// Timber.tag(TAG).d("Received polling response: ${response.code} from $uri") if (response.code == 404) { cancel(RendezvousFailureReason.Unknown) @@ -142,7 +141,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo etag = it } val data = response.body?.bytes() - Timber.tag(TAG).i("Received data: ${data?.toString(Charsets.UTF_8)} from $uri with etag $etag") +// Timber.tag(TAG).d("Received data: ${data?.toString(Charsets.UTF_8)} from $uri with etag $etag") return data } @@ -158,6 +157,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo override suspend fun cancel(reason: RendezvousFailureReason) { var mappedReason = reason + Timber.tag(TAG).i("$expiresAt") if (mappedReason == RendezvousFailureReason.Unknown && expiresAt != null && Date() > expiresAt) { mappedReason = RendezvousFailureReason.Expired From 88238c0f04648a7468c2ee33d86068fa79e4fe5f Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:11:15 +0100 Subject: [PATCH 18/93] Support for login by m.login.token during QR code sign in --- .../sdk/api/auth/AuthenticationService.kt | 13 +++ .../matrix/android/sdk/api/auth/LoginType.kt | 4 +- .../auth/DefaultAuthenticationService.kt | 15 +++- .../sdk/internal/auth/data/LoginParams.kt | 2 + .../internal/auth/data/PasswordLoginParams.kt | 4 +- .../internal/auth/data/TokenLoginParams.kt | 4 +- .../internal/auth/login/QrLoginTokenTask.kt | 88 +++++++++++++++++++ 7 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index d040f9c67be..6bb47dda5bb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -130,4 +130,17 @@ interface AuthenticationService { * Return true if qr code login is supported by the server, false otherwise. */ suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean + * Authenticate using m.login.token method during sign in with QR code. + * @param homeServerConnectionConfig the information about the homeserver and other configuration + * @param loginToken the m.login.token + * @param initialDeviceName the initial device name + * @param deviceId the device id, optional. If not provided or null, the server will generate one. + */ + + suspend fun loginUsingQrLoginToken( + homeServerConnectionConfig: HomeServerConnectionConfig, + loginToken: String, + initialDeviceName: String, + deviceId: String? = null + ): Session } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt index 627a8256799..991b7b654d5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt @@ -22,7 +22,8 @@ enum class LoginType { UNSUPPORTED, CUSTOM, DIRECT, - UNKNOWN; + UNKNOWN, + QR; companion object { @@ -32,6 +33,7 @@ enum class LoginType { UNSUPPORTED.name -> UNSUPPORTED CUSTOM.name -> CUSTOM DIRECT.name -> DIRECT + QR.name -> QR else -> UNKNOWN } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 4f45f807df3..5b6f0686c4e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -40,6 +40,7 @@ import org.matrix.android.sdk.internal.auth.data.WebClientConfig import org.matrix.android.sdk.internal.auth.db.PendingSessionData import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard import org.matrix.android.sdk.internal.auth.login.DirectLoginTask +import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard import org.matrix.android.sdk.internal.auth.version.Versions import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices @@ -64,7 +65,8 @@ internal class DefaultAuthenticationService @Inject constructor( private val sessionCreator: SessionCreator, private val pendingSessionStore: PendingSessionStore, private val getWellknownTask: GetWellknownTask, - private val directLoginTask: DirectLoginTask + private val directLoginTask: DirectLoginTask, + private val loginTokenAuthTask: QrLoginTokenTask ) : AuthenticationService { private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData() @@ -420,6 +422,17 @@ internal class DefaultAuthenticationService @Inject constructor( } } + override suspend fun loginUsingQrLoginToken(homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, initialDeviceName: String, deviceId: String?): Session { + return loginTokenAuthTask.execute( + QrLoginTokenTask.Params( + homeServerConnectionConfig = homeServerConnectionConfig, + loginToken = loginToken, + deviceName = initialDeviceName, + deviceId = deviceId + ) + ) + } + private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI { val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString()) return retrofit.create(AuthAPI::class.java) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt index ea8578ed8c5..86467520837 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginParams.kt @@ -18,4 +18,6 @@ package org.matrix.android.sdk.internal.auth.data internal interface LoginParams { val type: String + val deviceDisplayName: String? + val deviceId: String? } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt index 5f0a2298cb6..062b2466e55 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt @@ -30,8 +30,8 @@ internal data class PasswordLoginParams( @Json(name = "identifier") val identifier: Map, @Json(name = "password") val password: String, @Json(name = "type") override val type: String, - @Json(name = "initial_device_display_name") val deviceDisplayName: String?, - @Json(name = "device_id") val deviceId: String? + @Json(name = "initial_device_display_name") override val deviceDisplayName: String?, + @Json(name = "device_id") override val deviceId: String? ) : LoginParams { companion object { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt index 0c6fb45e788..22cc185fa75 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt @@ -23,5 +23,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes @JsonClass(generateAdapter = true) internal data class TokenLoginParams( @Json(name = "type") override val type: String = LoginFlowTypes.TOKEN, - @Json(name = "token") val token: String + @Json(name = "token") val token: String, + @Json(name = "initial_device_display_name") override val deviceDisplayName: String?, + @Json(name = "device_id") override val deviceId: String? ) : LoginParams diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt new file mode 100644 index 00000000000..477719f607a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/QrLoginTokenTask.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.auth.login + +import dagger.Lazy +import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.internal.auth.AuthAPI +import org.matrix.android.sdk.internal.auth.SessionCreator +import org.matrix.android.sdk.internal.auth.data.TokenLoginParams +import org.matrix.android.sdk.internal.di.Unauthenticated +import org.matrix.android.sdk.internal.network.RetrofitFactory +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.network.httpclient.addSocketFactory +import org.matrix.android.sdk.internal.network.ssl.UnrecognizedCertificateException +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface QrLoginTokenTask : Task { + data class Params( + val homeServerConnectionConfig: HomeServerConnectionConfig, + val loginToken: String, + val deviceName: String?, + val deviceId: String? + ) +} + +internal class DefaultQrLoginTokenTask @Inject constructor( + @Unauthenticated + private val okHttpClient: Lazy, + private val retrofitFactory: RetrofitFactory, + private val sessionCreator: SessionCreator, +) : QrLoginTokenTask { + + override suspend fun execute(params: QrLoginTokenTask.Params): Session { + val client = buildClient(params.homeServerConnectionConfig) + val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString() + + val authAPI = retrofitFactory.create(client, homeServerUrl) + .create(AuthAPI::class.java) + + val loginParams = TokenLoginParams( + token = params.loginToken, + deviceDisplayName = params.deviceName, + deviceId = params.deviceId + ) + + val credentials = try { + executeRequest(null) { + authAPI.login(loginParams) + } + } catch (throwable: Throwable) { + throw when (throwable) { + is UnrecognizedCertificateException -> Failure.UnrecognizedCertificateFailure( + homeServerUrl, + throwable.fingerprint + ) + else -> throwable + } + } + + return sessionCreator.createSession(credentials, params.homeServerConnectionConfig, LoginType.QR) + } + + private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient { + return okHttpClient.get() + .newBuilder() + .addSocketFactory(homeServerConnectionConfig) + .build() + } +} From 282825db7952fd6516a3b1531fb709ca6831cd78 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:18:31 +0100 Subject: [PATCH 19/93] Changelog --- changelog.d/7358.sdk | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7358.sdk diff --git a/changelog.d/7358.sdk b/changelog.d/7358.sdk new file mode 100644 index 00000000000..3d17076a445 --- /dev/null +++ b/changelog.d/7358.sdk @@ -0,0 +1 @@ +Add support for `m.login.token` auth during QR code based sign in From d0898a2b89e7ff0c2858fece93656a2b0427a19e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:19:39 +0100 Subject: [PATCH 20/93] Linting --- .../sdk/internal/auth/DefaultAuthenticationService.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 5b6f0686c4e..773f2118b1e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -422,7 +422,12 @@ internal class DefaultAuthenticationService @Inject constructor( } } - override suspend fun loginUsingQrLoginToken(homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, initialDeviceName: String, deviceId: String?): Session { + override suspend fun loginUsingQrLoginToken( + homeServerConnectionConfig: HomeServerConnectionConfig, + loginToken: String, + initialDeviceName: String, + deviceId: String?, + ): Session { return loginTokenAuthTask.execute( QrLoginTokenTask.Params( homeServerConnectionConfig = homeServerConnectionConfig, From 3b3e11e5681874a7540e0885ee44da1885d29e30 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:32:49 +0100 Subject: [PATCH 21/93] Retry scanning if not a QR code From de611ca81a1c9f16ded4b6b8d3d48b12b7edd68e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:33:30 +0100 Subject: [PATCH 22/93] Implementations of MSC3886 and MSC3903 From bfab07d716bddf91b2e7cab707dd2fe8e5ffb982 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 11 Oct 2022 23:34:05 +0100 Subject: [PATCH 23/93] Partial implementation of QR login logic --- .../features/login/qr/QrCodeLoginViewModel.kt | 27 ++++++++++++++----- .../voicebroadcast/VoiceBroadcastConstants.kt | 20 -------------- 2 files changed, 21 insertions(+), 26 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt 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 da3348653c9..05344f0a677 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 @@ -59,13 +59,28 @@ class QrCodeLoginViewModel @AssistedInject constructor( } private fun handleOnQrCodeScanned(action: QrCodeLoginAction.OnQrCodeScanned) { - if (isValidQrCode(action.qrCode)) { - setState { - copy( - connectionStatus = QrCodeLoginConnectionStatus.ConnectingToDevice - ) + Timber.tag(TAG).d("Scanned code: ${action.qrCode}") + + val rendezvous = Rendezvous.buildChannelFromCode(action.qrCode) { reason -> + Timber.tag(TAG).d("Rendezvous cancelled: $reason") + onFailed(reason) + } + + setState { + copy( + 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) } - _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) + rendezvous.completeOnNewDevice() } // TODO. UI test purpose. Fixme remove! diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt deleted file mode 100644 index d7d74b08e97..00000000000 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt +++ /dev/null @@ -1,20 +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.voicebroadcast - -/** Voice Broadcast State Event. */ -const val STATE_ROOM_VOICE_BROADCAST_INFO = "io.element.voice_broadcast_info" From ef574bd82fbc5e33f0d4da51958158de9773a45c Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 12 Oct 2022 14:32:09 +0300 Subject: [PATCH 24/93] Merge branch 'develop' into feature/ons/qr_code_login_ui # Conflicts: # library/ui-strings/src/main/res/values/strings.xml # library/ui-styles/src/main/res/values/stylable_sessions_list_header_view.xml # vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt # vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt # vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt # vector/src/main/java/im/vector/app/features/VectorFeatures.kt # vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt # vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionsListHeaderView.kt # vector/src/main/res/layout/fragment_other_sessions.xml # vector/src/main/res/layout/fragment_settings_devices.xml --- .../voicebroadcast/VoiceBroadcastConstants.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt new file mode 100644 index 00000000000..d7d74b08e97 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastConstants.kt @@ -0,0 +1,20 @@ +/* + * 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.voicebroadcast + +/** Voice Broadcast State Event. */ +const val STATE_ROOM_VOICE_BROADCAST_INFO = "io.element.voice_broadcast_info" From b03240330d9905fc422a2fd3d166376c5d80f3a7 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 12 Oct 2022 13:08:01 +0100 Subject: [PATCH 25/93] Only do completeOnNewDevice if we received a confirmation code --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 05344f0a677..877d32a11dd 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 @@ -79,8 +79,8 @@ class QrCodeLoginViewModel @AssistedInject constructor( Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") confirmationCode ?.let { onConnectionEstablished(it) + rendezvous.completeOnNewDevice() } - rendezvous.completeOnNewDevice() } // TODO. UI test purpose. Fixme remove! From 1e60f3c25b457e2cb40e5c8770e673c25f2fa941 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:35:45 +0100 Subject: [PATCH 26/93] Make initialDeviceName optional --- .../org/matrix/android/sdk/api/auth/AuthenticationService.kt | 2 +- .../android/sdk/internal/auth/DefaultAuthenticationService.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 6bb47dda5bb..9fde6d93264 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -140,7 +140,7 @@ interface AuthenticationService { suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, - initialDeviceName: String, + initialDeviceName: String?, deviceId: String? = null ): Session } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 773f2118b1e..7aeeacd10b1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -425,7 +425,7 @@ internal class DefaultAuthenticationService @Inject constructor( override suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, - initialDeviceName: String, + initialDeviceName: String?, deviceId: String?, ): Session { return loginTokenAuthTask.execute( From e2f3dde5c1579c88521ae7b2e16b725f7e7c48e5 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 15:58:19 +0100 Subject: [PATCH 27/93] Use correct var name --- .../android/sdk/internal/auth/DefaultAuthenticationService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 7aeeacd10b1..5449c0a735f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -66,7 +66,7 @@ internal class DefaultAuthenticationService @Inject constructor( private val pendingSessionStore: PendingSessionStore, private val getWellknownTask: GetWellknownTask, private val directLoginTask: DirectLoginTask, - private val loginTokenAuthTask: QrLoginTokenTask + private val qrLoginTokenTask: QrLoginTokenTask ) : AuthenticationService { private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData() @@ -428,7 +428,7 @@ internal class DefaultAuthenticationService @Inject constructor( initialDeviceName: String?, deviceId: String?, ): Session { - return loginTokenAuthTask.execute( + return qrLoginTokenTask.execute( QrLoginTokenTask.Params( homeServerConnectionConfig = homeServerConnectionConfig, loginToken = loginToken, From ca7a6efadee7430c4ac431a7cb89733db7486cc6 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:02:57 +0100 Subject: [PATCH 28/93] Add missing binding --- .../java/org/matrix/android/sdk/internal/auth/AuthModule.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt index 463692e574c..b1f65194f1e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt @@ -29,7 +29,9 @@ import org.matrix.android.sdk.internal.auth.db.AuthRealmModule import org.matrix.android.sdk.internal.auth.db.RealmPendingSessionStore import org.matrix.android.sdk.internal.auth.db.RealmSessionParamsStore import org.matrix.android.sdk.internal.auth.login.DefaultDirectLoginTask +import org.matrix.android.sdk.internal.auth.login.DefaultQrLoginTokenTask import org.matrix.android.sdk.internal.auth.login.DirectLoginTask +import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask import org.matrix.android.sdk.internal.database.RealmKeysUtils import org.matrix.android.sdk.internal.di.AuthDatabase import org.matrix.android.sdk.internal.legacy.DefaultLegacySessionImporter @@ -94,4 +96,7 @@ internal abstract class AuthModule { @Binds abstract fun bindHomeServerHistoryService(service: DefaultHomeServerHistoryService): HomeServerHistoryService + + @Binds + abstract fun bindQrLoginTokenTask(task: DefaultQrLoginTokenTask): QrLoginTokenTask } From ac80ae5632c4543b199189b90662ed4c971373eb Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:08:50 +0100 Subject: [PATCH 29/93] Set default value for optional params --- .../matrix/android/sdk/internal/auth/data/TokenLoginParams.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt index 22cc185fa75..52045a1d7a8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/TokenLoginParams.kt @@ -24,6 +24,6 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes internal data class TokenLoginParams( @Json(name = "type") override val type: String = LoginFlowTypes.TOKEN, @Json(name = "token") val token: String, - @Json(name = "initial_device_display_name") override val deviceDisplayName: String?, - @Json(name = "device_id") override val deviceId: String? + @Json(name = "initial_device_display_name") override val deviceDisplayName: String? = null, + @Json(name = "device_id") override val deviceId: String? = null ) : LoginParams From bc0843eddf1712983dd4990ac6835dd68fc0bbb5 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:11:41 +0100 Subject: [PATCH 30/93] Another default value fix --- .../org/matrix/android/sdk/api/auth/AuthenticationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 9fde6d93264..1cc53b311c4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -140,7 +140,7 @@ interface AuthenticationService { suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, - initialDeviceName: String?, + initialDeviceName: String? = null, deviceId: String? = null ): Session } From 991eeb1de6c29515aa43d4c551b8cf12580f5f53 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 16:28:47 +0100 Subject: [PATCH 31/93] Map for soft logout --- .../im/vector/app/features/signout/soft/SoftLogoutController.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt index b1a240e9421..a1ed27df1d8 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt @@ -152,6 +152,7 @@ class SoftLogoutController @Inject constructor( LoginType.SSO -> buildLoginSSOForm() LoginType.DIRECT, LoginType.CUSTOM, + LoginType.QR, LoginType.UNSUPPORTED -> buildLoginUnsupportedForm() LoginType.UNKNOWN -> Unit } From 9a72d6529b0a76bc83c28ed217f79c8a69c6acc4 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:08:45 +0100 Subject: [PATCH 32/93] Support for navigation to home screen --- .../im/vector/app/features/login/qr/QrCodeLoginActivity.kt | 7 +++++++ .../vector/app/features/login/qr/QrCodeLoginViewEvents.kt | 1 + 2 files changed, 8 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt index 042f8852319..fac31ce4e38 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt @@ -25,6 +25,7 @@ import com.airbnb.mvrx.viewModel import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.SimpleFragmentActivity +import im.vector.app.features.home.HomeActivity import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber @@ -74,6 +75,7 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { when (it) { QrCodeLoginViewEvents.NavigateToStatusScreen -> handleNavigateToStatusScreen() QrCodeLoginViewEvents.NavigateToShowQrCodeScreen -> handleNavigateToShowQrCodeScreen() + QrCodeLoginViewEvents.NavigateToHomeScreen -> handleNavigateToHomeScreen() } } } @@ -94,6 +96,11 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { ) } + private fun handleNavigateToHomeScreen() { + val intent = HomeActivity.newIntent(this, firstStartMainActivity = false, existingSession = true) + startActivity(intent) + } + companion object { private const val FRAGMENT_QR_CODE_INSTRUCTIONS_TAG = "FRAGMENT_QR_CODE_INSTRUCTIONS_TAG" diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt index dc258408e7c..0f282fee380 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt @@ -21,4 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents sealed class QrCodeLoginViewEvents : VectorViewEvents { object NavigateToStatusScreen : QrCodeLoginViewEvents() object NavigateToShowQrCodeScreen : QrCodeLoginViewEvents() + object NavigateToHomeScreen : QrCodeLoginViewEvents() } From dd47297dfd4bc774c509d06ccc1316fbb70e6514 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:15:52 +0100 Subject: [PATCH 33/93] QR login + E2EE set up --- .../sdk/internal/rendezvous/Rendezvous.kt | 210 ++++++++++++++++++ .../features/login/qr/QrCodeLoginViewModel.kt | 62 +++--- 2 files changed, 246 insertions(+), 26 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt new file mode 100644 index 00000000000..2f85a97c558 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt @@ -0,0 +1,210 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous + +import android.net.Uri +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.logger.LoggerTag +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel +import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME +import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME +import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME +import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME +import org.matrix.android.sdk.api.util.MatrixJsonParser +import org.matrix.android.sdk.internal.rendezvous.channels.ECDHRendezvousChannel +import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.internal.rendezvous.transports.SimpleHttpRendezvousTransport +import timber.log.Timber + +internal enum class PayloadType(val value: String) { + @Json(name = "m.login.start") Start("m.login.start"), + @Json(name = "m.login.finish") Finish("m.login.finish"), + @Json(name = "m.login.progress") Progress("m.login.progress") +} + +@JsonClass(generateAdapter = true) +internal data class Payload( + @Json val type: PayloadType, + @Json val intent: RendezvousIntent? = null, + @Json val outcome: String? = null, + @Json val protocols: List? = null, + @Json val protocol: String? = null, + @Json val homeserver: String? = null, + @Json val login_token: String? = null, + @Json val device_id: String? = null, + @Json val device_key: String? = null, + @Json val verifying_device_id: String? = null, + @Json val verifying_device_key: String? = null, + @Json val master_key: String? = null +) + +private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value + +/** + * Implementation of MSC3906 to sign in + E2EE set up using a QR code. + */ +class Rendezvous( + val channel: RendezvousChannel, + val theirIntent: RendezvousIntent, +) { + companion object { + fun buildChannelFromCode(code: String, onCancelled: (reason: RendezvousFailureReason) -> Unit): Rendezvous { + val parsed = MatrixJsonParser.getMoshi().adapter(ECDHRendezvousCode::class.java).fromJson(code) ?: throw RuntimeException("Invalid code") + + val transport = SimpleHttpRendezvousTransport(onCancelled, parsed.rendezvous.transport.uri) + + return Rendezvous( + ECDHRendezvousChannel(transport, parsed.rendezvous.key), + parsed.intent + ) + } + } + + private val adapter = MatrixJsonParser.getMoshi().adapter(Payload::class.java) + // not yet implemented: RendezvousIntent.RECIPROCATE_LOGIN_ON_EXISTING_DEVICE + val ourIntent: RendezvousIntent = RendezvousIntent.LOGIN_ON_NEW_DEVICE + + private suspend fun areIntentsIncompatible(): Boolean { + val incompatible = theirIntent == ourIntent + + Timber.tag(TAG).d("ourIntent: $ourIntent, theirIntent: $theirIntent, incompatible: $incompatible") + + if (incompatible) { + send(Payload(PayloadType.Finish, intent = ourIntent)) + val reason = if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) RendezvousFailureReason.OtherDeviceNotSignedIn else RendezvousFailureReason.OtherDeviceAlreadySignedIn + channel.cancel(reason) + } + + return incompatible + } + + suspend fun startAfterScanningCode(): String? { + val checksum = channel.connect(); + + Timber.tag(TAG).i("Connected to secure channel with checksum: $checksum") + + if (areIntentsIncompatible()) { + return null + } + + // get protocols + Timber.tag(TAG).i("Waiting for protocols"); + val protocolsResponse = receive() + + if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains("login_token")) { + send(Payload(PayloadType.Finish, outcome = "unsupported")) + Timber.tag(TAG).i("No supported protocol") + cancel(RendezvousFailureReason.Unknown) + return null + } + + send(Payload(PayloadType.Progress, protocol = "login_token")) + + return checksum + } + + suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session? { + Timber.tag(TAG).i("Waiting for login_token"); + + val loginToken = receive() + + if (loginToken?.type == PayloadType.Finish) { + when (loginToken.outcome) { + "declined" -> { + Timber.tag(TAG).i("Login declined by other device") + channel.cancel(RendezvousFailureReason.UserDeclined) + return null + } + "unsupported" -> { + Timber.tag(TAG).i("Not supported") + channel.cancel(RendezvousFailureReason.HomeserverLacksSupport) + return null + } + } + channel.cancel(RendezvousFailureReason.Unknown) + return null + } + + val homeserver = loginToken?.homeserver ?: throw RuntimeException("No homeserver returned") + val login_token = loginToken.login_token ?: throw RuntimeException("No login token returned") + + Timber.tag(TAG).i("Got login_token: $login_token for $homeserver"); + + val hsConfig = HomeServerConnectionConfig(homeServerUri = Uri.parse(homeserver)) + return authenticationService.loginUsingQrLoginToken(hsConfig, login_token) + } + + suspend fun completeVerificationOnNewDevice(session: Session) { + val userId = session.myUserId + val crypto = session.cryptoService() + val deviceId = crypto.getMyDevice().deviceId + val deviceKey = crypto.getMyDevice().fingerprint() + send(Payload(PayloadType.Progress, outcome = "success", device_id = deviceId, device_key = deviceKey)) + + // await confirmation of verification + + val verificationResponse = receive() + val verifyingDeviceId = verificationResponse?.verifying_device_id ?: throw RuntimeException("No verifying device id returned") + val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) + if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifying_device_key) { + Timber.tag(TAG).w("Verifying device $verifyingDeviceId doesn't match: $verifyingDeviceFromServer") + return; + } + + // set other device as verified + Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified"); + crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) + + // TODO: what do we do with the master key? +// verificationResponse.master_key ?.let { +// // set master key as trusted +// crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, it) +// } + + // request secrets from the verifying device + Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") + + session.sharedSecretStorageService() .let { + it.requestSecret(MASTER_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(SELF_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(USER_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(KEYBACKUP_SECRET_SSSS_NAME, verifyingDeviceId) + } + } + + private suspend fun receive(): Payload? { + val data = channel.receive()?: return null + return adapter.fromJson(data.toString(Charsets.UTF_8)) + } + + private suspend fun send(payload: Payload) { + channel.send(adapter.toJson(payload).toByteArray(Charsets.UTF_8)); + } + + suspend fun cancel(reason: RendezvousFailureReason) { + channel.cancel(reason) + } + + suspend fun close() { + channel.close() + } +} 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 877d32a11dd..d9c30690a79 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 @@ -16,19 +16,32 @@ package im.vector.app.features.login.qr +import android.content.Context import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.platform.VectorViewModel -import kotlinx.coroutines.delay +import im.vector.app.features.home.HomeActivity +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.auth.AuthenticationService +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, + private val applicationContext: Context, + private val authenticationService: AuthenticationService, + private val activeSessionHolder: ActiveSessionHolder, ) : VectorViewModel(initialState) { + val TAG: String = QrCodeLoginViewModel::class.java.simpleName @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { @@ -75,28 +88,32 @@ class QrCodeLoginViewModel @AssistedInject constructor( _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() + try { + val confirmationCode = rendezvous.startAfterScanningCode() + Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") + confirmationCode?.let { + onConnectionEstablished(it) + val session = rendezvous.waitForLoginOnNewDevice(authenticationService) + onSigningIn() + session?.let { + activeSessionHolder.setActiveSession(session) + authenticationService.reset() + + session.configureAndStart(applicationContext) + + rendezvous.completeVerificationOnNewDevice(session) + + _viewEvents.post(QrCodeLoginViewEvents.NavigateToHomeScreen) + } + } + } catch (failure: Throwable) { + Timber.tag(TAG).e(failure, "Error occurred during sign in") + onFailed(RendezvousFailureReason.Unknown) } } - - // 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) { + private fun onFailed(reason: RendezvousFailureReason) { setState { copy( connectionStatus = QrCodeLoginConnectionStatus.Failed(errorType, canTryAgain) @@ -121,13 +138,6 @@ class QrCodeLoginViewModel @AssistedInject constructor( } } - /** - * TODO. UI test purpose. Fixme accordingly. - */ - private fun isValidQrCode(qrCode: String): Boolean { - return qrCode.startsWith("http") - } - /** * TODO. UI test purpose. Fixme accordingly. */ From 7bc0bd3b57d1db71742051fe65d6b1003ad2037e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:26:22 +0100 Subject: [PATCH 34/93] Reduce logging --- .../channels/ECDHRendezvousChannel.kt | 218 ++++++++++++++++++ .../SimpleHttpRendezvousTransport.kt | 185 +++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt new file mode 100644 index 00000000000..cced29aab45 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt @@ -0,0 +1,218 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.channels + +import android.util.Base64 +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import okhttp3.MediaType.Companion.toMediaType +import org.matrix.android.sdk.api.logger.LoggerTag +import org.matrix.android.sdk.api.util.MatrixJsonParser +import org.matrix.android.sdk.internal.extensions.toUnsignedInt +import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.internal.rendezvous.RendezvousChannel +import org.matrix.android.sdk.internal.rendezvous.RendezvousTransport +import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvous +import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousError +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.internal.rendezvous.model.SecureRendezvousChannelAlgorithm +import org.matrix.android.sdk.internal.rendezvous.transports.SimpleHttpRendezvousTransportDetails +import org.matrix.olm.OlmSAS +import timber.log.Timber +import java.security.SecureRandom +import java.util.LinkedList +import javax.crypto.Cipher +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec + +@JsonClass(generateAdapter = true) +data class ECDHPayload( + @Json val algorithm: SecureRendezvousChannelAlgorithm? = null, + @Json val key: String? = null, + @Json val ciphertext: String? = null, + @Json val iv: String? = null +) + +private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value + +fun getDecimalCodeRepresentation(byteArray: ByteArray): String { + val b0 = byteArray[0].toUnsignedInt() // need unsigned byte + val b1 = byteArray[1].toUnsignedInt() // need unsigned byte + val b2 = byteArray[2].toUnsignedInt() // need unsigned byte + val b3 = byteArray[3].toUnsignedInt() // need unsigned byte + val b4 = byteArray[4].toUnsignedInt() // need unsigned byte + // (B0 << 5 | B1 >> 3) + 1000 + val first = (b0.shl(5) or b1.shr(3)) + 1000 + // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 + val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 + // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 + val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 + return "$first-$second-$third" +} + +const val ALGORITHM_SPEC = "AES/GCM/NoPadding" +const val KEY_SPEC = "AES" + +/** + * Implements X25519 ECDH key agreement and AES-256-GCM encryption channel as per MSC3903: + * https://github.com/matrix-org/matrix-spec-proposals/pull/3903 + */ +class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPublicKeyBase64: String?): RendezvousChannel { + private var olmSAS: OlmSAS? + private val ourPublicKey: ByteArray + private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) + private var theirPublicKey: ByteArray? = null + private var aesKey: ByteArray? = null + + init { + theirPublicKeyBase64 ?.let { + theirPublicKey = Base64.decode(it, Base64.NO_WRAP) + } + olmSAS = OlmSAS() + ourPublicKey = Base64.decode(olmSAS!!.publicKey, Base64.NO_WRAP) + } + + override suspend fun connect(): String { + if (olmSAS == null) { + throw RuntimeException("Channel closed") + } + val isInitiator = theirPublicKey == null + + if (isInitiator) { +// Timber.tag(TAG).i("Waiting for other device to send their public key") + val res = this.receiveAsPayload() ?: throw RuntimeException("No reply from other device") + + if (res.key == null) { + throw RendezvousError( + "Unsupported algorithm: ${res.algorithm}", + RendezvousFailureReason.UnsupportedAlgorithm, + ) + } + theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) + } else { + // send our public key unencrypted +// Timber.tag(TAG).i("Sending public key") + send(ECDHPayload( + algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, + key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) + )) + } + + olmSAS!!.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) + + val initiatorKey = Base64.encodeToString(if (isInitiator) ourPublicKey else theirPublicKey, Base64.NO_WRAP) + val recipientKey = Base64.encodeToString(if (isInitiator) theirPublicKey else ourPublicKey, Base64.NO_WRAP) + val aesInfo = "${SecureRendezvousChannelAlgorithm.ECDH_V1.value}|$initiatorKey|$recipientKey" + + aesKey = olmSAS!!.generateShortCode(aesInfo, 32) + +// Timber.tag(TAG).i("Our public key: ${Base64.encodeToString(ourPublicKey, Base64.NO_WRAP)}") +// Timber.tag(TAG).i("Their public key: ${Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)}") +// Timber.tag(TAG).i("AES info: $aesInfo") +// Timber.tag(TAG).i("AES key: ${Base64.encodeToString(aesKey, Base64.NO_WRAP)}") + + val rawChecksum = olmSAS!!.generateShortCode(aesInfo, 5) + return getDecimalCodeRepresentation(rawChecksum) + } + + private suspend fun send(payload: ECDHPayload) { + transport.send("application/json".toMediaType(), ecdhAdapter.toJson(payload).toByteArray(Charsets.UTF_8)) + } + + override suspend fun send(data: ByteArray) { + if (aesKey == null) { + throw RuntimeException("Shared secret not established") + } + send(encrypt(data)) + } + + private suspend fun receiveAsPayload(): ECDHPayload? { + transport.receive()?.toString(Charsets.UTF_8) ?.let { + return ecdhAdapter.fromJson(it) + } ?: return null + } + + override suspend fun receive(): ByteArray? { + if (aesKey == null) { + throw RuntimeException("Shared secret not established") + } + val payload = receiveAsPayload() ?: return null + return decrypt(payload) + } + + override suspend fun generateCode(intent: RendezvousIntent): ECDHRendezvousCode { + return ECDHRendezvousCode( + intent, + rendezvous = ECDHRendezvous( + transport.details() as SimpleHttpRendezvousTransportDetails, + SecureRendezvousChannelAlgorithm.ECDH_V1, + key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) + ) + ) + } + + override suspend fun cancel(reason: RendezvousFailureReason) { + try { + transport.cancel(reason) + } finally { + close() + } + } + + override suspend fun close() { + olmSAS?.releaseSas() + olmSAS = null + } + + private fun encrypt(plainText: ByteArray): ECDHPayload { +// Timber.tag(TAG).d("Encrypting: ${plainText.toString(Charsets.UTF_8)}") + val iv = ByteArray(16) + SecureRandom().nextBytes(iv) + + val cipherText = LinkedList() + + val encryptCipher = Cipher.getInstance(ALGORITHM_SPEC) + val secretKeySpec = SecretKeySpec(aesKey, KEY_SPEC) + val ivParameterSpec = IvParameterSpec(iv) + encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) + cipherText.addAll(encryptCipher.update(plainText).toList()) + cipherText.addAll(encryptCipher.doFinal().toList()) + + return ECDHPayload( + ciphertext = Base64.encodeToString(cipherText.toByteArray(), Base64.NO_WRAP), + iv = Base64.encodeToString(iv, Base64.NO_WRAP) + ) + } + + private fun decrypt(payload: ECDHPayload): ByteArray { + val iv = Base64.decode(payload.iv, Base64.NO_WRAP) + val encryptCipher = Cipher.getInstance(ALGORITHM_SPEC) + val secretKeySpec = SecretKeySpec(aesKey, KEY_SPEC) + val ivParameterSpec = IvParameterSpec(iv) + encryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) + + val plainText = LinkedList() + plainText.addAll(encryptCipher.update(Base64.decode(payload.ciphertext, Base64.NO_WRAP)).toList()) + plainText.addAll(encryptCipher.doFinal().toList()) + + val plainTextBytes = plainText.toByteArray() + +// Timber.tag(TAG).d("Decrypted: ${plainTextBytes.toString(Charsets.UTF_8)}") + return plainTextBytes + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt new file mode 100644 index 00000000000..cc4346d55ef --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -0,0 +1,185 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.transports + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import kotlinx.coroutines.delay +import okhttp3.MediaType +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import org.matrix.android.sdk.api.logger.LoggerTag +import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.internal.rendezvous.RendezvousTransport +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousTransportDetails +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousTransportType +import timber.log.Timber +import java.text.SimpleDateFormat +import java.util.Date + +private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName, LoggerTag.RENDEZVOUS).value + +@JsonClass(generateAdapter = true) +data class SimpleHttpRendezvousTransportDetails( + @Json val uri: String +): RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) + +/** + * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 + */ +class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: RendezvousFailureReason) -> Unit)?, rendezvousUri: String?) : RendezvousTransport { + override var ready = false + private var cancelled = false + private var uri: String? + private var etag: String? = null + private var expiresAt: Date? = null + + init { + uri = rendezvousUri + } + + override suspend fun details(): RendezvousTransportDetails { + val uri = uri ?: throw IllegalStateException("Rendezvous not set up") + + return SimpleHttpRendezvousTransportDetails(uri) + } + + override suspend fun send(contentType: MediaType, data: ByteArray) { + if (cancelled) { + return + } + + val method = if (uri != null) "PUT" else "POST" + // TODO: properly determine endpoint + val uri = if (uri != null) uri!! else "https://rendezvous.lab.element.dev" + +// Timber.tag(TAG).i("Sending data: ${data.toString(Charsets.UTF_8)} to $uri") + + val httpClient = okhttp3.OkHttpClient.Builder().build() + + val request = Request.Builder() + .url(uri) + .method(method, data.toRequestBody()) + .header("content-type", contentType.toString()) + + etag ?.let { + request.header("if-match", it) + } + + val response = httpClient.newCall(request.build()).execute() + + if (response.code == 404) { + cancel(RendezvousFailureReason.Unknown) + } + etag = response.header("etag") + + Timber.tag(TAG).i("Sent data to $uri new etag $etag") + + if (method == "POST") { + val location = response.header("location") ?: throw RuntimeException("No rendezvous URI found in response") + + response.header("expires") ?.let { + val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz") + expiresAt = format.parse(it) + } + + // resolve location header which could be relative or absolute + this.uri = response.request.url.toUri().resolve(location).toString() + ready = true + } + } + + override suspend fun receive(): ByteArray? { + val uri = uri ?: throw IllegalStateException("Rendezvous not set up") + var done = false + val httpClient = okhttp3.OkHttpClient.Builder().build() + while (!done) { + if (cancelled) { + return null + } + Timber.tag(TAG).i("Polling: $uri after etag $etag") + val request = Request.Builder() + .url(uri) + .get() + + etag ?.let { + request.header("if-none-match", it) + } + + val response = httpClient.newCall(request.build()).execute() + + try { +// Timber.tag(TAG).d("Received polling response: ${response.code} from $uri") + + if (response.code == 404) { + cancel(RendezvousFailureReason.Unknown) + return null + } + + // rely on server expiring the channel rather than checking ourselves + + if (response.header("content-type") != "application/json") { + response.header("etag")?.let { + etag = it + } + } else if (response.code == 200) { + response.header("etag")?.let { + etag = it + } + val data = response.body?.bytes() +// Timber.tag(TAG).d("Received data: ${data?.toString(Charsets.UTF_8)} from $uri with etag $etag") + return data + } + + done = false + delay(1000) + } finally { + response.close() + } + } + + return null + } + + override suspend fun cancel(reason: RendezvousFailureReason) { + var mappedReason = reason + Timber.tag(TAG).i("$expiresAt") + if (mappedReason == RendezvousFailureReason.Unknown && + expiresAt != null && Date() > expiresAt) { + mappedReason = RendezvousFailureReason.Expired + } + + cancelled = true + ready = false + onCancelled ?.let { it(mappedReason) } + + if (mappedReason == RendezvousFailureReason.UserDeclined) { + uri ?.let { + try { + val httpClient = okhttp3.OkHttpClient.Builder().build() + val request = Request.Builder() + .url(it) + .delete() + .build() + httpClient.newCall(request).execute() + } catch (e: Exception) { + Timber.tag(TAG).w(e, "Failed to delete channel") + } + } + } + } +} From 6399032312c743793fc79ec1f7863c95aec0db1a Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 22:23:26 +0100 Subject: [PATCH 35/93] Fix bad merge --- .../org/matrix/android/sdk/api/auth/AuthenticationService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 1cc53b311c4..252c33a8c4c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -130,13 +130,14 @@ interface AuthenticationService { * Return true if qr code login is supported by the server, false otherwise. */ suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean + + /** * Authenticate using m.login.token method during sign in with QR code. * @param homeServerConnectionConfig the information about the homeserver and other configuration * @param loginToken the m.login.token * @param initialDeviceName the initial device name * @param deviceId the device id, optional. If not provided or null, the server will generate one. */ - suspend fun loginUsingQrLoginToken( homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, From 958ee2d3561fb4b871ba83c6cb3be2ce4fbeb943 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 22:32:02 +0100 Subject: [PATCH 36/93] Revert "Revert "Retry scanning if not a QR code"" This reverts commit 9429a4f22aabfbff23ffc223c3b090626be553dc. --- .../app/features/login/qr/QrCodeLoginInstructionsFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt index ae3ba9574b7..17b4ff24095 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt @@ -83,6 +83,7 @@ class QrCodeLoginInstructionsFragment : VectorBaseFragment Date: Thu, 13 Oct 2022 22:37:19 +0100 Subject: [PATCH 37/93] Revert "Revert "Implementations of MSC3886 and MSC3903"" This reverts commit 489dfd73546a78246b1f18faf97e7a36bb4e0241. --- .../android/sdk/api/logger/LoggerTag.kt | 1 + .../internal/rendezvous/RendezvousChannel.kt | 45 +++++++++++++++++++ .../rendezvous/RendezvousFailureReason.kt | 31 +++++++++++++ .../rendezvous/RendezvousTransport.kt | 29 ++++++++++++ .../rendezvous/model/ECDHRendezvous.kt | 34 ++++++++++++++ .../rendezvous/model/EmbeddedRendezvous.kt | 26 +++++++++++ .../rendezvous/model/RendezvousError.kt | 22 +++++++++ .../rendezvous/model/RendezvousIntent.kt | 24 ++++++++++ .../model/RendezvousTransportDetails.kt | 25 +++++++++++ .../model/RendezvousTransportType.kt | 23 ++++++++++ .../model/SecureRendezvousChannelAlgorithm.kt | 23 ++++++++++ 11 files changed, 283 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt index ae65963f37b..22af8cebbda 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt @@ -27,6 +27,7 @@ open class LoggerTag(name: String, parentTag: LoggerTag? = null) { object SYNC : LoggerTag("SYNC") object VOIP : LoggerTag("VOIP") object CRYPTO : LoggerTag("CRYPTO") + object RENDEZVOUS : LoggerTag("RZ") val value: String = if (parentTag == null) { name diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt new file mode 100644 index 00000000000..43552f46be6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt @@ -0,0 +1,45 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous + +import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousIntent + +interface RendezvousChannel { + var transport: RendezvousTransport; + /** + * @returns the checksum/confirmation digits to be shown to the user + */ + suspend fun connect(): String + /** + * Send a payload via the channel. + * @param data payload to send + */ + suspend fun send(data: ByteArray) + /** + * Receive a payload from the channel. + * @returns the received payload + */ + suspend fun receive(): ByteArray? + /** + * @returns a representation of the channel that can be encoded in a QR or similar + */ + suspend fun close() + // TODO: this should be transport independent in the future + suspend fun generateCode(intent: RendezvousIntent): ECDHRendezvousCode + suspend fun cancel(reason: RendezvousFailureReason) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt new file mode 100644 index 00000000000..0e2ea8c7587 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt @@ -0,0 +1,31 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous + +enum class RendezvousFailureReason(val value: String, val canRetry: Boolean = true) { + UserDeclined("user_declined"), + OtherDeviceNotSignedIn("other_device_not_signed_in"), + OtherDeviceAlreadySignedIn("other_device_already_signed_in"), + Unknown("unknown"), + Expired("expired"), + UserCancelled("user_cancelled"), + InvalidCode("invalid_code"), + UnsupportedAlgorithm("unsupported_algorithm", false), + DataMismatch("data_mismatch"), + UnsupportedTransport("unsupported_transport", false), + HomeserverLacksSupport("homeserver_lacks_support", false) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt new file mode 100644 index 00000000000..753b0bc6fa3 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt @@ -0,0 +1,29 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous + +import okhttp3.MediaType +import org.matrix.android.sdk.internal.rendezvous.model.RendezvousTransportDetails + +interface RendezvousTransport { + var ready: Boolean; + var onCancelled: ((reason: RendezvousFailureReason) -> Unit)?; + suspend fun details(): RendezvousTransportDetails; + suspend fun send(contentType: MediaType, data: ByteArray); + suspend fun receive(): ByteArray?; + suspend fun cancel(reason: RendezvousFailureReason); +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt new file mode 100644 index 00000000000..e296dce09d2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt @@ -0,0 +1,34 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.internal.rendezvous.transports.SimpleHttpRendezvousTransportDetails + +@JsonClass(generateAdapter = true) +data class ECDHRendezvous( + @Json val transport: SimpleHttpRendezvousTransportDetails, + @Json val algorithm: SecureRendezvousChannelAlgorithm, + @Json val key: String +) + +@JsonClass(generateAdapter = true) +data class ECDHRendezvousCode( + @Json val intent: RendezvousIntent, + @Json val rendezvous: ECDHRendezvous +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt new file mode 100644 index 00000000000..d490de01338 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt @@ -0,0 +1,26 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +open class EmbeddedRendezvous( + @Json(name = "transport") val transport: RendezvousTransportDetails, + @Json(name = "algorithm") val algorithm: SecureRendezvousChannelAlgorithm +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt new file mode 100644 index 00000000000..ead273e8ce2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt @@ -0,0 +1,22 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason + +class RendezvousError(val description: String, val reason: RendezvousFailureReason): RuntimeException(description) { +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt new file mode 100644 index 00000000000..6285c1e57a4 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt @@ -0,0 +1,24 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import com.squareup.moshi.Json + +enum class RendezvousIntent { + @Json(name = "login.start") LOGIN_ON_NEW_DEVICE, + @Json(name = "login.reciprocate") RECIPROCATE_LOGIN_ON_EXISTING_DEVICE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt new file mode 100644 index 00000000000..1b1826194fb --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt @@ -0,0 +1,25 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +open class RendezvousTransportDetails( + @Json val type: RendezvousTransportType +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt new file mode 100644 index 00000000000..c3b6ba7ac87 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt @@ -0,0 +1,23 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import com.squareup.moshi.Json + +enum class RendezvousTransportType(val value: String) { + @Json(name = "http.v1") MSC3886_SIMPLE_HTTP_V1("http.v1") +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt new file mode 100644 index 00000000000..ddc0ae20e7c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt @@ -0,0 +1,23 @@ +/* + * 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 org.matrix.android.sdk.internal.rendezvous.model + +import com.squareup.moshi.Json + +enum class SecureRendezvousChannelAlgorithm(val value: String) { + @Json(name = "m.rendezvous.v1.curve25519-aes-sha256") ECDH_V1("m.rendezvous.v1.curve25519-aes-sha256") +} From f04f0e6fac25345b7cdc39181e0ac4743fdb37c5 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 22:42:58 +0100 Subject: [PATCH 38/93] Revert "Revert "Partial implementation of QR login logic"" This reverts commit e305478ddabf39c6e2a272485a1b154b3ad12263. --- .../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 | 4 ++-- 5 files changed, 13 insertions(+), 31 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 822e9d38651..108fe7db7cc 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3368,6 +3368,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 330562b8740..4de191f863c 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 9a6cc13de02..00000000000 --- 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 1c0841aa115..fb372cbb2fd 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 d9c30690a79..8461d8d88fd 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 @@ -39,7 +39,7 @@ class QrCodeLoginViewModel @AssistedInject constructor( @Assisted private val initialState: QrCodeLoginViewState, private val applicationContext: Context, private val authenticationService: AuthenticationService, - private val activeSessionHolder: ActiveSessionHolder, + private val activeSessionHolder: ActiveSessionHolder ) : VectorViewModel(initialState) { val TAG: String = QrCodeLoginViewModel::class.java.simpleName @@ -116,7 +116,7 @@ class QrCodeLoginViewModel @AssistedInject constructor( private fun onFailed(reason: RendezvousFailureReason) { setState { copy( - connectionStatus = QrCodeLoginConnectionStatus.Failed(errorType, canTryAgain) + connectionStatus = QrCodeLoginConnectionStatus.Failed(reason, reason.canRetry) ) } } From 5abb786b6b792ea70f38ca616bd5925a329af719 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 00:59:31 +0100 Subject: [PATCH 39/93] Fix copyright on SDK --- .../org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt | 2 +- .../matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt | 2 +- .../android/sdk/internal/rendezvous/RendezvousFailureReason.kt | 2 +- .../android/sdk/internal/rendezvous/RendezvousTransport.kt | 2 +- .../sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt | 2 +- .../android/sdk/internal/rendezvous/model/ECDHRendezvous.kt | 2 +- .../android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt | 2 +- .../android/sdk/internal/rendezvous/model/RendezvousError.kt | 2 +- .../android/sdk/internal/rendezvous/model/RendezvousIntent.kt | 2 +- .../sdk/internal/rendezvous/model/RendezvousTransportDetails.kt | 2 +- .../sdk/internal/rendezvous/model/RendezvousTransportType.kt | 2 +- .../rendezvous/model/SecureRendezvousChannelAlgorithm.kt | 2 +- .../rendezvous/transports/SimpleHttpRendezvousTransport.kt | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt index 2f85a97c558..d8fd3230565 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt index 43552f46be6..66554688086 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt index 0e2ea8c7587..0920bf224f1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt index 753b0bc6fa3..f054b7cb734 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt index cced29aab45..9f347b85368 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt index e296dce09d2..14976ec836e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt index d490de01338..5a609d497e9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt index ead273e8ce2..feb7d0cf35b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt index 6285c1e57a4..d317531835a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt index 1b1826194fb..ee9058daa3d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt index c3b6ba7ac87..51371ddb2fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt index ddc0ae20e7c..122b6ede82c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt index cc4346d55ef..7918946d75a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From c18439f99b7056619fcf1d7f7df3697d1ee5b63c Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 01:07:19 +0100 Subject: [PATCH 40/93] Refactor code into api from internal --- .../rendezvous/Rendezvous.kt | 12 ++++---- .../rendezvous/RendezvousChannel.kt | 8 +++--- .../rendezvous/RendezvousFailureReason.kt | 4 +-- .../rendezvous/RendezvousTransport.kt | 6 ++-- .../channels/ECDHRendezvousChannel.kt | 28 ++++++++++--------- .../rendezvous/model/ECDHRendezvous.kt | 6 ++-- .../rendezvous/model/EmbeddedRendezvous.kt | 8 +++--- .../rendezvous/model/RendezvousError.kt | 6 ++-- .../rendezvous/model/RendezvousIntent.kt | 4 +-- .../model/RendezvousTransportDetails.kt | 4 +-- .../model/RendezvousTransportType.kt | 4 +-- .../model/SecureRendezvousChannelAlgorithm.kt | 4 +-- .../SimpleHttpRendezvousTransport.kt | 12 ++++---- .../login/qr/QrCodeLoginConnectionStatus.kt | 2 +- .../login/qr/QrCodeLoginStatusFragment.kt | 2 +- .../features/login/qr/QrCodeLoginViewModel.kt | 4 +-- 16 files changed, 58 insertions(+), 56 deletions(-) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/Rendezvous.kt (95%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/RendezvousChannel.kt (84%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/RendezvousFailureReason.kt (91%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/RendezvousTransport.kt (83%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/channels/ECDHRendezvousChannel.kt (90%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/ECDHRendezvous.kt (83%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/EmbeddedRendezvous.kt (72%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/RendezvousError.kt (79%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/RendezvousIntent.kt (87%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/RendezvousTransportDetails.kt (87%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/RendezvousTransportType.kt (86%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/model/SecureRendezvousChannelAlgorithm.kt (87%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/{internal => api}/rendezvous/transports/SimpleHttpRendezvousTransport.kt (93%) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt similarity index 95% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index d8fd3230565..534d5df1ca7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous +package org.matrix.android.sdk.api.rendezvous import android.net.Uri import com.squareup.moshi.Json @@ -29,10 +29,10 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NA import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.util.MatrixJsonParser -import org.matrix.android.sdk.internal.rendezvous.channels.ECDHRendezvousChannel -import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvousCode -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousIntent -import org.matrix.android.sdk.internal.rendezvous.transports.SimpleHttpRendezvousTransport +import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel +import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport import timber.log.Timber internal enum class PayloadType(val value: String) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt similarity index 84% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index 66554688086..2a73e8f112d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous +package org.matrix.android.sdk.api.rendezvous -import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvousCode -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent interface RendezvousChannel { var transport: RendezvousTransport; diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt similarity index 91% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt index 0920bf224f1..a607dc7f38f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousFailureReason.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous +package org.matrix.android.sdk.api.rendezvous enum class RendezvousFailureReason(val value: String, val canRetry: Boolean = true) { UserDeclined("user_declined"), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt similarity index 83% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt index f054b7cb734..11471288f6d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/RendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous +package org.matrix.android.sdk.api.rendezvous import okhttp3.MediaType -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousTransportDetails +import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails interface RendezvousTransport { var ready: Boolean; diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt similarity index 90% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 9f347b85368..0f69bd7eda0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.channels +package org.matrix.android.sdk.api.rendezvous.channels import android.util.Base64 import com.squareup.moshi.Json @@ -23,15 +23,15 @@ import okhttp3.MediaType.Companion.toMediaType import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.util.MatrixJsonParser import org.matrix.android.sdk.internal.extensions.toUnsignedInt -import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason -import org.matrix.android.sdk.internal.rendezvous.RendezvousChannel -import org.matrix.android.sdk.internal.rendezvous.RendezvousTransport -import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvous -import org.matrix.android.sdk.internal.rendezvous.model.ECDHRendezvousCode -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousError -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousIntent -import org.matrix.android.sdk.internal.rendezvous.model.SecureRendezvousChannelAlgorithm -import org.matrix.android.sdk.internal.rendezvous.transports.SimpleHttpRendezvousTransportDetails +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.api.rendezvous.RendezvousChannel +import org.matrix.android.sdk.api.rendezvous.RendezvousTransport +import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvous +import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.api.rendezvous.model.RendezvousError +import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm +import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransportDetails import org.matrix.olm.OlmSAS import timber.log.Timber import java.security.SecureRandom @@ -107,10 +107,12 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } else { // send our public key unencrypted // Timber.tag(TAG).i("Sending public key") - send(ECDHPayload( + send( + ECDHPayload( algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) - )) + ) + ) } olmSAS!!.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt similarity index 83% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt index 14976ec836e..b203101b660 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/ECDHRendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.rendezvous.transports.SimpleHttpRendezvousTransportDetails +import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransportDetails @JsonClass(generateAdapter = true) data class ECDHRendezvous( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt similarity index 72% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt index 5a609d497e9..785ce1fed7f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/EmbeddedRendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,13 +14,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) open class EmbeddedRendezvous( - @Json(name = "transport") val transport: RendezvousTransportDetails, - @Json(name = "algorithm") val algorithm: SecureRendezvousChannelAlgorithm + @Json(name = "transport") val transport: RendezvousTransportDetails, + @Json(name = "algorithm") val algorithm: SecureRendezvousChannelAlgorithm ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt similarity index 79% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt index feb7d0cf35b..f731c89649a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model -import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason class RendezvousError(val description: String, val reason: RendezvousFailureReason): RuntimeException(description) { } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt similarity index 87% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt index d317531835a..1c070599b0e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousIntent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt similarity index 87% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt index ee9058daa3d..55b3bbb5d9a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportDetails.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt similarity index 86% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt index 51371ddb2fd..9c3e44f25b6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/RendezvousTransportType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt similarity index 87% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt index 122b6ede82c..9a9db58a41e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/model/SecureRendezvousChannelAlgorithm.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.model +package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 7918946d75a..ba604595441 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.rendezvous.transports +package org.matrix.android.sdk.api.rendezvous.transports import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -23,10 +23,10 @@ import okhttp3.MediaType import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.matrix.android.sdk.api.logger.LoggerTag -import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason -import org.matrix.android.sdk.internal.rendezvous.RendezvousTransport -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousTransportDetails -import org.matrix.android.sdk.internal.rendezvous.model.RendezvousTransportType +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.api.rendezvous.RendezvousTransport +import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails +import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportType import timber.log.Timber import java.text.SimpleDateFormat import java.util.Date 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 4de191f863c..4bef41b6c1a 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,7 +16,7 @@ package im.vector.app.features.login.qr -import org.matrix.android.sdk.internal.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason sealed class QrCodeLoginConnectionStatus { object ConnectingToDevice : QrCodeLoginConnectionStatus() 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 fb372cbb2fd..5451a16b44f 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,7 +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 +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason @AndroidEntryPoint class QrCodeLoginStatusFragment : VectorBaseFragment() { 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 8461d8d88fd..276cedad430 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 @@ -31,8 +31,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.AuthenticationService 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 org.matrix.android.sdk.api.rendezvous.Rendezvous +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import timber.log.Timber class QrCodeLoginViewModel @AssistedInject constructor( From c00ce91214cea1a0308d7885d46b5ea5224f5aea Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 01:11:25 +0100 Subject: [PATCH 41/93] Linting --- .../android/sdk/api/rendezvous/Rendezvous.kt | 27 ++++++++++--------- .../sdk/api/rendezvous/RendezvousChannel.kt | 7 ++++- .../sdk/api/rendezvous/RendezvousTransport.kt | 12 ++++----- .../channels/ECDHRendezvousChannel.kt | 9 +++---- .../api/rendezvous/model/RendezvousError.kt | 3 +-- .../SimpleHttpRendezvousTransport.kt | 2 +- .../features/login/qr/QrCodeLoginViewModel.kt | 2 -- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index 534d5df1ca7..e33130e5297 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -22,6 +22,10 @@ import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.logger.LoggerTag +import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel +import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME @@ -29,10 +33,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NA import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.util.MatrixJsonParser -import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel -import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode -import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent -import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport import timber.log.Timber internal enum class PayloadType(val value: String) { @@ -80,6 +80,7 @@ class Rendezvous( } private val adapter = MatrixJsonParser.getMoshi().adapter(Payload::class.java) + // not yet implemented: RendezvousIntent.RECIPROCATE_LOGIN_ON_EXISTING_DEVICE val ourIntent: RendezvousIntent = RendezvousIntent.LOGIN_ON_NEW_DEVICE @@ -98,7 +99,7 @@ class Rendezvous( } suspend fun startAfterScanningCode(): String? { - val checksum = channel.connect(); + val checksum = channel.connect() Timber.tag(TAG).i("Connected to secure channel with checksum: $checksum") @@ -107,7 +108,7 @@ class Rendezvous( } // get protocols - Timber.tag(TAG).i("Waiting for protocols"); + Timber.tag(TAG).i("Waiting for protocols") val protocolsResponse = receive() if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains("login_token")) { @@ -123,7 +124,7 @@ class Rendezvous( } suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session? { - Timber.tag(TAG).i("Waiting for login_token"); + Timber.tag(TAG).i("Waiting for login_token") val loginToken = receive() @@ -147,7 +148,7 @@ class Rendezvous( val homeserver = loginToken?.homeserver ?: throw RuntimeException("No homeserver returned") val login_token = loginToken.login_token ?: throw RuntimeException("No login token returned") - Timber.tag(TAG).i("Got login_token: $login_token for $homeserver"); + Timber.tag(TAG).i("Got login_token: $login_token for $homeserver") val hsConfig = HomeServerConnectionConfig(homeServerUri = Uri.parse(homeserver)) return authenticationService.loginUsingQrLoginToken(hsConfig, login_token) @@ -167,11 +168,11 @@ class Rendezvous( val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifying_device_key) { Timber.tag(TAG).w("Verifying device $verifyingDeviceId doesn't match: $verifyingDeviceFromServer") - return; + return } // set other device as verified - Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified"); + Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) // TODO: what do we do with the master key? @@ -183,7 +184,7 @@ class Rendezvous( // request secrets from the verifying device Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") - session.sharedSecretStorageService() .let { + session.sharedSecretStorageService().let { it.requestSecret(MASTER_KEY_SSSS_NAME, verifyingDeviceId) it.requestSecret(SELF_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) it.requestSecret(USER_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) @@ -192,12 +193,12 @@ class Rendezvous( } private suspend fun receive(): Payload? { - val data = channel.receive()?: return null + val data = channel.receive() ?: return null return adapter.fromJson(data.toString(Charsets.UTF_8)) } private suspend fun send(payload: Payload) { - channel.send(adapter.toJson(payload).toByteArray(Charsets.UTF_8)); + channel.send(adapter.toJson(payload).toByteArray(Charsets.UTF_8)) } suspend fun cancel(reason: RendezvousFailureReason) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index 2a73e8f112d..588d034f108 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -20,25 +20,30 @@ import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent interface RendezvousChannel { - var transport: RendezvousTransport; + var transport: RendezvousTransport + /** * @returns the checksum/confirmation digits to be shown to the user */ suspend fun connect(): String + /** * Send a payload via the channel. * @param data payload to send */ suspend fun send(data: ByteArray) + /** * Receive a payload from the channel. * @returns the received payload */ suspend fun receive(): ByteArray? + /** * @returns a representation of the channel that can be encoded in a QR or similar */ suspend fun close() + // TODO: this should be transport independent in the future suspend fun generateCode(intent: RendezvousIntent): ECDHRendezvousCode suspend fun cancel(reason: RendezvousFailureReason) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt index 11471288f6d..de0aed7efc6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt @@ -20,10 +20,10 @@ import okhttp3.MediaType import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails interface RendezvousTransport { - var ready: Boolean; - var onCancelled: ((reason: RendezvousFailureReason) -> Unit)?; - suspend fun details(): RendezvousTransportDetails; - suspend fun send(contentType: MediaType, data: ByteArray); - suspend fun receive(): ByteArray?; - suspend fun cancel(reason: RendezvousFailureReason); + var ready: Boolean + var onCancelled: ((reason: RendezvousFailureReason) -> Unit)? + suspend fun details(): RendezvousTransportDetails + suspend fun send(contentType: MediaType, data: ByteArray) + suspend fun receive(): ByteArray? + suspend fun cancel(reason: RendezvousFailureReason) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 0f69bd7eda0..1c8bca5d1cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -21,10 +21,8 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import okhttp3.MediaType.Companion.toMediaType import org.matrix.android.sdk.api.logger.LoggerTag -import org.matrix.android.sdk.api.util.MatrixJsonParser -import org.matrix.android.sdk.internal.extensions.toUnsignedInt -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import org.matrix.android.sdk.api.rendezvous.RendezvousChannel +import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import org.matrix.android.sdk.api.rendezvous.RendezvousTransport import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvous import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode @@ -32,8 +30,9 @@ import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransportDetails +import org.matrix.android.sdk.api.util.MatrixJsonParser +import org.matrix.android.sdk.internal.extensions.toUnsignedInt import org.matrix.olm.OlmSAS -import timber.log.Timber import java.security.SecureRandom import java.util.LinkedList import javax.crypto.Cipher @@ -72,7 +71,7 @@ const val KEY_SPEC = "AES" * Implements X25519 ECDH key agreement and AES-256-GCM encryption channel as per MSC3903: * https://github.com/matrix-org/matrix-spec-proposals/pull/3903 */ -class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPublicKeyBase64: String?): RendezvousChannel { +class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPublicKeyBase64: String?) : RendezvousChannel { private var olmSAS: OlmSAS? private val ourPublicKey: ByteArray private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt index f731c89649a..fec55ffb67c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt @@ -18,5 +18,4 @@ package org.matrix.android.sdk.api.rendezvous.model import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason -class RendezvousError(val description: String, val reason: RendezvousFailureReason): RuntimeException(description) { -} +class RendezvousError(val description: String, val reason: RendezvousFailureReason) : RuntimeException(description) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index ba604595441..475a4fbe6ce 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -36,7 +36,7 @@ private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName @JsonClass(generateAdapter = true) data class SimpleHttpRendezvousTransportDetails( @Json val uri: String -): RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) +) : RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) /** * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 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 276cedad430..7a510984399 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 @@ -26,11 +26,9 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.home.HomeActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.AuthenticationService -import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.rendezvous.Rendezvous import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import timber.log.Timber From efa70fa0ff92b56d15f638dbd240a050f9b3ff25 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 21:48:33 +0100 Subject: [PATCH 42/93] Revert "Retry scanning if not a QR code" This reverts commit 87956e943897333f3f7e9be9a6e59d9a7f0c4547. --- .../app/features/login/qr/QrCodeLoginInstructionsFragment.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt index 17b4ff24095..ae3ba9574b7 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt @@ -83,7 +83,6 @@ class QrCodeLoginInstructionsFragment : VectorBaseFragment Date: Fri, 14 Oct 2022 01:45:03 +0100 Subject: [PATCH 43/93] Add flag to allow QR login on all servers + split flag for showing in device manager --- .../debug/features/DebugFeaturesStateFactory.kt | 10 ++++++++++ .../app/features/debug/features/DebugVectorFeatures.kt | 8 ++++++++ .../main/java/im/vector/app/features/VectorFeatures.kt | 4 ++++ .../app/features/onboarding/OnboardingViewModel.kt | 9 +++++++++ .../devices/v2/VectorSettingsDevicesFragment.kt | 2 +- 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt index 3a302feba09..1d8171a9e59 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt @@ -95,6 +95,16 @@ class DebugFeaturesStateFactory @Inject constructor( key = DebugFeatureKeys.qrCodeLoginEnabled, factory = VectorFeatures::isQrCodeLoginEnabled ), + createBooleanFeature( + label = "Allow QR Code Login for all servers", + key = DebugFeatureKeys.allowQrCodeLoginForAllServers, + factory = VectorFeatures::allowQrCodeLoginForAllServers + ), + createBooleanFeature( + label = "Show QR Code Login in Device Manager", + key = DebugFeatureKeys.allowReciprocateQrCodeLogin, + factory = VectorFeatures::allowReciprocateQrCodeLogin + ), createBooleanFeature( label = "Enable Voice Broadcast", key = DebugFeatureKeys.voiceBroadcastEnabled, diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt index b5ffa28db7c..701f2dcab81 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt @@ -82,6 +82,12 @@ class DebugVectorFeatures( override fun isQrCodeLoginEnabled() = read(DebugFeatureKeys.qrCodeLoginEnabled) ?: vectorFeatures.isQrCodeLoginEnabled() + override fun allowQrCodeLoginForAllServers() = read(DebugFeatureKeys.allowQrCodeLoginForAllServers) + ?: vectorFeatures.allowQrCodeLoginForAllServers() + + override fun allowReciprocateQrCodeLogin() = read(DebugFeatureKeys.allowReciprocateQrCodeLogin) + ?: vectorFeatures.allowReciprocateQrCodeLogin() + override fun isVoiceBroadcastEnabled(): Boolean = read(DebugFeatureKeys.voiceBroadcastEnabled) ?: vectorFeatures.isVoiceBroadcastEnabled() @@ -147,5 +153,7 @@ object DebugFeatureKeys { val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled") val newDeviceManagementEnabled = booleanPreferencesKey("new-device-management-enabled") val qrCodeLoginEnabled = booleanPreferencesKey("qr-code-login-enabled") + val allowQrCodeLoginForAllServers = booleanPreferencesKey("allow-qr-code-login-for-all-servers") + val allowReciprocateQrCodeLogin = booleanPreferencesKey("allow-reciprocate-qr-code-login") val voiceBroadcastEnabled = booleanPreferencesKey("voice-broadcast-enabled") } diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index 62eb0523b08..061276ba212 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -42,6 +42,8 @@ interface VectorFeatures { fun isNewAppLayoutFeatureEnabled(): Boolean fun isNewDeviceManagementEnabled(): Boolean fun isQrCodeLoginEnabled(): Boolean + fun allowQrCodeLoginForAllServers(): Boolean + fun allowReciprocateQrCodeLogin(): Boolean fun isVoiceBroadcastEnabled(): Boolean } @@ -60,5 +62,7 @@ class DefaultVectorFeatures : VectorFeatures { override fun isNewAppLayoutFeatureEnabled(): Boolean = true override fun isNewDeviceManagementEnabled(): Boolean = false override fun isQrCodeLoginEnabled(): Boolean = false + override fun allowQrCodeLoginForAllServers(): Boolean = false + override fun allowReciprocateQrCodeLogin(): Boolean = false override fun isVoiceBroadcastEnabled(): Boolean = false } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt index 03cf2f43e6a..8e64948c6ab 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt @@ -124,7 +124,16 @@ class OnboardingViewModel @AssistedInject constructor( canLoginWithQrCode = false ) } + } else if (vectorFeatures.allowQrCodeLoginForAllServers()) { + // allow for all servers + setState { + copy( + canLoginWithQrCode = true + ) + } } else { + // check if selected server supports MSC3882 first + // FIXME: this should be checking the selected homeserver not defaultHomeserverUrl homeServerConnectionConfigFactory.create(defaultHomeserverUrl)?.let { val canLoginWithQrCode = authenticationService.isQrLoginSupported(it) setState { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 48f66cfc757..7e6da851dd4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -158,7 +158,7 @@ class VectorSettingsDevicesFragment : } private fun initQrLoginView() { - if (!vectorFeatures.isQrCodeLoginEnabled()) { + if (!vectorFeatures.allowReciprocateQrCodeLogin()) { views.deviceListHeaderSignInWithQrCode.isVisible = false views.deviceListHeaderScanQrCodeButton.isVisible = false views.deviceListHeaderShowQrCodeButton.isVisible = false From de4232dff519b05063e0e671789802bbd96830cd Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 02:04:08 +0100 Subject: [PATCH 44/93] Fix logic for showing confirm button --- .../vector/app/features/login/qr/QrCodeLoginStatusFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5451a16b44f..05ed070915a 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 @@ -115,7 +115,7 @@ class QrCodeLoginStatusFragment : VectorBaseFragment Date: Fri, 14 Oct 2022 13:46:57 +0100 Subject: [PATCH 45/93] Handle master key trust during E2EE set up --- .../android/sdk/api/rendezvous/Rendezvous.kt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index e33130e5297..17f3a731812 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -176,10 +176,17 @@ class Rendezvous( crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) // TODO: what do we do with the master key? -// verificationResponse.master_key ?.let { -// // set master key as trusted -// crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, it) -// } + verificationResponse.master_key ?.let { masterKeyFromVerifyingDevice -> + // set master key as trusted + crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey()?.let { localMasterKey -> + if (localMasterKey.unpaddedBase64PublicKey == masterKeyFromVerifyingDevice) { + Timber.tag(TAG).i("Setting master key as trusted") + crypto.crossSigningService().markMyMasterKeyAsTrusted() + } else { + Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") + } + } ?: Timber.tag(TAG).i("No local master key") + } ?: Timber.tag(TAG).i("No master key given by verifying device") // request secrets from the verifying device Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") From f999e7275952633a87d9cff123a4211546e7e735 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 14:01:13 +0100 Subject: [PATCH 46/93] Changelog --- changelog.d/7369.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7369.feature diff --git a/changelog.d/7369.feature b/changelog.d/7369.feature new file mode 100644 index 00000000000..240fac35160 --- /dev/null +++ b/changelog.d/7369.feature @@ -0,0 +1 @@ +Add logic for sign in with QR code From 411b766890ab33722b10be177bb1f3e64d963e75 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 14:17:19 +0100 Subject: [PATCH 47/93] Refactor to camelcase --- .../android/sdk/api/rendezvous/Rendezvous.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index 17f3a731812..67bdeb22353 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -49,12 +49,12 @@ internal data class Payload( @Json val protocols: List? = null, @Json val protocol: String? = null, @Json val homeserver: String? = null, - @Json val login_token: String? = null, - @Json val device_id: String? = null, - @Json val device_key: String? = null, - @Json val verifying_device_id: String? = null, - @Json val verifying_device_key: String? = null, - @Json val master_key: String? = null + @Json(name = "login_token") val loginToken: String? = null, + @Json(name = "device_id") val deviceId: String? = null, + @Json(name = "device_key") val deviceKey: String? = null, + @Json(name = "verifying_device_id") val verifyingDeviceId: String? = null, + @Json(name = "verifying_device_key") val verifyingDeviceKey: String? = null, + @Json(name = "master_key") val masterKey: String? = null ) private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value @@ -146,7 +146,7 @@ class Rendezvous( } val homeserver = loginToken?.homeserver ?: throw RuntimeException("No homeserver returned") - val login_token = loginToken.login_token ?: throw RuntimeException("No login token returned") + val login_token = loginToken.loginToken ?: throw RuntimeException("No login token returned") Timber.tag(TAG).i("Got login_token: $login_token for $homeserver") @@ -159,14 +159,14 @@ class Rendezvous( val crypto = session.cryptoService() val deviceId = crypto.getMyDevice().deviceId val deviceKey = crypto.getMyDevice().fingerprint() - send(Payload(PayloadType.Progress, outcome = "success", device_id = deviceId, device_key = deviceKey)) + send(Payload(PayloadType.Progress, outcome = "success", deviceId = deviceId, deviceKey = deviceKey)) // await confirmation of verification val verificationResponse = receive() - val verifyingDeviceId = verificationResponse?.verifying_device_id ?: throw RuntimeException("No verifying device id returned") + val verifyingDeviceId = verificationResponse?.verifyingDeviceId ?: throw RuntimeException("No verifying device id returned") val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) - if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifying_device_key) { + if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { Timber.tag(TAG).w("Verifying device $verifyingDeviceId doesn't match: $verifyingDeviceFromServer") return } @@ -176,7 +176,7 @@ class Rendezvous( crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) // TODO: what do we do with the master key? - verificationResponse.master_key ?.let { masterKeyFromVerifyingDevice -> + verificationResponse.masterKey ?.let { masterKeyFromVerifyingDevice -> // set master key as trusted crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey()?.let { localMasterKey -> if (localMasterKey.unpaddedBase64PublicKey == masterKeyFromVerifyingDevice) { From 6426ff40d351396741ebf8aa71da1b87d9661673 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 14:18:50 +0100 Subject: [PATCH 48/93] Linting --- .../org/matrix/android/sdk/api/rendezvous/Rendezvous.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index 67bdeb22353..6403d170316 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -91,7 +91,11 @@ class Rendezvous( if (incompatible) { send(Payload(PayloadType.Finish, intent = ourIntent)) - val reason = if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) RendezvousFailureReason.OtherDeviceNotSignedIn else RendezvousFailureReason.OtherDeviceAlreadySignedIn + val reason = if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) { + RendezvousFailureReason.OtherDeviceNotSignedIn + } else { + RendezvousFailureReason.OtherDeviceAlreadySignedIn + } channel.cancel(reason) } @@ -175,7 +179,6 @@ class Rendezvous( Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - // TODO: what do we do with the master key? verificationResponse.masterKey ?.let { masterKeyFromVerifyingDevice -> // set master key as trusted crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey()?.let { localMasterKey -> From fdc55965ca0e3328d6ed4f32b00bde97f00941b9 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 17:23:26 +0100 Subject: [PATCH 49/93] Linting --- .../matrix/android/sdk/api/rendezvous/RendezvousChannel.kt | 5 ++++- .../app/features/login/qr/QrCodeLoginStatusFragment.kt | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index 588d034f108..9d2843ce66c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -19,6 +19,9 @@ package org.matrix.android.sdk.api.rendezvous import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent +/** + * Representation of a rendezvous channel such as that described by MSC3903 + */ interface RendezvousChannel { var transport: RendezvousTransport @@ -44,7 +47,7 @@ interface RendezvousChannel { */ suspend fun close() - // TODO: this should be transport independent in the future + // In future we probably want this to be a more generic RendezvousCode but it is suffice for now suspend fun generateCode(intent: RendezvousIntent): ECDHRendezvousCode suspend fun cancel(reason: RendezvousFailureReason) } 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 556be3af4d3..f0030d67633 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 @@ -80,7 +80,8 @@ class QrCodeLoginStatusFragment : VectorBaseFragment getString(R.string.qr_code_login_header_failed_device_is_not_supported_description) + 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) From bfe3daa37fda9cd42bc541b5c13c4f75bb58e221 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 17:25:06 +0100 Subject: [PATCH 50/93] Fix compile error from bad merge --- .../vector/app/features/login/qr/QrCodeLoginViewModel.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 7a510984399..af0df22ca3d 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 @@ -24,8 +24,8 @@ import dagger.assisted.AssistedInject import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.session.ConfigureAndStartSessionUseCase import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.AuthenticationService @@ -37,7 +37,8 @@ class QrCodeLoginViewModel @AssistedInject constructor( @Assisted private val initialState: QrCodeLoginViewState, private val applicationContext: Context, private val authenticationService: AuthenticationService, - private val activeSessionHolder: ActiveSessionHolder + private val activeSessionHolder: ActiveSessionHolder, + private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase ) : VectorViewModel(initialState) { val TAG: String = QrCodeLoginViewModel::class.java.simpleName @@ -97,7 +98,7 @@ class QrCodeLoginViewModel @AssistedInject constructor( activeSessionHolder.setActiveSession(session) authenticationService.reset() - session.configureAndStart(applicationContext) + configureAndStartSessionUseCase.execute(session, startSyncing) rendezvous.completeVerificationOnNewDevice(session) From a3fc78594502953d86944d3f1ec0509c13921e7d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 14 Oct 2022 18:52:42 +0100 Subject: [PATCH 51/93] Fix missing param --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 af0df22ca3d..81a00cf5488 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 @@ -98,7 +98,7 @@ class QrCodeLoginViewModel @AssistedInject constructor( activeSessionHolder.setActiveSession(session) authenticationService.reset() - configureAndStartSessionUseCase.execute(session, startSyncing) + configureAndStartSessionUseCase.execute(session) rendezvous.completeVerificationOnNewDevice(session) From d979b50b2cd8b098b5bd3e353264e7e76be5dabe Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 10:52:24 +0100 Subject: [PATCH 52/93] Logging cleanup --- .../android/sdk/api/rendezvous/Rendezvous.kt | 22 ++++++++++++------- .../channels/ECDHRendezvousChannel.kt | 16 ++++---------- .../SimpleHttpRendezvousTransport.kt | 11 +++------- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index 6403d170316..b43b122cba9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -36,9 +36,14 @@ import org.matrix.android.sdk.api.util.MatrixJsonParser import timber.log.Timber internal enum class PayloadType(val value: String) { - @Json(name = "m.login.start") Start("m.login.start"), - @Json(name = "m.login.finish") Finish("m.login.finish"), - @Json(name = "m.login.progress") Progress("m.login.progress") + @Json(name = "m.login.start") + Start("m.login.start"), + + @Json(name = "m.login.finish") + Finish("m.login.finish"), + + @Json(name = "m.login.progress") + Progress("m.login.progress") } @JsonClass(generateAdapter = true) @@ -150,12 +155,12 @@ class Rendezvous( } val homeserver = loginToken?.homeserver ?: throw RuntimeException("No homeserver returned") - val login_token = loginToken.loginToken ?: throw RuntimeException("No login token returned") + val token = loginToken.loginToken ?: throw RuntimeException("No login token returned") - Timber.tag(TAG).i("Got login_token: $login_token for $homeserver") + Timber.tag(TAG).i("Got login_token now attempting to sign in with $homeserver") val hsConfig = HomeServerConnectionConfig(homeServerUri = Uri.parse(homeserver)) - return authenticationService.loginUsingQrLoginToken(hsConfig, login_token) + return authenticationService.loginUsingQrLoginToken(hsConfig, token) } suspend fun completeVerificationOnNewDevice(session: Session) { @@ -171,8 +176,8 @@ class Rendezvous( val verifyingDeviceId = verificationResponse?.verifyingDeviceId ?: throw RuntimeException("No verifying device id returned") val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { - Timber.tag(TAG).w("Verifying device $verifyingDeviceId doesn't match: $verifyingDeviceFromServer") - return + Timber.tag(TAG).w("Verifying device $verifyingDeviceId key doesn't match: ${verifyingDeviceFromServer?.fingerprint()} vs ${verificationResponse.verifyingDeviceKey})") + throw RuntimeException("Key from verifying device doesn't match") } // set other device as verified @@ -187,6 +192,7 @@ class Rendezvous( crypto.crossSigningService().markMyMasterKeyAsTrusted() } else { Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") + throw RuntimeException("Master key from verifying device doesn't match") } } ?: Timber.tag(TAG).i("No local master key") } ?: Timber.tag(TAG).i("No master key given by verifying device") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 1c8bca5d1cb..4d5ed30ac5d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTran import org.matrix.android.sdk.api.util.MatrixJsonParser import org.matrix.android.sdk.internal.extensions.toUnsignedInt import org.matrix.olm.OlmSAS +import timber.log.Timber import java.security.SecureRandom import java.util.LinkedList import javax.crypto.Cipher @@ -93,7 +94,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu val isInitiator = theirPublicKey == null if (isInitiator) { -// Timber.tag(TAG).i("Waiting for other device to send their public key") + Timber.tag(TAG).i("Waiting for other device to send their public key") val res = this.receiveAsPayload() ?: throw RuntimeException("No reply from other device") if (res.key == null) { @@ -105,7 +106,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) } else { // send our public key unencrypted -// Timber.tag(TAG).i("Sending public key") + Timber.tag(TAG).i("Sending public key") send( ECDHPayload( algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, @@ -122,11 +123,6 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu aesKey = olmSAS!!.generateShortCode(aesInfo, 32) -// Timber.tag(TAG).i("Our public key: ${Base64.encodeToString(ourPublicKey, Base64.NO_WRAP)}") -// Timber.tag(TAG).i("Their public key: ${Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)}") -// Timber.tag(TAG).i("AES info: $aesInfo") -// Timber.tag(TAG).i("AES key: ${Base64.encodeToString(aesKey, Base64.NO_WRAP)}") - val rawChecksum = olmSAS!!.generateShortCode(aesInfo, 5) return getDecimalCodeRepresentation(rawChecksum) } @@ -181,7 +177,6 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } private fun encrypt(plainText: ByteArray): ECDHPayload { -// Timber.tag(TAG).d("Encrypting: ${plainText.toString(Charsets.UTF_8)}") val iv = ByteArray(16) SecureRandom().nextBytes(iv) @@ -211,9 +206,6 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu plainText.addAll(encryptCipher.update(Base64.decode(payload.ciphertext, Base64.NO_WRAP)).toList()) plainText.addAll(encryptCipher.doFinal().toList()) - val plainTextBytes = plainText.toByteArray() - -// Timber.tag(TAG).d("Decrypted: ${plainTextBytes.toString(Charsets.UTF_8)}") - return plainTextBytes + return plainText.toByteArray() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 475a4fbe6ce..004cf38e241 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -67,8 +67,6 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo // TODO: properly determine endpoint val uri = if (uri != null) uri!! else "https://rendezvous.lab.element.dev" -// Timber.tag(TAG).i("Sending data: ${data.toString(Charsets.UTF_8)} to $uri") - val httpClient = okhttp3.OkHttpClient.Builder().build() val request = Request.Builder() @@ -123,8 +121,6 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo val response = httpClient.newCall(request.build()).execute() try { -// Timber.tag(TAG).d("Received polling response: ${response.code} from $uri") - if (response.code == 404) { cancel(RendezvousFailureReason.Unknown) return null @@ -140,9 +136,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo response.header("etag")?.let { etag = it } - val data = response.body?.bytes() -// Timber.tag(TAG).d("Received data: ${data?.toString(Charsets.UTF_8)} from $uri with etag $etag") - return data + return response.body?.bytes() } done = false @@ -159,7 +153,8 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo var mappedReason = reason Timber.tag(TAG).i("$expiresAt") if (mappedReason == RendezvousFailureReason.Unknown && - expiresAt != null && Date() > expiresAt) { + expiresAt != null && Date() > expiresAt + ) { mappedReason = RendezvousFailureReason.Expired } From ed6bc01bef48b4266dbe34e600f8038b0dcc6a3a Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 10:54:28 +0100 Subject: [PATCH 53/93] Resolve TODO --- .../api/rendezvous/transports/SimpleHttpRendezvousTransport.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 004cf38e241..dde5edcb939 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -64,8 +64,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo } val method = if (uri != null) "PUT" else "POST" - // TODO: properly determine endpoint - val uri = if (uri != null) uri!! else "https://rendezvous.lab.element.dev" + val uri = this.uri ?: throw RuntimeException("No rendezvous URI") val httpClient = okhttp3.OkHttpClient.Builder().build() From 33be5c257dcaa8c674486a77c5851d1a6a626f7e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 11:24:48 +0100 Subject: [PATCH 54/93] Refactor into dedicated files and companion objects --- .../android/sdk/api/rendezvous/Rendezvous.kt | 39 +++--------- .../channels/ECDHRendezvousChannel.kt | 59 ++++++++++--------- .../api/rendezvous/model/ECDHRendezvous.kt | 7 --- .../rendezvous/model/ECDHRendezvousCode.kt | 26 ++++++++ .../sdk/api/rendezvous/model/Payload.kt | 36 +++++++++++ .../sdk/api/rendezvous/model/PayloadType.kt | 30 ++++++++++ .../SimpleHttpRendezvousTransportDetails.kt | 25 ++++++++ .../SimpleHttpRendezvousTransport.kt | 13 ++-- 8 files changed, 159 insertions(+), 76 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index b43b122cba9..4270d4a09ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -17,13 +17,13 @@ package org.matrix.android.sdk.api.rendezvous import android.net.Uri -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.api.rendezvous.model.Payload +import org.matrix.android.sdk.api.rendezvous.model.PayloadType import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport import org.matrix.android.sdk.api.session.Session @@ -35,35 +35,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_S import org.matrix.android.sdk.api.util.MatrixJsonParser import timber.log.Timber -internal enum class PayloadType(val value: String) { - @Json(name = "m.login.start") - Start("m.login.start"), - - @Json(name = "m.login.finish") - Finish("m.login.finish"), - - @Json(name = "m.login.progress") - Progress("m.login.progress") -} - -@JsonClass(generateAdapter = true) -internal data class Payload( - @Json val type: PayloadType, - @Json val intent: RendezvousIntent? = null, - @Json val outcome: String? = null, - @Json val protocols: List? = null, - @Json val protocol: String? = null, - @Json val homeserver: String? = null, - @Json(name = "login_token") val loginToken: String? = null, - @Json(name = "device_id") val deviceId: String? = null, - @Json(name = "device_key") val deviceKey: String? = null, - @Json(name = "verifying_device_id") val verifyingDeviceId: String? = null, - @Json(name = "verifying_device_key") val verifyingDeviceKey: String? = null, - @Json(name = "master_key") val masterKey: String? = null -) - -private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value - /** * Implementation of MSC3906 to sign in + E2EE set up using a QR code. */ @@ -72,6 +43,8 @@ class Rendezvous( val theirIntent: RendezvousIntent, ) { companion object { + private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value + fun buildChannelFromCode(code: String, onCancelled: (reason: RendezvousFailureReason) -> Unit): Rendezvous { val parsed = MatrixJsonParser.getMoshi().adapter(ECDHRendezvousCode::class.java).fromJson(code) ?: throw RuntimeException("Invalid code") @@ -176,7 +149,9 @@ class Rendezvous( val verifyingDeviceId = verificationResponse?.verifyingDeviceId ?: throw RuntimeException("No verifying device id returned") val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { - Timber.tag(TAG).w("Verifying device $verifyingDeviceId key doesn't match: ${verifyingDeviceFromServer?.fingerprint()} vs ${verificationResponse.verifyingDeviceKey})") + Timber.tag(TAG).w("Verifying device $verifyingDeviceId key doesn't match: ${ + verifyingDeviceFromServer?.fingerprint()} vs ${verificationResponse.verifyingDeviceKey})" + ) throw RuntimeException("Key from verifying device doesn't match") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 4d5ed30ac5d..5dbac894aef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm -import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransportDetails +import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransportDetails import org.matrix.android.sdk.api.util.MatrixJsonParser import org.matrix.android.sdk.internal.extensions.toUnsignedInt import org.matrix.olm.OlmSAS @@ -40,39 +40,40 @@ import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec -@JsonClass(generateAdapter = true) -data class ECDHPayload( - @Json val algorithm: SecureRendezvousChannelAlgorithm? = null, - @Json val key: String? = null, - @Json val ciphertext: String? = null, - @Json val iv: String? = null -) - -private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value - -fun getDecimalCodeRepresentation(byteArray: ByteArray): String { - val b0 = byteArray[0].toUnsignedInt() // need unsigned byte - val b1 = byteArray[1].toUnsignedInt() // need unsigned byte - val b2 = byteArray[2].toUnsignedInt() // need unsigned byte - val b3 = byteArray[3].toUnsignedInt() // need unsigned byte - val b4 = byteArray[4].toUnsignedInt() // need unsigned byte - // (B0 << 5 | B1 >> 3) + 1000 - val first = (b0.shl(5) or b1.shr(3)) + 1000 - // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 - val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 - // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 - val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 - return "$first-$second-$third" -} - -const val ALGORITHM_SPEC = "AES/GCM/NoPadding" -const val KEY_SPEC = "AES" - /** * Implements X25519 ECDH key agreement and AES-256-GCM encryption channel as per MSC3903: * https://github.com/matrix-org/matrix-spec-proposals/pull/3903 */ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPublicKeyBase64: String?) : RendezvousChannel { + companion object { + private const val ALGORITHM_SPEC = "AES/GCM/NoPadding" + private const val KEY_SPEC = "AES" + private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value + + private fun getDecimalCodeRepresentation(byteArray: ByteArray): String { + val b0 = byteArray[0].toUnsignedInt() // need unsigned byte + val b1 = byteArray[1].toUnsignedInt() // need unsigned byte + val b2 = byteArray[2].toUnsignedInt() // need unsigned byte + val b3 = byteArray[3].toUnsignedInt() // need unsigned byte + val b4 = byteArray[4].toUnsignedInt() // need unsigned byte + // (B0 << 5 | B1 >> 3) + 1000 + val first = (b0.shl(5) or b1.shr(3)) + 1000 + // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 + val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 + // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 + val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 + return "$first-$second-$third" + } + } + + @JsonClass(generateAdapter = true) + internal data class ECDHPayload( + @Json val algorithm: SecureRendezvousChannelAlgorithm? = null, + @Json val key: String? = null, + @Json val ciphertext: String? = null, + @Json val iv: String? = null + ) + private var olmSAS: OlmSAS? private val ourPublicKey: ByteArray private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt index b203101b660..0840e1ca2ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransportDetails @JsonClass(generateAdapter = true) data class ECDHRendezvous( @@ -26,9 +25,3 @@ data class ECDHRendezvous( @Json val algorithm: SecureRendezvousChannelAlgorithm, @Json val key: String ) - -@JsonClass(generateAdapter = true) -data class ECDHRendezvousCode( - @Json val intent: RendezvousIntent, - @Json val rendezvous: ECDHRendezvous -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt new file mode 100644 index 00000000000..410c5c10367 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.rendezvous.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ECDHRendezvousCode( + @Json val intent: RendezvousIntent, + @Json val rendezvous: ECDHRendezvous +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt new file mode 100644 index 00000000000..56274522322 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.rendezvous.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class Payload( + @Json val type: PayloadType, + @Json val intent: RendezvousIntent? = null, + @Json val outcome: String? = null, + @Json val protocols: List? = null, + @Json val protocol: String? = null, + @Json val homeserver: String? = null, + @Json(name = "login_token") val loginToken: String? = null, + @Json(name = "device_id") val deviceId: String? = null, + @Json(name = "device_key") val deviceKey: String? = null, + @Json(name = "verifying_device_id") val verifyingDeviceId: String? = null, + @Json(name = "verifying_device_key") val verifyingDeviceKey: String? = null, + @Json(name = "master_key") val masterKey: String? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt new file mode 100644 index 00000000000..9854e7c0703 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.rendezvous.model + +import com.squareup.moshi.Json + +internal enum class PayloadType(val value: String) { + @Json(name = "m.login.start") + Start("m.login.start"), + + @Json(name = "m.login.finish") + Finish("m.login.finish"), + + @Json(name = "m.login.progress") + Progress("m.login.progress") +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt new file mode 100644 index 00000000000..70a441d7608 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.rendezvous.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class SimpleHttpRendezvousTransportDetails( + @Json val uri: String +) : RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index dde5edcb939..03e8b0cda70 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -26,22 +26,19 @@ import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import org.matrix.android.sdk.api.rendezvous.RendezvousTransport import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails -import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportType +import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransportDetails import timber.log.Timber import java.text.SimpleDateFormat import java.util.Date -private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName, LoggerTag.RENDEZVOUS).value - -@JsonClass(generateAdapter = true) -data class SimpleHttpRendezvousTransportDetails( - @Json val uri: String -) : RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) - /** * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 */ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: RendezvousFailureReason) -> Unit)?, rendezvousUri: String?) : RendezvousTransport { + companion object { + private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName, LoggerTag.RENDEZVOUS).value + } + override var ready = false private var cancelled = false private var uri: String? From 3be4a0ca2137c339b66b9b5aa12bb0617c15d935 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 11:25:09 +0100 Subject: [PATCH 55/93] Remove unused val --- .../java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 1 - 1 file changed, 1 deletion(-) 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 81a00cf5488..8b70f61e800 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 @@ -35,7 +35,6 @@ import timber.log.Timber class QrCodeLoginViewModel @AssistedInject constructor( @Assisted private val initialState: QrCodeLoginViewState, - private val applicationContext: Context, private val authenticationService: AuthenticationService, private val activeSessionHolder: ActiveSessionHolder, private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase From 48de8f4e345105668298ec238bbad5600c057ab9 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 11:48:35 +0100 Subject: [PATCH 56/93] Fix bad merge --- .../session/homeserver/GetHomeServerCapabilitiesTask.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index d65e629b71e..42bba5fe884 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -133,6 +133,8 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( homeServerCapabilitiesEntity.roomVersionsJson = capabilities?.roomVersions?.let { MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it) } + homeServerCapabilitiesEntity.canUseThreading = /* capabilities?.threads?.enabled.orFalse() || */ + getVersionResult?.doesServerSupportThreads().orFalse() } if (getMediaConfigResult != null) { From 506fa729ea8f9d77357cc0f1347d3227e6b51702 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 11:50:56 +0100 Subject: [PATCH 57/93] Cleanup --- .../android/sdk/api/rendezvous/Rendezvous.kt | 29 ++++++++++-------- .../channels/ECDHRendezvousChannel.kt | 1 + .../sdk/api/rendezvous/model/Outcome.kt | 30 +++++++++++++++++++ .../sdk/api/rendezvous/model/Payload.kt | 6 ++-- .../sdk/api/rendezvous/model/PayloadType.kt | 6 ++-- .../sdk/api/rendezvous/model/Protocol.kt | 24 +++++++++++++++ 6 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index 4270d4a09ca..e467ff06e3b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -22,8 +22,10 @@ import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode +import org.matrix.android.sdk.api.rendezvous.model.Outcome import org.matrix.android.sdk.api.rendezvous.model.Payload import org.matrix.android.sdk.api.rendezvous.model.PayloadType +import org.matrix.android.sdk.api.rendezvous.model.Protocol import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport import org.matrix.android.sdk.api.session.Session @@ -68,7 +70,7 @@ class Rendezvous( Timber.tag(TAG).d("ourIntent: $ourIntent, theirIntent: $theirIntent, incompatible: $incompatible") if (incompatible) { - send(Payload(PayloadType.Finish, intent = ourIntent)) + send(Payload(PayloadType.FINISH, intent = ourIntent)) val reason = if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) { RendezvousFailureReason.OtherDeviceNotSignedIn } else { @@ -93,14 +95,14 @@ class Rendezvous( Timber.tag(TAG).i("Waiting for protocols") val protocolsResponse = receive() - if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains("login_token")) { - send(Payload(PayloadType.Finish, outcome = "unsupported")) + if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains(Protocol.LOGIN_TOKEN)) { + send(Payload(PayloadType.FINISH, outcome = Outcome.UNSUPPORTED)) Timber.tag(TAG).i("No supported protocol") cancel(RendezvousFailureReason.Unknown) return null } - send(Payload(PayloadType.Progress, protocol = "login_token")) + send(Payload(PayloadType.PROGRESS, protocol = Protocol.LOGIN_TOKEN)) return checksum } @@ -110,21 +112,23 @@ class Rendezvous( val loginToken = receive() - if (loginToken?.type == PayloadType.Finish) { + if (loginToken?.type == PayloadType.FINISH) { when (loginToken.outcome) { - "declined" -> { + Outcome.DECLINED -> { Timber.tag(TAG).i("Login declined by other device") channel.cancel(RendezvousFailureReason.UserDeclined) return null } - "unsupported" -> { + Outcome.UNSUPPORTED -> { Timber.tag(TAG).i("Not supported") channel.cancel(RendezvousFailureReason.HomeserverLacksSupport) return null } + else -> { + channel.cancel(RendezvousFailureReason.Unknown) + return null + } } - channel.cancel(RendezvousFailureReason.Unknown) - return null } val homeserver = loginToken?.homeserver ?: throw RuntimeException("No homeserver returned") @@ -141,7 +145,7 @@ class Rendezvous( val crypto = session.cryptoService() val deviceId = crypto.getMyDevice().deviceId val deviceKey = crypto.getMyDevice().fingerprint() - send(Payload(PayloadType.Progress, outcome = "success", deviceId = deviceId, deviceKey = deviceKey)) + send(Payload(PayloadType.PROGRESS, outcome = Outcome.SUCCESS, deviceId = deviceId, deviceKey = deviceKey)) // await confirmation of verification @@ -149,8 +153,9 @@ class Rendezvous( val verifyingDeviceId = verificationResponse?.verifyingDeviceId ?: throw RuntimeException("No verifying device id returned") val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { - Timber.tag(TAG).w("Verifying device $verifyingDeviceId key doesn't match: ${ - verifyingDeviceFromServer?.fingerprint()} vs ${verificationResponse.verifyingDeviceKey})" + Timber.tag(TAG).w( + "Verifying device $verifyingDeviceId key doesn't match: ${ + verifyingDeviceFromServer?.fingerprint()} vs ${verificationResponse.verifyingDeviceKey})" ) throw RuntimeException("Key from verifying device doesn't match") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 5dbac894aef..489d20e5885 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -50,6 +50,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu private const val KEY_SPEC = "AES" private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value + // n.b. we are only aver processing byte array that we have generated, so we can make assumptions about the length private fun getDecimalCodeRepresentation(byteArray: ByteArray): String { val b0 = byteArray[0].toUnsignedInt() // need unsigned byte val b1 = byteArray[1].toUnsignedInt() // need unsigned byte diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt new file mode 100644 index 00000000000..2dd6e7be28b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.rendezvous.model + +import com.squareup.moshi.Json + +enum class Outcome(val value: String) { + @Json(name = "success") + SUCCESS("success"), + + @Json(name = "declined") + DECLINED("declined"), + + @Json(name = "unsupported") + UNSUPPORTED("unsupported") +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt index 56274522322..593177e625d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt @@ -23,9 +23,9 @@ import com.squareup.moshi.JsonClass internal data class Payload( @Json val type: PayloadType, @Json val intent: RendezvousIntent? = null, - @Json val outcome: String? = null, - @Json val protocols: List? = null, - @Json val protocol: String? = null, + @Json val outcome: Outcome? = null, + @Json val protocols: List? = null, + @Json val protocol: Protocol? = null, @Json val homeserver: String? = null, @Json(name = "login_token") val loginToken: String? = null, @Json(name = "device_id") val deviceId: String? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt index 9854e7c0703..5ff4cd7cfa3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt @@ -20,11 +20,11 @@ import com.squareup.moshi.Json internal enum class PayloadType(val value: String) { @Json(name = "m.login.start") - Start("m.login.start"), + START("m.login.start"), @Json(name = "m.login.finish") - Finish("m.login.finish"), + FINISH("m.login.finish"), @Json(name = "m.login.progress") - Progress("m.login.progress") + PROGRESS("m.login.progress") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt new file mode 100644 index 00000000000..18381984a54 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.rendezvous.model + +import com.squareup.moshi.Json + +enum class Protocol(val value: String) { + @Json(name = "login_token") + LOGIN_TOKEN("login_token") +} From 4306c57236dccd50531bf20e8732031a84d6bb0e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 12:01:12 +0100 Subject: [PATCH 58/93] Thread safe use of OlmSAS --- .../channels/ECDHRendezvousChannel.kt | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 489d20e5885..ca7083b2972 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -90,43 +90,45 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } override suspend fun connect(): String { - if (olmSAS == null) { - throw RuntimeException("Channel closed") - } - val isInitiator = theirPublicKey == null - - if (isInitiator) { - Timber.tag(TAG).i("Waiting for other device to send their public key") - val res = this.receiveAsPayload() ?: throw RuntimeException("No reply from other device") - - if (res.key == null) { - throw RendezvousError( - "Unsupported algorithm: ${res.algorithm}", - RendezvousFailureReason.UnsupportedAlgorithm, + olmSAS ?.let { olmSAS -> + val isInitiator = theirPublicKey == null + + if (isInitiator) { + Timber.tag(TAG).i("Waiting for other device to send their public key") + val res = this.receiveAsPayload() ?: throw RuntimeException("No reply from other device") + + if (res.key == null) { + throw RendezvousError( + "Unsupported algorithm: ${res.algorithm}", + RendezvousFailureReason.UnsupportedAlgorithm, + ) + } + theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) + } else { + // send our public key unencrypted + Timber.tag(TAG).i("Sending public key") + send( + ECDHPayload( + algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, + key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) + ) ) } - theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) - } else { - // send our public key unencrypted - Timber.tag(TAG).i("Sending public key") - send( - ECDHPayload( - algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, - key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) - ) - ) - } - olmSAS!!.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) + synchronized(olmSAS) { + olmSAS.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) + olmSAS.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) - val initiatorKey = Base64.encodeToString(if (isInitiator) ourPublicKey else theirPublicKey, Base64.NO_WRAP) - val recipientKey = Base64.encodeToString(if (isInitiator) theirPublicKey else ourPublicKey, Base64.NO_WRAP) - val aesInfo = "${SecureRendezvousChannelAlgorithm.ECDH_V1.value}|$initiatorKey|$recipientKey" + val initiatorKey = Base64.encodeToString(if (isInitiator) ourPublicKey else theirPublicKey, Base64.NO_WRAP) + val recipientKey = Base64.encodeToString(if (isInitiator) theirPublicKey else ourPublicKey, Base64.NO_WRAP) + val aesInfo = "${SecureRendezvousChannelAlgorithm.ECDH_V1.value}|$initiatorKey|$recipientKey" - aesKey = olmSAS!!.generateShortCode(aesInfo, 32) + aesKey = olmSAS.generateShortCode(aesInfo, 32) - val rawChecksum = olmSAS!!.generateShortCode(aesInfo, 5) - return getDecimalCodeRepresentation(rawChecksum) + val rawChecksum = olmSAS.generateShortCode(aesInfo, 5) + return getDecimalCodeRepresentation(rawChecksum) + } + } ?: throw RuntimeException("Channel closed") } private suspend fun send(payload: ECDHPayload) { @@ -174,8 +176,13 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } override suspend fun close() { - olmSAS?.releaseSas() - olmSAS = null + olmSAS ?.let { + synchronized(it) { + // this does a double release check already so we don't re-check ourselves + it.releaseSas() + olmSAS = null + } + } } private fun encrypt(plainText: ByteArray): ECDHPayload { From fb86ab70a270e124b15b3e7af888381f32b78dd8 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 12:05:32 +0100 Subject: [PATCH 59/93] Comments and error mapping --- .../transports/SimpleHttpRendezvousTransport.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 03e8b0cda70..e899a64e990 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -99,9 +99,8 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo override suspend fun receive(): ByteArray? { val uri = uri ?: throw IllegalStateException("Rendezvous not set up") - var done = false val httpClient = okhttp3.OkHttpClient.Builder().build() - while (!done) { + while (true) { if (cancelled) { return null } @@ -117,8 +116,9 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo val response = httpClient.newCall(request.build()).execute() try { + // expired if (response.code == 404) { - cancel(RendezvousFailureReason.Unknown) + cancel(RendezvousFailureReason.Expired) return null } @@ -135,7 +135,8 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo return response.body?.bytes() } - done = false + // sleep for a second before polling again + // we rely on the server expiring the channel rather than checking it ourselves delay(1000) } finally { response.close() From 1976451c8164ee15b88186ae1fc6291513d158ec Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 12:23:14 +0100 Subject: [PATCH 60/93] Lint --- .../matrix/android/sdk/api/rendezvous/RendezvousChannel.kt | 2 +- .../rendezvous/transports/SimpleHttpRendezvousTransport.kt | 4 ---- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index 9d2843ce66c..31014e392d9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent /** - * Representation of a rendezvous channel such as that described by MSC3903 + * Representation of a rendezvous channel such as that described by MSC3903. */ interface RendezvousChannel { var transport: RendezvousTransport diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index e899a64e990..3e9b11a68b3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -16,8 +16,6 @@ package org.matrix.android.sdk.api.rendezvous.transports -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass import kotlinx.coroutines.delay import okhttp3.MediaType import okhttp3.Request @@ -142,8 +140,6 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo response.close() } } - - return null } override suspend fun cancel(reason: RendezvousFailureReason) { 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 8b70f61e800..36e88b284c3 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 @@ -16,7 +16,6 @@ package im.vector.app.features.login.qr -import android.content.Context import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory From eb30ef166acff6fca015b321c71ce1b10a811c49 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 12:32:40 +0100 Subject: [PATCH 61/93] Improve 404 handling --- .../rendezvous/transports/SimpleHttpRendezvousTransport.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 3e9b11a68b3..ca2a3425cd6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -75,7 +75,9 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo val response = httpClient.newCall(request.build()).execute() if (response.code == 404) { + // we set to unknown and the cancel method will rewrite the reason to expired if applicable cancel(RendezvousFailureReason.Unknown) + return } etag = response.header("etag") @@ -116,7 +118,8 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo try { // expired if (response.code == 404) { - cancel(RendezvousFailureReason.Expired) + // we set to unknown and the cancel method will rewrite the reason to expired if applicable + cancel(RendezvousFailureReason.Unknown) return null } From d616251f260515548f8b699514247b6e0a8ee9bc Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 13:41:27 +0100 Subject: [PATCH 62/93] Fix merge --- .../session/homeserver/GetHomeServerCapabilitiesTask.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index 9147c4e1cde..2c3cb440b62 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -132,8 +132,6 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( homeServerCapabilitiesEntity.roomVersionsJson = capabilities?.roomVersions?.let { MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it) } - homeServerCapabilitiesEntity.canUseThreading = /* capabilities?.threads?.enabled.orFalse() || */ - getVersionResult?.doesServerSupportThreads().orFalse() } if (getMediaConfigResult != null) { From e01ee619d3bb59d5bec0c1d0ee1bef9829584f40 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:02:25 +0100 Subject: [PATCH 63/93] Refactor error handling and report E2EE errors --- .../src/main/res/values/strings.xml | 6 + .../android/sdk/api/rendezvous/Rendezvous.kt | 140 ++++++++++-------- .../sdk/api/rendezvous/RendezvousChannel.kt | 12 +- .../api/rendezvous/RendezvousFailureReason.kt | 25 ++-- .../sdk/api/rendezvous/RendezvousTransport.kt | 7 +- .../channels/ECDHRendezvousChannel.kt | 27 +--- .../sdk/api/rendezvous/model/Outcome.kt | 8 +- .../api/rendezvous/model/RendezvousError.kt | 2 +- .../SimpleHttpRendezvousTransport.kt | 59 ++++---- .../login/qr/QrCodeLoginStatusFragment.kt | 6 + .../features/login/qr/QrCodeLoginViewModel.kt | 27 +++- 11 files changed, 172 insertions(+), 147 deletions(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 7d0173f3412..e28ebb31c62 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3383,6 +3383,12 @@ The linking wasn’t completed in the required time. The request was denied on the other device. The request failed. + A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your intent connection(s); Your device(s); + The other device is already signed in. + The other device must be signed in. + The QR code scanned is invalid. + The sign in was cancelled on the other device. + The homeserver doesn\'t support sign in with QR code. Open ${app_name} on your other device Go to Settings -> Security & Privacy -> Show All Sessions Select \'Show QR code in this device\' diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index e467ff06e3b..9ad889fca07 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.rendezvous.model.Outcome import org.matrix.android.sdk.api.rendezvous.model.Payload import org.matrix.android.sdk.api.rendezvous.model.PayloadType import org.matrix.android.sdk.api.rendezvous.model.Protocol +import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport import org.matrix.android.sdk.api.session.Session @@ -47,10 +48,16 @@ class Rendezvous( companion object { private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value - fun buildChannelFromCode(code: String, onCancelled: (reason: RendezvousFailureReason) -> Unit): Rendezvous { - val parsed = MatrixJsonParser.getMoshi().adapter(ECDHRendezvousCode::class.java).fromJson(code) ?: throw RuntimeException("Invalid code") + @Throws(RendezvousError::class) + fun buildChannelFromCode(code: String): Rendezvous { + val parsed = try { + // we rely on moshi validating the code and throwing exception if invalid JSON or doesn't + MatrixJsonParser.getMoshi().adapter(ECDHRendezvousCode::class.java).fromJson(code) + } catch (a: Throwable) { + throw RendezvousError("Invalid code", RendezvousFailureReason.InvalidCode) + } ?: throw RendezvousError("Invalid code", RendezvousFailureReason.InvalidCode) - val transport = SimpleHttpRendezvousTransport(onCancelled, parsed.rendezvous.transport.uri) + val transport = SimpleHttpRendezvousTransport(parsed.rendezvous.transport.uri) return Rendezvous( ECDHRendezvousChannel(transport, parsed.rendezvous.key), @@ -64,32 +71,30 @@ class Rendezvous( // not yet implemented: RendezvousIntent.RECIPROCATE_LOGIN_ON_EXISTING_DEVICE val ourIntent: RendezvousIntent = RendezvousIntent.LOGIN_ON_NEW_DEVICE - private suspend fun areIntentsIncompatible(): Boolean { + @Throws(RendezvousError::class) + private suspend fun checkCompatibility() { val incompatible = theirIntent == ourIntent Timber.tag(TAG).d("ourIntent: $ourIntent, theirIntent: $theirIntent, incompatible: $incompatible") if (incompatible) { + // inform the other side send(Payload(PayloadType.FINISH, intent = ourIntent)) - val reason = if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) { - RendezvousFailureReason.OtherDeviceNotSignedIn + if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) { + throw RendezvousError("The other device isn't signed in", RendezvousFailureReason.OtherDeviceNotSignedIn) } else { - RendezvousFailureReason.OtherDeviceAlreadySignedIn + throw RendezvousError("The other device is already signed in", RendezvousFailureReason.OtherDeviceAlreadySignedIn) } - channel.cancel(reason) } - - return incompatible } + @Throws(RendezvousError::class) suspend fun startAfterScanningCode(): String? { val checksum = channel.connect() Timber.tag(TAG).i("Connected to secure channel with checksum: $checksum") - if (areIntentsIncompatible()) { - return null - } + checkCompatibility() // get protocols Timber.tag(TAG).i("Waiting for protocols") @@ -97,9 +102,7 @@ class Rendezvous( if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains(Protocol.LOGIN_TOKEN)) { send(Payload(PayloadType.FINISH, outcome = Outcome.UNSUPPORTED)) - Timber.tag(TAG).i("No supported protocol") - cancel(RendezvousFailureReason.Unknown) - return null + throw RendezvousError("Unsupported protocols", RendezvousFailureReason.UnsupportedHomeserver) } send(Payload(PayloadType.PROGRESS, protocol = Protocol.LOGIN_TOKEN)) @@ -107,6 +110,7 @@ class Rendezvous( return checksum } + @Throws(RendezvousError::class) suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session? { Timber.tag(TAG).i("Waiting for login_token") @@ -115,24 +119,19 @@ class Rendezvous( if (loginToken?.type == PayloadType.FINISH) { when (loginToken.outcome) { Outcome.DECLINED -> { - Timber.tag(TAG).i("Login declined by other device") - channel.cancel(RendezvousFailureReason.UserDeclined) - return null + throw RendezvousError("Login declined by other device", RendezvousFailureReason.UserDeclined) } Outcome.UNSUPPORTED -> { - Timber.tag(TAG).i("Not supported") - channel.cancel(RendezvousFailureReason.HomeserverLacksSupport) - return null + throw RendezvousError("Homeserver lacks support", RendezvousFailureReason.UnsupportedHomeserver) } else -> { - channel.cancel(RendezvousFailureReason.Unknown) - return null + throw RendezvousError("Unknown error", RendezvousFailureReason.Unknown) } } } - val homeserver = loginToken?.homeserver ?: throw RuntimeException("No homeserver returned") - val token = loginToken.loginToken ?: throw RuntimeException("No login token returned") + val homeserver = loginToken?.homeserver ?: throw RendezvousError("No homeserver returned", RendezvousFailureReason.ProtocolError) + val token = loginToken.loginToken ?: throw RendezvousError("No login token returned", RendezvousFailureReason.ProtocolError) Timber.tag(TAG).i("Got login_token now attempting to sign in with $homeserver") @@ -140,6 +139,7 @@ class Rendezvous( return authenticationService.loginUsingQrLoginToken(hsConfig, token) } + @Throws(RendezvousError::class) suspend fun completeVerificationOnNewDevice(session: Session) { val userId = session.myUserId val crypto = session.cryptoService() @@ -148,59 +148,77 @@ class Rendezvous( send(Payload(PayloadType.PROGRESS, outcome = Outcome.SUCCESS, deviceId = deviceId, deviceKey = deviceKey)) // await confirmation of verification - val verificationResponse = receive() - val verifyingDeviceId = verificationResponse?.verifyingDeviceId ?: throw RuntimeException("No verifying device id returned") - val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) - if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { - Timber.tag(TAG).w( - "Verifying device $verifyingDeviceId key doesn't match: ${ - verifyingDeviceFromServer?.fingerprint()} vs ${verificationResponse.verifyingDeviceKey})" - ) - throw RuntimeException("Key from verifying device doesn't match") - } + if (verificationResponse?.outcome == Outcome.VERIFIED) { + val verifyingDeviceId = verificationResponse.verifyingDeviceId + ?: throw RendezvousError("No verifying device id returned", RendezvousFailureReason.ProtocolError) + val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) + if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { + Timber.tag(TAG).w( + "Verifying device $verifyingDeviceId key doesn't match: ${ + verifyingDeviceFromServer?.fingerprint() + } vs ${verificationResponse.verifyingDeviceKey})" + ) + // inform the other side + send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) + throw RendezvousError("Key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) + } - // set other device as verified - Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") - crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) + verificationResponse.masterKey?.let { masterKeyFromVerifyingDevice -> + // check master key againt what the homeserver told us + crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey()?.let { localMasterKey -> + if (localMasterKey.unpaddedBase64PublicKey != masterKeyFromVerifyingDevice) { + Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") + // inform the other side + send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) + throw RendezvousError("Master key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) + } + // set other device as verified + Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") + crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - verificationResponse.masterKey ?.let { masterKeyFromVerifyingDevice -> - // set master key as trusted - crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey()?.let { localMasterKey -> - if (localMasterKey.unpaddedBase64PublicKey == masterKeyFromVerifyingDevice) { Timber.tag(TAG).i("Setting master key as trusted") crypto.crossSigningService().markMyMasterKeyAsTrusted() - } else { - Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") - throw RuntimeException("Master key from verifying device doesn't match") - } - } ?: Timber.tag(TAG).i("No local master key") - } ?: Timber.tag(TAG).i("No master key given by verifying device") + } ?: Timber.tag(TAG).w("No local master key so not verifying") + } ?: run { + // set other device as verified anyway + Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") + crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - // request secrets from the verifying device - Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") + Timber.tag(TAG).i("No master key given by verifying device") + } + + // request secrets from the verifying device + Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") - session.sharedSecretStorageService().let { - it.requestSecret(MASTER_KEY_SSSS_NAME, verifyingDeviceId) - it.requestSecret(SELF_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) - it.requestSecret(USER_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) - it.requestSecret(KEYBACKUP_SECRET_SSSS_NAME, verifyingDeviceId) + session.sharedSecretStorageService().let { + it.requestSecret(MASTER_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(SELF_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(USER_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) + it.requestSecret(KEYBACKUP_SECRET_SSSS_NAME, verifyingDeviceId) + } + } else { + Timber.tag(TAG).i("Not doing verification") } } + @Throws(RendezvousError::class) private suspend fun receive(): Payload? { val data = channel.receive() ?: return null - return adapter.fromJson(data.toString(Charsets.UTF_8)) + val payload = try { + adapter.fromJson(data.toString(Charsets.UTF_8)) + } catch (e: Exception) { + Timber.tag(TAG).w(e, "Failed to parse payload") + throw RendezvousError("Invalid payload received", RendezvousFailureReason.Unknown) + } + + return payload } private suspend fun send(payload: Payload) { channel.send(adapter.toJson(payload).toByteArray(Charsets.UTF_8)) } - suspend fun cancel(reason: RendezvousFailureReason) { - channel.cancel(reason) - } - suspend fun close() { channel.close() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index 31014e392d9..be79569164f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -16,8 +16,7 @@ package org.matrix.android.sdk.api.rendezvous -import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode -import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent +import org.matrix.android.sdk.api.rendezvous.model.RendezvousError /** * Representation of a rendezvous channel such as that described by MSC3903. @@ -28,26 +27,25 @@ interface RendezvousChannel { /** * @returns the checksum/confirmation digits to be shown to the user */ + @Throws(RendezvousError::class) suspend fun connect(): String /** * Send a payload via the channel. * @param data payload to send */ + @Throws(RendezvousError::class) suspend fun send(data: ByteArray) /** * Receive a payload from the channel. * @returns the received payload */ + @Throws(RendezvousError::class) suspend fun receive(): ByteArray? /** - * @returns a representation of the channel that can be encoded in a QR or similar + * @returns closes the channel and cleans up */ suspend fun close() - - // In future we probably want this to be a more generic RendezvousCode but it is suffice for now - suspend fun generateCode(intent: RendezvousIntent): ECDHRendezvousCode - suspend fun cancel(reason: RendezvousFailureReason) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt index a607dc7f38f..18e625d8259 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt @@ -16,16 +16,17 @@ package org.matrix.android.sdk.api.rendezvous -enum class RendezvousFailureReason(val value: String, val canRetry: Boolean = true) { - UserDeclined("user_declined"), - OtherDeviceNotSignedIn("other_device_not_signed_in"), - OtherDeviceAlreadySignedIn("other_device_already_signed_in"), - Unknown("unknown"), - Expired("expired"), - UserCancelled("user_cancelled"), - InvalidCode("invalid_code"), - UnsupportedAlgorithm("unsupported_algorithm", false), - DataMismatch("data_mismatch"), - UnsupportedTransport("unsupported_transport", false), - HomeserverLacksSupport("homeserver_lacks_support", false) +enum class RendezvousFailureReason(val canRetry: Boolean = true) { + UserDeclined, + OtherDeviceNotSignedIn, + OtherDeviceAlreadySignedIn, + Unknown, + Expired, + UserCancelled, + InvalidCode, + UnsupportedAlgorithm(false), + UnsupportedTransport(false), + UnsupportedHomeserver(false), + ProtocolError, + E2EESecurityIssue(false) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt index de0aed7efc6..5daf9069306 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt @@ -17,13 +17,16 @@ package org.matrix.android.sdk.api.rendezvous import okhttp3.MediaType +import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails interface RendezvousTransport { var ready: Boolean - var onCancelled: ((reason: RendezvousFailureReason) -> Unit)? + @Throws(RendezvousError::class) suspend fun details(): RendezvousTransportDetails + @Throws(RendezvousError::class) suspend fun send(contentType: MediaType, data: ByteArray) + @Throws(RendezvousError::class) suspend fun receive(): ByteArray? - suspend fun cancel(reason: RendezvousFailureReason) + suspend fun close() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index ca7083b2972..9a5c5e865a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -89,13 +89,14 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu ourPublicKey = Base64.decode(olmSAS!!.publicKey, Base64.NO_WRAP) } + @Throws(RendezvousError::class) override suspend fun connect(): String { olmSAS ?.let { olmSAS -> val isInitiator = theirPublicKey == null if (isInitiator) { Timber.tag(TAG).i("Waiting for other device to send their public key") - val res = this.receiveAsPayload() ?: throw RuntimeException("No reply from other device") + val res = this.receiveAsPayload() ?: throw RendezvousError("No reply from other device", RendezvousFailureReason.ProtocolError) if (res.key == null) { throw RendezvousError( @@ -137,7 +138,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu override suspend fun send(data: ByteArray) { if (aesKey == null) { - throw RuntimeException("Shared secret not established") + throw IllegalStateException("Shared secret not established") } send(encrypt(data)) } @@ -150,31 +151,12 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu override suspend fun receive(): ByteArray? { if (aesKey == null) { - throw RuntimeException("Shared secret not established") + throw IllegalStateException("Shared secret not established") } val payload = receiveAsPayload() ?: return null return decrypt(payload) } - override suspend fun generateCode(intent: RendezvousIntent): ECDHRendezvousCode { - return ECDHRendezvousCode( - intent, - rendezvous = ECDHRendezvous( - transport.details() as SimpleHttpRendezvousTransportDetails, - SecureRendezvousChannelAlgorithm.ECDH_V1, - key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) - ) - ) - } - - override suspend fun cancel(reason: RendezvousFailureReason) { - try { - transport.cancel(reason) - } finally { - close() - } - } - override suspend fun close() { olmSAS ?.let { synchronized(it) { @@ -183,6 +165,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu olmSAS = null } } + transport.close() } private fun encrypt(plainText: ByteArray): ECDHPayload { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt index 2dd6e7be28b..2ef24e9cb79 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt @@ -26,5 +26,11 @@ enum class Outcome(val value: String) { DECLINED("declined"), @Json(name = "unsupported") - UNSUPPORTED("unsupported") + UNSUPPORTED("unsupported"), + + @Json(name = "verified") + VERIFIED("verified"), + + @Json(name = "e2ee_security_error") + E2EE_SECURITY_ERROR("e2ee_security_error") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt index fec55ffb67c..c52b11a3226 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt @@ -18,4 +18,4 @@ package org.matrix.android.sdk.api.rendezvous.model import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason -class RendezvousError(val description: String, val reason: RendezvousFailureReason) : RuntimeException(description) +class RendezvousError(val description: String, val reason: RendezvousFailureReason) : Exception(description) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index ca2a3425cd6..fa0e5d8e2a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -23,6 +23,7 @@ import okhttp3.RequestBody.Companion.toRequestBody import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import org.matrix.android.sdk.api.rendezvous.RendezvousTransport +import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransportDetails import timber.log.Timber @@ -32,7 +33,7 @@ import java.util.Date /** * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 */ -class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: RendezvousFailureReason) -> Unit)?, rendezvousUri: String?) : RendezvousTransport { +class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTransport { companion object { private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName, LoggerTag.RENDEZVOUS).value } @@ -55,7 +56,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo override suspend fun send(contentType: MediaType, data: ByteArray) { if (cancelled) { - return + throw IllegalStateException("Rendezvous cancelled") } val method = if (uri != null) "PUT" else "POST" @@ -75,9 +76,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo val response = httpClient.newCall(request.build()).execute() if (response.code == 404) { - // we set to unknown and the cancel method will rewrite the reason to expired if applicable - cancel(RendezvousFailureReason.Unknown) - return + throw get404Error() } etag = response.header("etag") @@ -98,12 +97,12 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo } override suspend fun receive(): ByteArray? { + if (cancelled) { + throw IllegalStateException("Rendezvous cancelled") + } val uri = uri ?: throw IllegalStateException("Rendezvous not set up") val httpClient = okhttp3.OkHttpClient.Builder().build() while (true) { - if (cancelled) { - return null - } Timber.tag(TAG).i("Polling: $uri after etag $etag") val request = Request.Builder() .url(uri) @@ -118,9 +117,7 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo try { // expired if (response.code == 404) { - // we set to unknown and the cancel method will rewrite the reason to expired if applicable - cancel(RendezvousFailureReason.Unknown) - return null + throw get404Error() } // rely on server expiring the channel rather than checking ourselves @@ -145,31 +142,27 @@ class SimpleHttpRendezvousTransport(override var onCancelled: ((reason: Rendezvo } } - override suspend fun cancel(reason: RendezvousFailureReason) { - var mappedReason = reason - Timber.tag(TAG).i("$expiresAt") - if (mappedReason == RendezvousFailureReason.Unknown && - expiresAt != null && Date() > expiresAt - ) { - mappedReason = RendezvousFailureReason.Expired - } + private fun get404Error(): RendezvousError { + return if (expiresAt != null && Date() > expiresAt) + RendezvousError("Expired", RendezvousFailureReason.Expired) + else + RendezvousError("Received unexpected 404", RendezvousFailureReason.Unknown) + } + override suspend fun close() { cancelled = true ready = false - onCancelled ?.let { it(mappedReason) } - - if (mappedReason == RendezvousFailureReason.UserDeclined) { - uri ?.let { - try { - val httpClient = okhttp3.OkHttpClient.Builder().build() - val request = Request.Builder() - .url(it) - .delete() - .build() - httpClient.newCall(request).execute() - } catch (e: Exception) { - Timber.tag(TAG).w(e, "Failed to delete channel") - } + + uri ?.let { + try { + val httpClient = okhttp3.OkHttpClient.Builder().build() + val request = Request.Builder() + .url(it) + .delete() + .build() + httpClient.newCall(request).execute() + } catch (e: Throwable) { + Timber.tag(TAG).w(e, "Failed to delete channel") } } } 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 0691e2367e1..617d620c277 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 @@ -70,8 +70,14 @@ class QrCodeLoginStatusFragment : VectorBaseFragment getString(R.string.qr_code_login_header_failed_device_is_not_supported_description) + RendezvousFailureReason.UnsupportedHomeserver -> getString(R.string.qr_code_login_header_failed_homeserver_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) + RendezvousFailureReason.E2EESecurityIssue -> getString(R.string.qr_code_login_header_failed_e2ee_security_issue_description) + RendezvousFailureReason.OtherDeviceAlreadySignedIn -> getString(R.string.qr_code_login_header_failed_other_device_already_signed_in_description) + RendezvousFailureReason.OtherDeviceNotSignedIn -> getString(R.string.qr_code_login_header_failed_other_device_not_signed_in_description) + RendezvousFailureReason.InvalidCode -> getString(R.string.qr_code_login_header_failed_invalid_qr_code_description) + RendezvousFailureReason.UserCancelled -> getString(R.string.qr_code_login_header_failed_user_cancelled_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 9d4e5e98701..7f95fad4851 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 @@ -30,6 +30,7 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.rendezvous.Rendezvous import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason +import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import timber.log.Timber class QrCodeLoginViewModel @AssistedInject constructor( @@ -38,14 +39,15 @@ class QrCodeLoginViewModel @AssistedInject constructor( private val activeSessionHolder: ActiveSessionHolder, private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase ) : VectorViewModel(initialState) { - val TAG: String = QrCodeLoginViewModel::class.java.simpleName @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { override fun create(initialState: QrCodeLoginViewState): QrCodeLoginViewModel } - companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() { + val TAG: String = QrCodeLoginViewModel::class.java.simpleName + } override fun handle(action: QrCodeLoginAction) { when (action) { @@ -71,9 +73,14 @@ class QrCodeLoginViewModel @AssistedInject constructor( private fun handleOnQrCodeScanned(action: QrCodeLoginAction.OnQrCodeScanned) { Timber.tag(TAG).d("Scanned code: ${action.qrCode}") - val rendezvous = Rendezvous.buildChannelFromCode(action.qrCode) { reason -> - Timber.tag(TAG).d("Rendezvous cancelled: $reason") - onFailed(reason) + val rendezvous = try { Rendezvous.buildChannelFromCode(action.qrCode) } catch (t: Throwable) { + Timber.tag(TAG).e(t, "Error occurred during sign in") + if (t is RendezvousError) { + onFailed(t.reason) + } else { + onFailed(RendezvousFailureReason.Unknown) + } + return } setState { @@ -103,9 +110,13 @@ class QrCodeLoginViewModel @AssistedInject constructor( _viewEvents.post(QrCodeLoginViewEvents.NavigateToHomeScreen) } } - } catch (failure: Throwable) { - Timber.tag(TAG).e(failure, "Error occurred during sign in") - onFailed(RendezvousFailureReason.Unknown) + } catch (t: Throwable) { + Timber.tag(TAG).e(t, "Error occurred during sign in") + if (t is RendezvousError) { + onFailed(t.reason) + } else { + onFailed(RendezvousFailureReason.Unknown) + } } } } From 29065b819f6be245a9e78ca3ba7666766d0ce28a Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:03:47 +0100 Subject: [PATCH 64/93] Remove unused class --- .../rendezvous/model/EmbeddedRendezvous.kt | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt deleted file mode 100644 index 785ce1fed7f..00000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/EmbeddedRendezvous.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 The Matrix.org Foundation C.I.C. - * - * 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 org.matrix.android.sdk.api.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -open class EmbeddedRendezvous( - @Json(name = "transport") val transport: RendezvousTransportDetails, - @Json(name = "algorithm") val algorithm: SecureRendezvousChannelAlgorithm -) From e877feed6eedc22792a24188e3fa37099d5f1f93 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:06:08 +0100 Subject: [PATCH 65/93] Add @JsonClass to all enums --- .../java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt | 2 ++ .../org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt | 2 ++ .../org/matrix/android/sdk/api/rendezvous/model/Protocol.kt | 2 ++ .../matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt | 2 ++ .../android/sdk/api/rendezvous/model/RendezvousTransportType.kt | 2 ++ .../api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt | 2 ++ 6 files changed, 12 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt index 2ef24e9cb79..a0b2cb31b4a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt @@ -17,7 +17,9 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +@JsonClass(generateAdapter = true) enum class Outcome(val value: String) { @Json(name = "success") SUCCESS("success"), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt index 5ff4cd7cfa3..9e0dbd95624 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt @@ -17,7 +17,9 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +@JsonClass(generateAdapter = true) internal enum class PayloadType(val value: String) { @Json(name = "m.login.start") START("m.login.start"), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt index 18381984a54..3442d4abf4c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt @@ -17,7 +17,9 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +@JsonClass(generateAdapter = true) enum class Protocol(val value: String) { @Json(name = "login_token") LOGIN_TOKEN("login_token") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt index 1c070599b0e..8ce64302120 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt @@ -17,7 +17,9 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +@JsonClass(generateAdapter = true) enum class RendezvousIntent { @Json(name = "login.start") LOGIN_ON_NEW_DEVICE, @Json(name = "login.reciprocate") RECIPROCATE_LOGIN_ON_EXISTING_DEVICE diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt index 9c3e44f25b6..2814cad77c4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt @@ -17,7 +17,9 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +@JsonClass(generateAdapter = true) enum class RendezvousTransportType(val value: String) { @Json(name = "http.v1") MSC3886_SIMPLE_HTTP_V1("http.v1") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt index 9a9db58a41e..d9f73a0b993 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt @@ -17,7 +17,9 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +@JsonClass(generateAdapter = true) enum class SecureRendezvousChannelAlgorithm(val value: String) { @Json(name = "m.rendezvous.v1.curve25519-aes-sha256") ECDH_V1("m.rendezvous.v1.curve25519-aes-sha256") } From 623277e31ff94a4deac05b3bc297b95f52c85441 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:13:49 +0100 Subject: [PATCH 66/93] Lint --- .../sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt | 4 ---- .../transports/SimpleHttpRendezvousTransport.kt | 9 +++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 9a5c5e865a3..2f368d65206 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -24,12 +24,8 @@ import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.rendezvous.RendezvousChannel import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason import org.matrix.android.sdk.api.rendezvous.RendezvousTransport -import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvous -import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm -import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransportDetails import org.matrix.android.sdk.api.util.MatrixJsonParser import org.matrix.android.sdk.internal.extensions.toUnsignedInt import org.matrix.olm.OlmSAS diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index fa0e5d8e2a3..50cebae12dd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -143,10 +143,11 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor } private fun get404Error(): RendezvousError { - return if (expiresAt != null && Date() > expiresAt) - RendezvousError("Expired", RendezvousFailureReason.Expired) - else - RendezvousError("Received unexpected 404", RendezvousFailureReason.Unknown) + if (expiresAt != null && Date() > expiresAt) { + return RendezvousError("Expired", RendezvousFailureReason.Expired) + } + + return RendezvousError("Received unexpected 404", RendezvousFailureReason.Unknown) } override suspend fun close() { From 3d37e0b2a557cf121efe01935a5a2980c9177ff2 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:19:03 +0100 Subject: [PATCH 67/93] Fix enum JsonClass generateAdapter = false --- .../java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt | 2 +- .../org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt | 2 +- .../org/matrix/android/sdk/api/rendezvous/model/Protocol.kt | 2 +- .../matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt | 2 +- .../android/sdk/api/rendezvous/model/RendezvousTransportType.kt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt index a0b2cb31b4a..0ebd1f88b34 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -@JsonClass(generateAdapter = true) +@JsonClass(generateAdapter = false) enum class Outcome(val value: String) { @Json(name = "success") SUCCESS("success"), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt index 9e0dbd95624..33beb1f5250 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -@JsonClass(generateAdapter = true) +@JsonClass(generateAdapter = false) internal enum class PayloadType(val value: String) { @Json(name = "m.login.start") START("m.login.start"), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt index 3442d4abf4c..7c020da641d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -@JsonClass(generateAdapter = true) +@JsonClass(generateAdapter = false) enum class Protocol(val value: String) { @Json(name = "login_token") LOGIN_TOKEN("login_token") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt index 8ce64302120..65037e1252e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -@JsonClass(generateAdapter = true) +@JsonClass(generateAdapter = false) enum class RendezvousIntent { @Json(name = "login.start") LOGIN_ON_NEW_DEVICE, @Json(name = "login.reciprocate") RECIPROCATE_LOGIN_ON_EXISTING_DEVICE diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt index 2814cad77c4..aa578e36605 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -@JsonClass(generateAdapter = true) +@JsonClass(generateAdapter = false) enum class RendezvousTransportType(val value: String) { @Json(name = "http.v1") MSC3886_SIMPLE_HTTP_V1("http.v1") } From 552fb9de9a30d8295256329f0c63fc525d1031cb Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:24:01 +0100 Subject: [PATCH 68/93] Improved comment around QR generation --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 7f95fad4851..69deb44c707 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 @@ -147,9 +147,10 @@ class QrCodeLoginViewModel @AssistedInject constructor( } /** - * TODO. UI test purpose. Fixme accordingly. + * QR code generation is not currently supported and this is a placeholder for future + * functionality. */ private fun generateQrCodeData(): String { - return "TODO" + return "NOT SUPPORTED" } } From b2dc0b33b5fb07bf47a5cc697589479d138e5515 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 17 Oct 2022 18:32:35 +0300 Subject: [PATCH 69/93] Implement try again button action. --- .../GetHomeServerCapabilitiesTask.kt | 1 + .../features/login/qr/QrCodeLoginAction.kt | 1 + .../features/login/qr/QrCodeLoginActivity.kt | 42 +++++++++++-------- .../login/qr/QrCodeLoginStatusFragment.kt | 7 ++++ .../login/qr/QrCodeLoginViewEvents.kt | 1 + .../features/login/qr/QrCodeLoginViewModel.kt | 5 +++ 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index 2c3cb440b62..4b56d8e756c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.wellknown.WellknownResult +import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orTrue import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.internal.auth.version.Versions diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt index 8854d0720fc..5ea46d3dcd2 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt @@ -22,4 +22,5 @@ sealed class QrCodeLoginAction : VectorViewModelAction { data class OnQrCodeScanned(val qrCode: String) : QrCodeLoginAction() object GenerateQrCode : QrCodeLoginAction() object ShowQrCode : QrCodeLoginAction() + object TryAgain : QrCodeLoginAction() } diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt index 2f302618906..c9b8ae00804 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt @@ -38,28 +38,31 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { super.onCreate(savedInstanceState) views.toolbar.visibility = View.GONE - val qrCodeLoginArgs: QrCodeLoginArgs? = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) if (isFirstCreation()) { - when (qrCodeLoginArgs?.loginType) { - QrCodeLoginType.LOGIN -> { + navigateToInitialFragment() + } + + observeViewEvents() + } + + private fun navigateToInitialFragment() { + val qrCodeLoginArgs: QrCodeLoginArgs? = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) + when (qrCodeLoginArgs?.loginType) { + QrCodeLoginType.LOGIN -> { + showInstructionsFragment(qrCodeLoginArgs) + } + QrCodeLoginType.LINK_A_DEVICE -> { + if (qrCodeLoginArgs.showQrCodeImmediately) { + handleNavigateToShowQrCodeScreen() + } else { showInstructionsFragment(qrCodeLoginArgs) } - QrCodeLoginType.LINK_A_DEVICE -> { - if (qrCodeLoginArgs.showQrCodeImmediately) { - handleNavigateToShowQrCodeScreen() - } else { - showInstructionsFragment(qrCodeLoginArgs) - } - } - null -> { - Timber.i("QrCodeLoginArgs is null. This is not expected.") - finish() - return - } + } + null -> { + Timber.i("QrCodeLoginArgs is null. This is not expected.") + finish() } } - - observeViewEvents() } private fun showInstructionsFragment(qrCodeLoginArgs: QrCodeLoginArgs) { @@ -77,10 +80,15 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { QrCodeLoginViewEvents.NavigateToStatusScreen -> handleNavigateToStatusScreen() QrCodeLoginViewEvents.NavigateToShowQrCodeScreen -> handleNavigateToShowQrCodeScreen() QrCodeLoginViewEvents.NavigateToHomeScreen -> handleNavigateToHomeScreen() + QrCodeLoginViewEvents.NavigateToInitialScreen -> handleNavigateToInitialScreen() } } } + private fun handleNavigateToInitialScreen() { + navigateToInitialFragment() + } + private fun handleNavigateToShowQrCodeScreen() { addFragment( views.container, 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 617d620c277..097c956f2c6 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 @@ -42,6 +42,13 @@ class QrCodeLoginStatusFragment : VectorBaseFragment handleOnQrCodeScanned(action) QrCodeLoginAction.GenerateQrCode -> handleQrCodeViewStarted() QrCodeLoginAction.ShowQrCode -> handleShowQrCode() + QrCodeLoginAction.TryAgain -> handleTryAgain() } } + private fun handleTryAgain() { + _viewEvents.post(QrCodeLoginViewEvents.NavigateToInitialScreen) + } + private fun handleShowQrCode() { _viewEvents.post(QrCodeLoginViewEvents.NavigateToShowQrCodeScreen) } From 1863e4c3efe867faa0e30d001fadf33885fbe08d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:34:51 +0100 Subject: [PATCH 70/93] Use unstable prefixes --- .../org/matrix/android/sdk/api/rendezvous/model/Protocol.kt | 4 ++-- .../sdk/api/rendezvous/model/RendezvousTransportType.kt | 3 ++- .../api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt index 7c020da641d..6fce2fa11c4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt @@ -21,6 +21,6 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = false) enum class Protocol(val value: String) { - @Json(name = "login_token") - LOGIN_TOKEN("login_token") + @Json(name = "org.matrix.msc3906.login_token") + LOGIN_TOKEN("org.matrix.msc3906.login_token") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt index aa578e36605..6fca7efa714 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt @@ -21,5 +21,6 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = false) enum class RendezvousTransportType(val value: String) { - @Json(name = "http.v1") MSC3886_SIMPLE_HTTP_V1("http.v1") + @Json(name = "org.matrix.msc3886.http.v1") + MSC3886_SIMPLE_HTTP_V1("org.matrix.msc3886.http.v1") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt index d9f73a0b993..ab58179f5a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt @@ -21,5 +21,6 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) enum class SecureRendezvousChannelAlgorithm(val value: String) { - @Json(name = "m.rendezvous.v1.curve25519-aes-sha256") ECDH_V1("m.rendezvous.v1.curve25519-aes-sha256") + @Json(name = "org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") + ECDH_V1("org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") } From d3e61a23a9a23ea75fe57f5b4c01cf25ea642558 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 17:29:45 +0100 Subject: [PATCH 71/93] Fix generator --- .../api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt index ab58179f5a7..75f0024fdac 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.rendezvous.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -@JsonClass(generateAdapter = true) +@JsonClass(generateAdapter = false) enum class SecureRendezvousChannelAlgorithm(val value: String) { @Json(name = "org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") ECDH_V1("org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") From 41dbdbcd7bc5c492620612f4e7f3bcd05c89e7e1 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 17:30:54 +0100 Subject: [PATCH 72/93] Lint --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ed2fb6e0f5f..2647c5974dc 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 @@ -37,7 +37,7 @@ class QrCodeLoginViewModel @AssistedInject constructor( @Assisted private val initialState: QrCodeLoginViewState, private val authenticationService: AuthenticationService, private val activeSessionHolder: ActiveSessionHolder, - private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase + private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase, ) : VectorViewModel(initialState) { @AssistedFactory From 8c8190202f9792b708d623ef5944016220edc69c Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 17:31:14 +0100 Subject: [PATCH 73/93] Better function name --- .../vector/app/features/login/qr/QrCodeLoginStatusFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 097c956f2c6..6ef261e6d90 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 @@ -66,14 +66,14 @@ class QrCodeLoginStatusFragment : VectorBaseFragment getString(R.string.qr_code_login_header_failed_device_is_not_supported_description) From 8f4d998362d4a89ea0aed78d4abe7c7e2738e9f2 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 17:33:43 +0100 Subject: [PATCH 74/93] Lint --- .../internal/session/homeserver/GetHomeServerCapabilitiesTask.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index 4b56d8e756c..2c3cb440b62 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -20,7 +20,6 @@ import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.wellknown.WellknownResult -import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orTrue import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.internal.auth.version.Versions From 6d17d51fe9e7a5483288f833106f4e572fafcb46 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 17:36:35 +0100 Subject: [PATCH 75/93] remove nullability --- .../android/sdk/api/rendezvous/Rendezvous.kt | 4 ++-- .../features/login/qr/QrCodeLoginViewModel.kt | 22 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index 9ad889fca07..e41a72db94d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -89,7 +89,7 @@ class Rendezvous( } @Throws(RendezvousError::class) - suspend fun startAfterScanningCode(): String? { + suspend fun startAfterScanningCode(): String { val checksum = channel.connect() Timber.tag(TAG).i("Connected to secure channel with checksum: $checksum") @@ -111,7 +111,7 @@ class Rendezvous( } @Throws(RendezvousError::class) - suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session? { + suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session { Timber.tag(TAG).i("Waiting for login_token") val loginToken = receive() 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 2647c5974dc..4134dc8ab20 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 @@ -100,21 +100,19 @@ class QrCodeLoginViewModel @AssistedInject constructor( try { val confirmationCode = rendezvous.startAfterScanningCode() Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") - confirmationCode?.let { - onConnectionEstablished(it) - val session = rendezvous.waitForLoginOnNewDevice(authenticationService) - onSigningIn() - session?.let { - activeSessionHolder.setActiveSession(session) - authenticationService.reset() - configureAndStartSessionUseCase.execute(session) + onConnectionEstablished(confirmationCode) - rendezvous.completeVerificationOnNewDevice(session) + val session = rendezvous.waitForLoginOnNewDevice(authenticationService) + onSigningIn() - _viewEvents.post(QrCodeLoginViewEvents.NavigateToHomeScreen) - } - } + activeSessionHolder.setActiveSession(session) + authenticationService.reset() + configureAndStartSessionUseCase.execute(session) + + rendezvous.completeVerificationOnNewDevice(session) + + _viewEvents.post(QrCodeLoginViewEvents.NavigateToHomeScreen) } catch (t: Throwable) { Timber.tag(TAG).e(t, "Error occurred during sign in") if (t is RendezvousError) { From 8cfe6b13639158011e63b40e2592aa770316e5a0 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 23:46:28 +0100 Subject: [PATCH 76/93] Wording updates --- library/ui-strings/src/main/res/values/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index e28ebb31c62..7fe8dd8d08f 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3386,12 +3386,12 @@ A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your intent connection(s); Your device(s); The other device is already signed in. The other device must be signed in. - The QR code scanned is invalid. + That QR code is invalid. The sign in was cancelled on the other device. The homeserver doesn\'t support sign in with QR code. - Open ${app_name} on your other device - Go to Settings -> Security & Privacy -> Show All Sessions - Select \'Show QR code in this device\' + Open the app on your other device + Go to Settings -> Security & Privacy + Select \'Show QR code\' Start at the sign in screen Select \'Sign in with QR code\' Start at the sign in screen From cf1c7515fb87283915412c7718917a0d9902221f Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 00:35:13 +0100 Subject: [PATCH 77/93] Automatically try again on partial failed QR scan --- .../features/login/qr/QrCodeLoginInstructionsFragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt index efd23f25302..40fcbbbb852 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt @@ -63,6 +63,7 @@ class QrCodeLoginInstructionsFragment : VectorBaseFragment From a3126b0026dc70ad6c9e2cf12a11fe3ba0944179 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 00:35:35 +0100 Subject: [PATCH 78/93] Progress to status screen on failure --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) 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 4134dc8ab20..1a8ed945c05 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 @@ -125,6 +125,8 @@ class QrCodeLoginViewModel @AssistedInject constructor( } private fun onFailed(reason: RendezvousFailureReason) { + _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) + setState { copy( connectionStatus = QrCodeLoginConnectionStatus.Failed(reason, reason.canRetry) From 8a62dfb34aca1c3ab52d05d240ea74cc2b5a6d54 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 00:35:43 +0100 Subject: [PATCH 79/93] Lint --- .../matrix/android/sdk/api/rendezvous/RendezvousTransport.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt index 5daf9069306..81632e951a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt @@ -22,11 +22,15 @@ import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails interface RendezvousTransport { var ready: Boolean + @Throws(RendezvousError::class) suspend fun details(): RendezvousTransportDetails + @Throws(RendezvousError::class) suspend fun send(contentType: MediaType, data: ByteArray) + @Throws(RendezvousError::class) suspend fun receive(): ByteArray? + suspend fun close() } From f297117df2fe66c61e8589e73bc88cf7a99586bb Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 08:48:28 +0100 Subject: [PATCH 80/93] Use mutex --- .../channels/ECDHRendezvousChannel.kt | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 2f368d65206..19c46db34d3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -19,6 +19,8 @@ package org.matrix.android.sdk.api.rendezvous.channels import android.util.Base64 import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import okhttp3.MediaType.Companion.toMediaType import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.rendezvous.RendezvousChannel @@ -71,6 +73,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu @Json val iv: String? = null ) + private var olmSASMutex = Mutex() private var olmSAS: OlmSAS? private val ourPublicKey: ByteArray private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) @@ -87,45 +90,44 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu @Throws(RendezvousError::class) override suspend fun connect(): String { - olmSAS ?.let { olmSAS -> - val isInitiator = theirPublicKey == null + val sas = olmSAS ?: throw RendezvousError("Channel closed", RendezvousFailureReason.Unknown) + val isInitiator = theirPublicKey == null - if (isInitiator) { - Timber.tag(TAG).i("Waiting for other device to send their public key") - val res = this.receiveAsPayload() ?: throw RendezvousError("No reply from other device", RendezvousFailureReason.ProtocolError) + if (isInitiator) { + Timber.tag(TAG).i("Waiting for other device to send their public key") + val res = this.receiveAsPayload() ?: throw RendezvousError("No reply from other device", RendezvousFailureReason.ProtocolError) - if (res.key == null) { - throw RendezvousError( - "Unsupported algorithm: ${res.algorithm}", - RendezvousFailureReason.UnsupportedAlgorithm, - ) - } - theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) - } else { - // send our public key unencrypted - Timber.tag(TAG).i("Sending public key") - send( - ECDHPayload( - algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, - key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) - ) + if (res.key == null) { + throw RendezvousError( + "Unsupported algorithm: ${res.algorithm}", + RendezvousFailureReason.UnsupportedAlgorithm, ) } + theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) + } else { + // send our public key unencrypted + Timber.tag(TAG).i("Sending public key") + send( + ECDHPayload( + algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, + key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) + ) + ) + } - synchronized(olmSAS) { - olmSAS.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) - olmSAS.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) + olmSASMutex.withLock { + sas.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) + sas.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) - val initiatorKey = Base64.encodeToString(if (isInitiator) ourPublicKey else theirPublicKey, Base64.NO_WRAP) - val recipientKey = Base64.encodeToString(if (isInitiator) theirPublicKey else ourPublicKey, Base64.NO_WRAP) - val aesInfo = "${SecureRendezvousChannelAlgorithm.ECDH_V1.value}|$initiatorKey|$recipientKey" + val initiatorKey = Base64.encodeToString(if (isInitiator) ourPublicKey else theirPublicKey, Base64.NO_WRAP) + val recipientKey = Base64.encodeToString(if (isInitiator) theirPublicKey else ourPublicKey, Base64.NO_WRAP) + val aesInfo = "${SecureRendezvousChannelAlgorithm.ECDH_V1.value}|$initiatorKey|$recipientKey" - aesKey = olmSAS.generateShortCode(aesInfo, 32) + aesKey = sas.generateShortCode(aesInfo, 32) - val rawChecksum = olmSAS.generateShortCode(aesInfo, 5) - return getDecimalCodeRepresentation(rawChecksum) - } - } ?: throw RuntimeException("Channel closed") + val rawChecksum = sas.generateShortCode(aesInfo, 5) + return getDecimalCodeRepresentation(rawChecksum) + } } private suspend fun send(payload: ECDHPayload) { @@ -154,12 +156,11 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } override suspend fun close() { - olmSAS ?.let { - synchronized(it) { - // this does a double release check already so we don't re-check ourselves - it.releaseSas() - olmSAS = null - } + val sas = olmSAS ?: throw IllegalStateException("Channel already closed") + olmSASMutex.withLock { + // this does a double release check already so we don't re-check ourselves + sas.releaseSas() + olmSAS = null } transport.close() } From a1d2944c324c37bdcf9c92e0ec02864ce6781d71 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 09:08:40 +0100 Subject: [PATCH 81/93] Always check master key when provided by verifying device --- .../android/sdk/api/rendezvous/Rendezvous.kt | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt index e41a72db94d..f724ac4b621 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt @@ -165,21 +165,25 @@ class Rendezvous( } verificationResponse.masterKey?.let { masterKeyFromVerifyingDevice -> - // check master key againt what the homeserver told us - crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey()?.let { localMasterKey -> - if (localMasterKey.unpaddedBase64PublicKey != masterKeyFromVerifyingDevice) { - Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") - // inform the other side - send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) - throw RendezvousError("Master key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) - } - // set other device as verified - Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") - crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - - Timber.tag(TAG).i("Setting master key as trusted") - crypto.crossSigningService().markMyMasterKeyAsTrusted() - } ?: Timber.tag(TAG).w("No local master key so not verifying") + // verifying device provided us with a master key, so use it to check integrity + + // see what the homeserver told us + val localMasterKey = crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey() + + // n.b. if no local master key this is a problem, as well as it not matching + if (localMasterKey?.unpaddedBase64PublicKey != masterKeyFromVerifyingDevice) { + Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") + // inform the other side + send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) + throw RendezvousError("Master key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) + } + + // set other device as verified + Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") + crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) + + Timber.tag(TAG).i("Setting master key as trusted") + crypto.crossSigningService().markMyMasterKeyAsTrusted() } ?: run { // set other device as verified anyway Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") From 57a8dd4a1f61b50e180830d96264d5c3b1f1fe72 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 09:31:13 +0100 Subject: [PATCH 82/93] Whitespce --- .../sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt | 4 ++-- .../transports/SimpleHttpRendezvousTransport.kt | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 19c46db34d3..f7da0efa92e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -81,7 +81,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu private var aesKey: ByteArray? = null init { - theirPublicKeyBase64 ?.let { + theirPublicKeyBase64?.let { theirPublicKey = Base64.decode(it, Base64.NO_WRAP) } olmSAS = OlmSAS() @@ -142,7 +142,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu } private suspend fun receiveAsPayload(): ECDHPayload? { - transport.receive()?.toString(Charsets.UTF_8) ?.let { + transport.receive()?.toString(Charsets.UTF_8)?.let { return ecdhAdapter.fromJson(it) } ?: return null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 50cebae12dd..3f7cfe786e6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -69,7 +69,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor .method(method, data.toRequestBody()) .header("content-type", contentType.toString()) - etag ?.let { + etag?.let { request.header("if-match", it) } @@ -85,7 +85,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor if (method == "POST") { val location = response.header("location") ?: throw RuntimeException("No rendezvous URI found in response") - response.header("expires") ?.let { + response.header("expires")?.let { val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz") expiresAt = format.parse(it) } @@ -108,7 +108,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor .url(uri) .get() - etag ?.let { + etag?.let { request.header("if-none-match", it) } @@ -154,7 +154,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor cancelled = true ready = false - uri ?.let { + uri?.let { try { val httpClient = okhttp3.OkHttpClient.Builder().build() val request = Request.Builder() From 376cd1cb367c8fa3d3b9f9f2da898a56e0f3636e Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 09:34:28 +0100 Subject: [PATCH 83/93] Missing throws --- .../api/rendezvous/transports/SimpleHttpRendezvousTransport.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 3f7cfe786e6..7a5cbe54245 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -54,6 +54,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor return SimpleHttpRendezvousTransportDetails(uri) } + @Throws(RendezvousError::class) override suspend fun send(contentType: MediaType, data: ByteArray) { if (cancelled) { throw IllegalStateException("Rendezvous cancelled") @@ -96,6 +97,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor } } + @Throws(RendezvousError::class) override suspend fun receive(): ByteArray? { if (cancelled) { throw IllegalStateException("Rendezvous cancelled") From 9fb0db3129ff6521ac86aba4bee29c12e6d45d5b Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:07:12 +0100 Subject: [PATCH 84/93] Update library/ui-strings/src/main/res/values/strings.xml Co-authored-by: Benoit Marty --- library/ui-strings/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 7fe8dd8d08f..7b6b9b914d3 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3383,7 +3383,7 @@ The linking wasn’t completed in the required time. The request was denied on the other device. The request failed. - A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your intent connection(s); Your device(s); + A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your internet connection(s); Your device(s); The other device is already signed in. The other device must be signed in. That QR code is invalid. From 0d1df3f66e5587ba299b909183fa464673694489 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:08:09 +0100 Subject: [PATCH 85/93] Update matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt Co-authored-by: Benoit Marty --- .../org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index be79569164f..9976c7a8e42 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -45,7 +45,7 @@ interface RendezvousChannel { suspend fun receive(): ByteArray? /** - * @returns closes the channel and cleans up + * Closes the channel and cleans up. */ suspend fun close() } From 8530f8f28049dae1be38c2cf0503e8cfac04f2f6 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:09:06 +0100 Subject: [PATCH 86/93] Update matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt Co-authored-by: Benoit Marty --- .../sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index f7da0efa92e..b21d89059b9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -73,7 +73,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu @Json val iv: String? = null ) - private var olmSASMutex = Mutex() + private val olmSASMutex = Mutex() private var olmSAS: OlmSAS? private val ourPublicKey: ByteArray private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) From a83fb8bf83c10759c1e25e126e1fae5319cc4dad Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:09:17 +0100 Subject: [PATCH 87/93] Update matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt Co-authored-by: Benoit Marty --- .../org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt index 9976c7a8e42..0956a5b0a0a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt @@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.rendezvous.model.RendezvousError * Representation of a rendezvous channel such as that described by MSC3903. */ interface RendezvousChannel { - var transport: RendezvousTransport + val transport: RendezvousTransport /** * @returns the checksum/confirmation digits to be shown to the user From 916ae654e790bc001a1f5f86ef30d32657da952d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:11:41 +0100 Subject: [PATCH 88/93] Don't log whole QR code --- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1a8ed945c05..9bf3e955d3e 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 @@ -76,7 +76,7 @@ class QrCodeLoginViewModel @AssistedInject constructor( } private fun handleOnQrCodeScanned(action: QrCodeLoginAction.OnQrCodeScanned) { - Timber.tag(TAG).d("Scanned code: ${action.qrCode}") + Timber.tag(TAG).d("Scanned code of length ${action.qrCode.length}") val rendezvous = try { Rendezvous.buildChannelFromCode(action.qrCode) } catch (t: Throwable) { Timber.tag(TAG).e(t, "Error occurred during sign in") From 811d6d87ae50595726494abe772a8931d27da0c2 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:23:21 +0100 Subject: [PATCH 89/93] Reuse getDecimalCodeRepresentation from SAS instead of duplicating code --- .../channels/ECDHRendezvousChannel.kt | 17 ++---- .../SASDefaultVerificationTransaction.kt | 54 +++++++++---------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index b21d89059b9..6c45aacfaaa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.rendezvous.RendezvousTransport import org.matrix.android.sdk.api.rendezvous.model.RendezvousError import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm import org.matrix.android.sdk.api.util.MatrixJsonParser -import org.matrix.android.sdk.internal.extensions.toUnsignedInt +import org.matrix.android.sdk.internal.crypto.verification.SASDefaultVerificationTransaction import org.matrix.olm.OlmSAS import timber.log.Timber import java.security.SecureRandom @@ -48,20 +48,9 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu private const val KEY_SPEC = "AES" private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value - // n.b. we are only aver processing byte array that we have generated, so we can make assumptions about the length + // this is the same representation as for SAS but we delimit by dashes instead of spaces for readability private fun getDecimalCodeRepresentation(byteArray: ByteArray): String { - val b0 = byteArray[0].toUnsignedInt() // need unsigned byte - val b1 = byteArray[1].toUnsignedInt() // need unsigned byte - val b2 = byteArray[2].toUnsignedInt() // need unsigned byte - val b3 = byteArray[3].toUnsignedInt() // need unsigned byte - val b4 = byteArray[4].toUnsignedInt() // need unsigned byte - // (B0 << 5 | B1 >> 3) + 1000 - val first = (b0.shl(5) or b1.shr(3)) + 1000 - // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 - val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 - // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 - val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 - return "$first-$second-$third" + return SASDefaultVerificationTransaction.getDecimalCodeRepresentation(byteArray).replace(" ", "-") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt index 1cbaff059ae..b306288c5e1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt @@ -82,6 +82,33 @@ internal abstract class SASDefaultVerificationTransaction( // older devices have limited support of emoji but SDK offers images for the 64 verification emojis // so always send that we support EMOJI val KNOWN_SHORT_CODES = listOf(SasMode.EMOJI, SasMode.DECIMAL) + + /** + * decimal: generate five bytes by using HKDF. + * Take the first 13 bits and convert it to a decimal number (which will be a number between 0 and 8191 inclusive), + * and add 1000 (resulting in a number between 1000 and 9191 inclusive). + * Do the same with the second 13 bits, and the third 13 bits, giving three 4-digit numbers. + * In other words, if the five bytes are B0, B1, B2, B3, and B4, then the first number is (B0 << 5 | B1 >> 3) + 1000, + * the second number is ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000, and the third number is ((B3 & 0x3f) << 7 | B4 >> 1) + 1000. + * (This method of converting 13 bits at a time is used to avoid requiring 32-bit clients to do big-number arithmetic, + * and adding 1000 to the number avoids having clients to worry about properly zero-padding the number when displaying to the user.) + * The three 4-digit numbers are displayed to the user either with dashes (or another appropriate separator) separating the three numbers, + * or with the three numbers on separate lines. + */ + fun getDecimalCodeRepresentation(byteArray: ByteArray): String { + val b0 = byteArray[0].toUnsignedInt() // need unsigned byte + val b1 = byteArray[1].toUnsignedInt() // need unsigned byte + val b2 = byteArray[2].toUnsignedInt() // need unsigned byte + val b3 = byteArray[3].toUnsignedInt() // need unsigned byte + val b4 = byteArray[4].toUnsignedInt() // need unsigned byte + // (B0 << 5 | B1 >> 3) + 1000 + val first = (b0.shl(5) or b1.shr(3)) + 1000 + // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 + val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 + // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 + val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 + return "$first $second $third" + } } override var state: VerificationTxState = VerificationTxState.None @@ -371,33 +398,6 @@ internal abstract class SASDefaultVerificationTransaction( return getDecimalCodeRepresentation(shortCodeBytes!!) } - /** - * decimal: generate five bytes by using HKDF. - * Take the first 13 bits and convert it to a decimal number (which will be a number between 0 and 8191 inclusive), - * and add 1000 (resulting in a number between 1000 and 9191 inclusive). - * Do the same with the second 13 bits, and the third 13 bits, giving three 4-digit numbers. - * In other words, if the five bytes are B0, B1, B2, B3, and B4, then the first number is (B0 << 5 | B1 >> 3) + 1000, - * the second number is ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000, and the third number is ((B3 & 0x3f) << 7 | B4 >> 1) + 1000. - * (This method of converting 13 bits at a time is used to avoid requiring 32-bit clients to do big-number arithmetic, - * and adding 1000 to the number avoids having clients to worry about properly zero-padding the number when displaying to the user.) - * The three 4-digit numbers are displayed to the user either with dashes (or another appropriate separator) separating the three numbers, - * or with the three numbers on separate lines. - */ - fun getDecimalCodeRepresentation(byteArray: ByteArray): String { - val b0 = byteArray[0].toUnsignedInt() // need unsigned byte - val b1 = byteArray[1].toUnsignedInt() // need unsigned byte - val b2 = byteArray[2].toUnsignedInt() // need unsigned byte - val b3 = byteArray[3].toUnsignedInt() // need unsigned byte - val b4 = byteArray[4].toUnsignedInt() // need unsigned byte - // (B0 << 5 | B1 >> 3) + 1000 - val first = (b0.shl(5) or b1.shr(3)) + 1000 - // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 - val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 - // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 - val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 - return "$first $second $third" - } - override fun getEmojiCodeRepresentation(): List { return getEmojiCodeRepresentation(shortCodeBytes!!) } From f7e0a198335b9830af68404d522c834319adb784 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:29:48 +0100 Subject: [PATCH 90/93] Remove redundant annotations --- .../api/rendezvous/channels/ECDHRendezvousChannel.kt | 8 ++++---- .../sdk/api/rendezvous/model/ECDHRendezvous.kt | 7 +++---- .../sdk/api/rendezvous/model/ECDHRendezvousCode.kt | 5 ++--- .../android/sdk/api/rendezvous/model/Payload.kt | 12 ++++++------ .../rendezvous/model/RendezvousTransportDetails.kt | 3 +-- .../model/SimpleHttpRendezvousTransportDetails.kt | 3 +-- 6 files changed, 17 insertions(+), 21 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 6c45aacfaaa..4bbf34280c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -56,10 +56,10 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu @JsonClass(generateAdapter = true) internal data class ECDHPayload( - @Json val algorithm: SecureRendezvousChannelAlgorithm? = null, - @Json val key: String? = null, - @Json val ciphertext: String? = null, - @Json val iv: String? = null + val algorithm: SecureRendezvousChannelAlgorithm? = null, + val key: String? = null, + val ciphertext: String? = null, + val iv: String? = null ) private val olmSASMutex = Mutex() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt index 0840e1ca2ed..55bac6397e5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt @@ -16,12 +16,11 @@ package org.matrix.android.sdk.api.rendezvous.model -import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class ECDHRendezvous( - @Json val transport: SimpleHttpRendezvousTransportDetails, - @Json val algorithm: SecureRendezvousChannelAlgorithm, - @Json val key: String + val transport: SimpleHttpRendezvousTransportDetails, + val algorithm: SecureRendezvousChannelAlgorithm, + val key: String ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt index 410c5c10367..575b5d4bfd3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt @@ -16,11 +16,10 @@ package org.matrix.android.sdk.api.rendezvous.model -import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class ECDHRendezvousCode( - @Json val intent: RendezvousIntent, - @Json val rendezvous: ECDHRendezvous + val intent: RendezvousIntent, + val rendezvous: ECDHRendezvous ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt index 593177e625d..04631ce9599 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt @@ -21,12 +21,12 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class Payload( - @Json val type: PayloadType, - @Json val intent: RendezvousIntent? = null, - @Json val outcome: Outcome? = null, - @Json val protocols: List? = null, - @Json val protocol: Protocol? = null, - @Json val homeserver: String? = null, + val type: PayloadType, + val intent: RendezvousIntent? = null, + val outcome: Outcome? = null, + val protocols: List? = null, + val protocol: Protocol? = null, + val homeserver: String? = null, @Json(name = "login_token") val loginToken: String? = null, @Json(name = "device_id") val deviceId: String? = null, @Json(name = "device_key") val deviceKey: String? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt index 55b3bbb5d9a..1bde43ab7ea 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt @@ -16,10 +16,9 @@ package org.matrix.android.sdk.api.rendezvous.model -import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) open class RendezvousTransportDetails( - @Json val type: RendezvousTransportType + val type: RendezvousTransportType ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt index 70a441d7608..049aa8b7560 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt @@ -16,10 +16,9 @@ package org.matrix.android.sdk.api.rendezvous.model -import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class SimpleHttpRendezvousTransportDetails( - @Json val uri: String + val uri: String ) : RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) From 67be8c3c40f06a88345436abaf129ce3c4e52344 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 18 Oct 2022 12:44:05 +0100 Subject: [PATCH 91/93] The one that got away --- .../android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index 4bbf34280c0..e844143889f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.api.rendezvous.channels import android.util.Base64 -import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock From 0c52a7ed040c5637d81c408e2ec41197de4b2563 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 18 Oct 2022 15:45:39 +0300 Subject: [PATCH 92/93] Fix layout after try again button is clicked. --- .../im/vector/app/features/login/qr/QrCodeLoginActivity.kt | 3 ++- .../im/vector/app/features/login/qr/QrCodeLoginViewModel.kt | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt index c9b8ae00804..a0c113224d0 100644 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt @@ -24,6 +24,7 @@ import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment +import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.features.home.HomeActivity import im.vector.lib.core.utils.compat.getParcelableCompat @@ -66,7 +67,7 @@ class QrCodeLoginActivity : SimpleFragmentActivity() { } private fun showInstructionsFragment(qrCodeLoginArgs: QrCodeLoginArgs) { - addFragment( + replaceFragment( views.container, QrCodeLoginInstructionsFragment::class.java, qrCodeLoginArgs, 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 9bf3e955d3e..97cca9d7918 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 @@ -59,6 +59,11 @@ class QrCodeLoginViewModel @AssistedInject constructor( } private fun handleTryAgain() { + setState { + copy( + connectionStatus = null + ) + } _viewEvents.post(QrCodeLoginViewEvents.NavigateToInitialScreen) } From 4f652f102676e8bd2364149d00009f9d0f1ea656 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 19 Oct 2022 09:12:09 +0100 Subject: [PATCH 93/93] Request changes from review --- .../sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt | 7 +------ .../rendezvous/transports/SimpleHttpRendezvousTransport.kt | 3 ++- .../verification/SASDefaultVerificationTransaction.kt | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt index e844143889f..c1d6b1b70ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt @@ -46,11 +46,6 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu private const val ALGORITHM_SPEC = "AES/GCM/NoPadding" private const val KEY_SPEC = "AES" private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value - - // this is the same representation as for SAS but we delimit by dashes instead of spaces for readability - private fun getDecimalCodeRepresentation(byteArray: ByteArray): String { - return SASDefaultVerificationTransaction.getDecimalCodeRepresentation(byteArray).replace(" ", "-") - } } @JsonClass(generateAdapter = true) @@ -114,7 +109,7 @@ class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPu aesKey = sas.generateShortCode(aesInfo, 32) val rawChecksum = sas.generateShortCode(aesInfo, 5) - return getDecimalCodeRepresentation(rawChecksum) + return SASDefaultVerificationTransaction.getDecimalCodeRepresentation(rawChecksum, separator = "-") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt index 7a5cbe54245..620b599e3df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt @@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransport import timber.log.Timber import java.text.SimpleDateFormat import java.util.Date +import java.util.Locale /** * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 @@ -87,7 +88,7 @@ class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTranspor val location = response.header("location") ?: throw RuntimeException("No rendezvous URI found in response") response.header("expires")?.let { - val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz") + val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) expiresAt = format.parse(it) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt index b306288c5e1..29b416bb82c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt @@ -95,7 +95,7 @@ internal abstract class SASDefaultVerificationTransaction( * The three 4-digit numbers are displayed to the user either with dashes (or another appropriate separator) separating the three numbers, * or with the three numbers on separate lines. */ - fun getDecimalCodeRepresentation(byteArray: ByteArray): String { + fun getDecimalCodeRepresentation(byteArray: ByteArray, separator: String = " "): String { val b0 = byteArray[0].toUnsignedInt() // need unsigned byte val b1 = byteArray[1].toUnsignedInt() // need unsigned byte val b2 = byteArray[2].toUnsignedInt() // need unsigned byte @@ -107,7 +107,7 @@ internal abstract class SASDefaultVerificationTransaction( val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 - return "$first $second $third" + return "$first$separator$second$separator$third" } }