diff --git a/CHANGES.md b/CHANGES.md index 7d2bd74c04..95a3b88df3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Improvements 🙌: - Hide left rooms in breadcrumbs (#766) - Correctly handle SSO login redirection - SSO login is now performed in the default browser, or in Chrome Custom tab if available (#1400) + - Improve checking of homeserver version support (#1442) Bugfix 🐛: - Switch theme is not fully taken into account without restarting the app diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt index cbd6658c44..ec8cc5c074 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.auth import im.vector.matrix.android.api.auth.data.Credentials -import im.vector.matrix.android.api.auth.data.Versions import im.vector.matrix.android.internal.auth.data.LoginFlowResponse import im.vector.matrix.android.internal.auth.data.PasswordLoginParams import im.vector.matrix.android.internal.auth.data.RiotConfig @@ -28,6 +27,7 @@ import im.vector.matrix.android.internal.auth.registration.AddThreePidRegistrati import im.vector.matrix.android.internal.auth.registration.RegistrationParams import im.vector.matrix.android.internal.auth.registration.SuccessResult import im.vector.matrix.android.internal.auth.registration.ValidationCodeBody +import im.vector.matrix.android.internal.auth.version.Versions import im.vector.matrix.android.internal.network.NetworkConstants import retrofit2.Call import retrofit2.http.Body diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticationService.kt index 90d62e619c..2453bc0d05 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticationService.kt @@ -23,9 +23,6 @@ import im.vector.matrix.android.api.auth.AuthenticationService import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.LoginFlowResult -import im.vector.matrix.android.api.auth.data.Versions -import im.vector.matrix.android.api.auth.data.isLoginAndRegistrationSupportedBySdk -import im.vector.matrix.android.api.auth.data.isSupportedBySdk import im.vector.matrix.android.api.auth.login.LoginWizard import im.vector.matrix.android.api.auth.registration.RegistrationWizard import im.vector.matrix.android.api.auth.wellknown.WellknownResult @@ -40,6 +37,9 @@ import im.vector.matrix.android.internal.auth.db.PendingSessionData import im.vector.matrix.android.internal.auth.login.DefaultLoginWizard import im.vector.matrix.android.internal.auth.login.DirectLoginTask import im.vector.matrix.android.internal.auth.registration.DefaultRegistrationWizard +import im.vector.matrix.android.internal.auth.version.Versions +import im.vector.matrix.android.internal.auth.version.isLoginAndRegistrationSupportedBySdk +import im.vector.matrix.android.internal.auth.version.isSupportedBySdk import im.vector.matrix.android.internal.di.Unauthenticated import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.network.executeRequest diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/version/HomeServerVersion.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/version/HomeServerVersion.kt new file mode 100644 index 0000000000..7e0a95dfef --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/version/HomeServerVersion.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.auth.version + +/** + * Values will take the form "rX.Y.Z". + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions + */ +internal data class HomeServerVersion( + val major: Int, + val minor: Int, + val patch: Int +) : Comparable { + override fun compareTo(other: HomeServerVersion): Int { + return when { + major > other.major -> 1 + major < other.major -> -1 + minor > other.minor -> 1 + minor < other.minor -> -1 + patch > other.patch -> 1 + patch < other.patch -> -1 + else -> 0 + } + } + + companion object { + internal val pattern = Regex("""r(\d+)\.(\d+)\.(\d+)""") + + internal fun parse(value: String): HomeServerVersion? { + val result = pattern.matchEntire(value) ?: return null + return HomeServerVersion( + major = result.groupValues[1].toInt(), + minor = result.groupValues[2].toInt(), + patch = result.groupValues[3].toInt() + ) + } + + val r0_0_0 = HomeServerVersion(major = 0, minor = 0, patch = 0) + val r0_1_0 = HomeServerVersion(major = 0, minor = 1, patch = 0) + val r0_2_0 = HomeServerVersion(major = 0, minor = 2, patch = 0) + val r0_3_0 = HomeServerVersion(major = 0, minor = 3, patch = 0) + val r0_4_0 = HomeServerVersion(major = 0, minor = 4, patch = 0) + val r0_5_0 = HomeServerVersion(major = 0, minor = 5, patch = 0) + val r0_6_0 = HomeServerVersion(major = 0, minor = 6, patch = 0) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/Versions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/version/Versions.kt similarity index 80% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/Versions.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/version/Versions.kt index c4186c6ec5..aee5f7e3f3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/Versions.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/version/Versions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018 New Vector Ltd + * Copyright (c) 2020 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.api.auth.data +package im.vector.matrix.android.internal.auth.version import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -38,7 +38,7 @@ import com.squareup.moshi.JsonClass * */ @JsonClass(generateAdapter = true) -data class Versions( +internal data class Versions( @Json(name = "versions") val supportedVersions: List? = null, @@ -46,15 +46,6 @@ data class Versions( val unstableFeatures: Map? = null ) -// MatrixClientServerAPIVersion -private const val r0_0_1 = "r0.0.1" -private const val r0_1_0 = "r0.1.0" -private const val r0_2_0 = "r0.2.0" -private const val r0_3_0 = "r0.3.0" -private const val r0_4_0 = "r0.4.0" -private const val r0_5_0 = "r0.5.0" -private const val r0_6_0 = "r0.6.0" - // MatrixVersionsFeature private const val FEATURE_LAZY_LOAD_MEMBERS = "m.lazy_load_members" private const val FEATURE_REQUIRE_IDENTITY_SERVER = "m.require_identity_server" @@ -64,14 +55,14 @@ private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind" /** * Return true if the SDK supports this homeserver version */ -fun Versions.isSupportedBySdk(): Boolean { +internal fun Versions.isSupportedBySdk(): Boolean { return supportLazyLoadMembers() } /** * Return true if the SDK supports this homeserver version for login and registration */ -fun Versions.isLoginAndRegistrationSupportedBySdk(): Boolean { +internal fun Versions.isLoginAndRegistrationSupportedBySdk(): Boolean { return !doesServerRequireIdentityServerParam() && doesServerAcceptIdentityAccessToken() && doesServerSeparatesAddAndBind() @@ -83,7 +74,7 @@ fun Versions.isLoginAndRegistrationSupportedBySdk(): Boolean { * @return true if the server support the lazy loading of room members */ private fun Versions.supportLazyLoadMembers(): Boolean { - return supportedVersions?.contains(r0_5_0) == true + return getMaxVersion() >= HomeServerVersion.r0_5_0 || unstableFeatures?.get(FEATURE_LAZY_LOAD_MEMBERS) == true } @@ -92,7 +83,7 @@ private fun Versions.supportLazyLoadMembers(): Boolean { * adding a 3pid or resetting password. */ private fun Versions.doesServerRequireIdentityServerParam(): Boolean { - if (supportedVersions?.contains(r0_6_0) == true) return false + if (getMaxVersion() >= HomeServerVersion.r0_6_0) return false return unstableFeatures?.get(FEATURE_REQUIRE_IDENTITY_SERVER) ?: true } @@ -101,11 +92,18 @@ private fun Versions.doesServerRequireIdentityServerParam(): Boolean { * Some homeservers may trigger errors if they are not prepared for the new parameter. */ private fun Versions.doesServerAcceptIdentityAccessToken(): Boolean { - return supportedVersions?.contains(r0_6_0) == true + return getMaxVersion() >= HomeServerVersion.r0_6_0 || unstableFeatures?.get(FEATURE_ID_ACCESS_TOKEN) ?: false } private fun Versions.doesServerSeparatesAddAndBind(): Boolean { - return supportedVersions?.contains(r0_6_0) == true + return getMaxVersion() >= HomeServerVersion.r0_6_0 || unstableFeatures?.get(FEATURE_SEPARATE_ADD_AND_BIND) ?: false } + +private fun Versions.getMaxVersion(): HomeServerVersion { + return supportedVersions + ?.mapNotNull { HomeServerVersion.parse(it) } + ?.max() + ?: HomeServerVersion.r0_0_0 +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt index 880a8fbc31..f96863bea6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.session.homeserver -import im.vector.matrix.android.api.auth.data.Versions +import im.vector.matrix.android.internal.auth.version.Versions import im.vector.matrix.android.internal.network.NetworkConstants import retrofit2.Call import retrofit2.http.GET diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt index 56b9dfc294..f1ee8b4583 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt @@ -17,10 +17,10 @@ package im.vector.matrix.android.internal.session.homeserver import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Versions -import im.vector.matrix.android.api.auth.data.isLoginAndRegistrationSupportedBySdk import im.vector.matrix.android.api.auth.wellknown.WellknownResult import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities +import im.vector.matrix.android.internal.auth.version.Versions +import im.vector.matrix.android.internal.auth.version.isLoginAndRegistrationSupportedBySdk import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity import im.vector.matrix.android.internal.database.query.getOrCreate import im.vector.matrix.android.internal.di.UserId diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/auth/data/VersionsKtTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/auth/data/VersionsKtTest.kt new file mode 100644 index 0000000000..fa6e47f96d --- /dev/null +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/auth/data/VersionsKtTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.auth.data + +import im.vector.matrix.android.internal.auth.version.Versions +import im.vector.matrix.android.internal.auth.version.isSupportedBySdk +import org.amshove.kluent.shouldBe +import org.junit.Test + +class VersionsKtTest { + + @Test + fun isSupportedBySdkTooLow() { + Versions(supportedVersions = listOf("r0.4.0")).isSupportedBySdk() shouldBe false + Versions(supportedVersions = listOf("r0.4.1")).isSupportedBySdk() shouldBe false + } + + @Test + fun isSupportedBySdkUnstable() { + Versions(supportedVersions = listOf("r0.4.0"), unstableFeatures = mapOf("m.lazy_load_members" to true)).isSupportedBySdk() shouldBe true + } + + @Test + fun isSupportedBySdkOk() { + Versions(supportedVersions = listOf("r0.5.0")).isSupportedBySdk() shouldBe true + Versions(supportedVersions = listOf("r0.5.1")).isSupportedBySdk() shouldBe true + } + + // Was not working + @Test + fun isSupportedBySdkLater() { + Versions(supportedVersions = listOf("r0.6.0")).isSupportedBySdk() shouldBe true + Versions(supportedVersions = listOf("r0.6.1")).isSupportedBySdk() shouldBe true + } + + // Cover cases of issue #1442 + @Test + fun isSupportedBySdk1442() { + Versions(supportedVersions = listOf("r0.5.0", "r0.6.0")).isSupportedBySdk() shouldBe true + Versions(supportedVersions = listOf("r0.5.0", "r0.6.1")).isSupportedBySdk() shouldBe true + Versions(supportedVersions = listOf("r0.6.0")).isSupportedBySdk() shouldBe true + } +}