From 805015fa4af00180e80b6e9c45376b5fec55468d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 3 Apr 2023 12:20:21 +0100 Subject: [PATCH 1/4] Support for MSC3882 revision 1 --- .../internal/auth/DefaultAuthenticationService.kt | 5 ++++- .../sdk/internal/auth/data/LoginFlowResponse.kt | 10 +++++++++- .../android/sdk/internal/auth/version/Versions.kt | 3 +++ .../session/homeserver/GetCapabilitiesResult.kt | 9 ++++++++- .../homeserver/GetHomeServerCapabilitiesTask.kt | 12 ++++++++++++ 5 files changed, 36 insertions(+), 3 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 d1dd0238bad..bbef75a21d8 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 @@ -301,6 +301,9 @@ internal class DefaultAuthenticationService @Inject constructor( val oidcCompatibilityFlow = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == "m.login.sso" && it.delegatedOidcCompatibilty == true } val flows = if (oidcCompatibilityFlow != null) listOf(oidcCompatibilityFlow) else loginFlowResponse.flows + val supportsGetLoginTokenFlow = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == "m.login.token" && it.getLoginToken == true } != null + + @Suppress("DEPRECATION") return LoginFlowResult( supportedLoginTypes = flows.orEmpty().mapNotNull { it.type }, ssoIdentityProviders = flows.orEmpty().firstOrNull { it.type == LoginFlowTypes.SSO }?.ssoIdentityProvider, @@ -309,7 +312,7 @@ internal class DefaultAuthenticationService @Inject constructor( isOutdatedHomeserver = !versions.isSupportedBySdk(), hasOidcCompatibilityFlow = oidcCompatibilityFlow != null, isLogoutDevicesSupported = versions.doesServerSupportLogoutDevices(), - isLoginWithQrSupported = versions.doesServerSupportQrCodeLogin(), + isLoginWithQrSupported = supportsGetLoginTokenFlow || versions.doesServerSupportQrCodeLogin(), ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt index 971407388c3..8bd7b970a94 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt @@ -51,5 +51,13 @@ internal data class LoginFlow( * See [MSC3824](https://github.com/matrix-org/matrix-spec-proposals/pull/3824) */ @Json(name = "org.matrix.msc3824.delegated_oidc_compatibility") - val delegatedOidcCompatibilty: Boolean? = null + val delegatedOidcCompatibilty: Boolean? = null, + + /** + * Whether a login flow of type m.login.token could accept a token issued using MSC3882. + * + * See [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882) + */ + @Json(name = "org.matrix.msc3882.get_login_token") + val getLoginToken: Boolean? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt index 4d8e90cf35d..a6e42642b25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt @@ -54,6 +54,7 @@ private const val FEATURE_ID_ACCESS_TOKEN = "m.id_access_token" private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind" private const val FEATURE_THREADS_MSC3440 = "org.matrix.msc3440" private const val FEATURE_THREADS_MSC3440_STABLE = "org.matrix.msc3440.stable" +@Deprecated("The availability of MSC3882 is now exposed as a capability or part of login flow from revision 1 onwards") private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882" private const val FEATURE_THREADS_MSC3771 = "org.matrix.msc3771" private const val FEATURE_THREADS_MSC3773 = "org.matrix.msc3773" @@ -94,7 +95,9 @@ internal fun Versions.doesServerSupportThreadUnreadNotifications(): Boolean { return getMaxVersion() >= HomeServerVersion.v1_4_0 || (msc3771 && msc3773) } +@Deprecated("The availability of MSC3882 is now exposed as a capability or part of login flow from revision 1 onwards") internal fun Versions.doesServerSupportQrCodeLogin(): Boolean { + @Suppress("DEPRECATION") return unstableFeatures?.get(FEATURE_QR_CODE_LOGIN) ?: false } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt index 95ff44807c8..7ac2b8b30cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt @@ -71,7 +71,14 @@ internal data class Capabilities( * True if the user can use m.thread relation, false otherwise. */ @Json(name = "m.thread") - val threads: BooleanCapability? = null + val threads: BooleanCapability? = null, + + /** + * Capability to indicate if the server supports MSC3882 login token issuance for signing in another deivce. + * True if the user can use /login/get_token, false otherwise. + */ + @Json(name = "org.matrix.msc3882.get_login_token") + val getLoginToken: BooleanCapability? = null ) @JsonClass(generateAdapter = true) 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 ec12695ecdc..463316a5f16 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 @@ -135,6 +135,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( homeServerCapabilitiesEntity.roomVersionsJson = capabilities?.roomVersions?.let { MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it) } + // in r1 of MSC3882 a capability is exposed for the authenticated in user + if (capabilities?.getLoginToken != null) { + homeServerCapabilitiesEntity.canLoginWithQrCode = capabilities.getLoginToken.enabled == true + } } if (getMediaConfigResult != null) { @@ -151,12 +155,20 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( getVersionResult.doesServerSupportThreads() homeServerCapabilitiesEntity.canUseThreadReadReceiptsAndNotifications = getVersionResult.doesServerSupportThreadUnreadNotifications() + @Suppress("DEPRECATION") homeServerCapabilitiesEntity.canLoginWithQrCode = getVersionResult.doesServerSupportQrCodeLogin() homeServerCapabilitiesEntity.canRemotelyTogglePushNotificationsOfDevices = getVersionResult.doesServerSupportRemoteToggleOfPushNotifications() homeServerCapabilitiesEntity.canRedactEventWithRelations = getVersionResult.doesServerSupportRedactEventWithRelations() + + // in r0 of MSC3882 an unstable feature was exposed. In r1 it is done via /capabilities and /login + // so, only use it if set to true, otherwise we use the default or previous value + @Suppress("DEPRECATION") + if (getVersionResult.doesServerSupportQrCodeLogin()) { + homeServerCapabilitiesEntity.canLoginWithQrCode = true + } } if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { From c7d6f61b730d7df6f319f6cc4a9a3e36a785316b Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 4 Apr 2023 18:13:03 +0100 Subject: [PATCH 2/4] Attempt to reduce cognitive complexity --- .../GetHomeServerCapabilitiesTask.kt | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 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 463316a5f16..0de8c1c2db0 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 @@ -135,10 +135,6 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( homeServerCapabilitiesEntity.roomVersionsJson = capabilities?.roomVersions?.let { MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it) } - // in r1 of MSC3882 a capability is exposed for the authenticated in user - if (capabilities?.getLoginToken != null) { - homeServerCapabilitiesEntity.canLoginWithQrCode = capabilities.getLoginToken.enabled == true - } } if (getMediaConfigResult != null) { @@ -155,20 +151,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( getVersionResult.doesServerSupportThreads() homeServerCapabilitiesEntity.canUseThreadReadReceiptsAndNotifications = getVersionResult.doesServerSupportThreadUnreadNotifications() - @Suppress("DEPRECATION") - homeServerCapabilitiesEntity.canLoginWithQrCode = - getVersionResult.doesServerSupportQrCodeLogin() homeServerCapabilitiesEntity.canRemotelyTogglePushNotificationsOfDevices = getVersionResult.doesServerSupportRemoteToggleOfPushNotifications() homeServerCapabilitiesEntity.canRedactEventWithRelations = getVersionResult.doesServerSupportRedactEventWithRelations() - - // in r0 of MSC3882 an unstable feature was exposed. In r1 it is done via /capabilities and /login - // so, only use it if set to true, otherwise we use the default or previous value - @Suppress("DEPRECATION") - if (getVersionResult.doesServerSupportQrCodeLogin()) { - homeServerCapabilitiesEntity.canLoginWithQrCode = true - } } if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { @@ -181,10 +167,25 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( } homeServerCapabilitiesEntity.externalAccountManagementUrl = getWellknownResult.wellKnown.unstableDelegatedAuthConfig?.accountManagementUrl } + + homeServerCapabilitiesEntity.canLoginWithQrCode = canLoginWithQrCode(getCapabilitiesResult, getVersionResult) + homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time } } + private fun canLoginWithQrCode(getCapabilitiesResult: GetCapabilitiesResult?, getVersionResult: Versions?): Boolean { + // in r0 of MSC3882 an unstable feature was exposed. In r1 it is done via /capabilities and /login + + // in r1 of MSC3882 a capability is exposed for the authenticated in user + if (getCapabilitiesResult?.capabilities?.getLoginToken != null) { + return getCapabilitiesResult.capabilities.getLoginToken.enabled == true + } + + @Suppress("DEPRECATION") + return getVersionResult?.doesServerSupportQrCodeLogin() == true + } + companion object { // 8 hours like on Element Web private const val MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS = 8 * 60 * 60 * 1000 From c989b042f0e2bf32833f31efab98b486880ee987 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 4 Apr 2023 18:16:27 +0100 Subject: [PATCH 3/4] Changelog --- changelog.d/8299.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/8299.feature diff --git a/changelog.d/8299.feature b/changelog.d/8299.feature new file mode 100644 index 00000000000..d4c4dae9c5c --- /dev/null +++ b/changelog.d/8299.feature @@ -0,0 +1 @@ +Updates to protocol used for Sign in with QR code From 11c9b985fb815913ea84f13c2ca3e0e98504f62b Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 30 May 2023 12:43:47 +0100 Subject: [PATCH 4/4] Move straight to stable get_login_token Remove unstable MSC3882 revision 1 support --- .../android/sdk/internal/auth/data/LoginFlowResponse.kt | 6 +++--- .../matrix/android/sdk/internal/auth/version/Versions.kt | 4 ++-- .../internal/session/homeserver/GetCapabilitiesResult.kt | 4 ++-- .../session/homeserver/GetHomeServerCapabilitiesTask.kt | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt index 8bd7b970a94..ea749a56b8b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt @@ -54,10 +54,10 @@ internal data class LoginFlow( val delegatedOidcCompatibilty: Boolean? = null, /** - * Whether a login flow of type m.login.token could accept a token issued using MSC3882. + * Whether a login flow of type m.login.token could accept a token issued using /login/get_token. * - * See [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882) + * See https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv1loginget_token */ - @Json(name = "org.matrix.msc3882.get_login_token") + @Json(name = "get_login_token") val getLoginToken: Boolean? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt index a6e42642b25..3fe5541b680 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt @@ -54,7 +54,7 @@ private const val FEATURE_ID_ACCESS_TOKEN = "m.id_access_token" private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind" private const val FEATURE_THREADS_MSC3440 = "org.matrix.msc3440" private const val FEATURE_THREADS_MSC3440_STABLE = "org.matrix.msc3440.stable" -@Deprecated("The availability of MSC3882 is now exposed as a capability or part of login flow from revision 1 onwards") +@Deprecated("The availability of stable get_login_token is now exposed as a capability and part of login flow") private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882" private const val FEATURE_THREADS_MSC3771 = "org.matrix.msc3771" private const val FEATURE_THREADS_MSC3773 = "org.matrix.msc3773" @@ -95,7 +95,7 @@ internal fun Versions.doesServerSupportThreadUnreadNotifications(): Boolean { return getMaxVersion() >= HomeServerVersion.v1_4_0 || (msc3771 && msc3773) } -@Deprecated("The availability of MSC3882 is now exposed as a capability or part of login flow from revision 1 onwards") +@Deprecated("The availability of stable get_login_token is now exposed as a capability and part of login flow") internal fun Versions.doesServerSupportQrCodeLogin(): Boolean { @Suppress("DEPRECATION") return unstableFeatures?.get(FEATURE_QR_CODE_LOGIN) ?: false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt index 7ac2b8b30cc..7c60eab08f2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt @@ -74,10 +74,10 @@ internal data class Capabilities( val threads: BooleanCapability? = null, /** - * Capability to indicate if the server supports MSC3882 login token issuance for signing in another deivce. + * Capability to indicate if the server supports login token issuance for signing in another device. * True if the user can use /login/get_token, false otherwise. */ - @Json(name = "org.matrix.msc3882.get_login_token") + @Json(name = "m.get_login_token") val getLoginToken: BooleanCapability? = null ) 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 0de8c1c2db0..a3683257939 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 @@ -175,9 +175,9 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( } private fun canLoginWithQrCode(getCapabilitiesResult: GetCapabilitiesResult?, getVersionResult: Versions?): Boolean { - // in r0 of MSC3882 an unstable feature was exposed. In r1 it is done via /capabilities and /login + // in r0 of MSC3882 an unstable feature was exposed. In stable it is done via /capabilities and /login - // in r1 of MSC3882 a capability is exposed for the authenticated in user + // in stable 1.7 a capability is exposed for the authenticated user if (getCapabilitiesResult?.capabilities?.getLoginToken != null) { return getCapabilitiesResult.capabilities.getLoginToken.enabled == true }