diff --git a/changelog.d/8299.feature b/changelog.d/8299.feature new file mode 100644 index 0000000000..d4c4dae9c5 --- /dev/null +++ b/changelog.d/8299.feature @@ -0,0 +1 @@ +Updates to protocol used for Sign in with QR code 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 d1dd0238ba..bbef75a21d 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 971407388c..ea749a56b8 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 /login/get_token. + * + * See https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv1loginget_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 4d8e90cf35..3fe5541b68 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 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" @@ -94,7 +95,9 @@ internal fun Versions.doesServerSupportThreadUnreadNotifications(): Boolean { return getMaxVersion() >= HomeServerVersion.v1_4_0 || (msc3771 && msc3773) } +@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 95ff44807c..7c60eab08f 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 login token issuance for signing in another device. + * True if the user can use /login/get_token, false otherwise. + */ + @Json(name = "m.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 ec12695ecd..a368325793 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 @@ -151,8 +151,6 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( getVersionResult.doesServerSupportThreads() homeServerCapabilitiesEntity.canUseThreadReadReceiptsAndNotifications = getVersionResult.doesServerSupportThreadUnreadNotifications() - homeServerCapabilitiesEntity.canLoginWithQrCode = - getVersionResult.doesServerSupportQrCodeLogin() homeServerCapabilitiesEntity.canRemotelyTogglePushNotificationsOfDevices = getVersionResult.doesServerSupportRemoteToggleOfPushNotifications() homeServerCapabilitiesEntity.canRedactEventWithRelations = @@ -169,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 stable it is done via /capabilities and /login + + // in stable 1.7 a capability is exposed for the authenticated 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