From c1ed75b07f8ae3297777e5f194c1e1c3131a9bee Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 15 Dec 2025 19:12:59 +0000 Subject: [PATCH 1/9] Support for stable version of MSC3824 OAuth 2.0 aware --- .../matrix/android/sdk/api/auth/SSOAction.kt | 6 +-- .../android/sdk/api/auth/data/AuthMetadata.kt | 49 +++++++++++++++++++ .../homeserver/HomeServerCapabilities.kt | 33 ++++++++++++- .../auth/DefaultAuthenticationService.kt | 10 ++-- .../internal/auth/data/LoginFlowResponse.kt | 18 +++++-- .../mapper/HomeServerCapabilitiesMapper.kt | 1 + .../model/HomeServerCapabilitiesEntity.kt | 1 + .../session/homeserver/AuthMetadataAPI.kt | 30 ++++++++++++ .../session/homeserver/AuthMetadataModule.kt | 41 ++++++++++++++++ .../GetHomeServerCapabilitiesTask.kt | 27 ++++++++-- .../HomeServerCapabilitiesModule.kt | 7 +++ .../settings/devices/DevicesViewModel.kt | 6 +-- .../v2/overview/SessionOverviewFragment.kt | 4 +- .../v2/overview/SessionOverviewViewModel.kt | 8 +-- .../v2/overview/SessionOverviewViewState.kt | 2 +- .../fixtures/HomeserverCapabilityFixture.kt | 2 + 16 files changed, 221 insertions(+), 24 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/SSOAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/SSOAction.kt index db2dd870d52..bd5dfb662cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/SSOAction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/SSOAction.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.auth /** * See https://github.com/matrix-org/matrix-spec-proposals/pull/3824 */ -enum class SSOAction { - LOGIN, - REGISTER; +enum class SSOAction(val value: String) { + LOGIN("login"), + REGISTER("register"); } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt new file mode 100644 index 00000000000..80a7066671b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2023 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.auth.data + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.extensions.orFalse + +/** + * This is a subset of the server metadata discovery for the OAuth 2.0 API + * https://spec.matrix.org/v1.16/client-server-api/#get_matrixclientv1auth_metadata + * + * Includes the values from MSC4191: https://github.com/matrix-org/matrix-spec-proposals/pull/4191 + * + *
+ * {
+ *     "issuer": "https://id.server.org",
+ *     "account_management_uri": "https://id.server.org/my-account",
+ *     "account_management_actions_supported": ["org.matrix.profile", "org.matrix.devices_list"],
+ * }
+ * 
+ * . + */ + +@JsonClass(generateAdapter = true) +data class AuthMetadata( + @Json(name = "issuer") + val issuer: String, + + @Json(name = "account_management_uri") + val accountManagementUri: String?, + + @Json(name = "account_management_actions_supported") + val accountManagementActionsSupported: List?, +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index 101947f9d9b..4536b527fb2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.homeserver +import org.matrix.android.sdk.api.extensions.orFalse + data class HomeServerCapabilities( /** * True if it is possible to change the password of the account. @@ -82,12 +84,17 @@ data class HomeServerCapabilities( var canRedactRelatedEvents: Boolean = false, /** - * External account management url for use with MSC3824 delegated OIDC, provided in Wellknown. + * External account management url for use with OAuth API, provided by MSC4191 /auth_metadata discovery or in unstable Wellknown. */ val externalAccountManagementUrl: String? = null, /** - * Authentication issuer for use with MSC3824 delegated OIDC, provided in Wellknown. + * External account management supported actions for use with OAuth API, provided by MSC4191 /auth_metadata discovery + */ + val externalAccountManagementSupportedActions: List? = null, + + /** + * Authentication issuer for use with MSC3824 delegated OIDC, provided by /auth_metadata discovery or in unstable Wellknown. */ val authenticationIssuer: String? = null, @@ -162,4 +169,26 @@ data class HomeServerCapabilities( const val ROOM_CAP_KNOCK = "knock" const val ROOM_CAP_RESTRICTED = "restricted" } + + fun getLogoutDeviceURL(deviceId: String): String? { + if (externalAccountManagementUrl == null) { + return null; + } + + // default to the stable value: + var action = "org.matrix.device_delete" + externalAccountManagementSupportedActions?.also { actions -> + if (actions.contains("org.matrix.device_delete")) { + // server supports stable version so use it + } else if (actions.contains("org.matrix.session_end")) { + // earlier version of MSC4191: + action = "org.matrix.session_end" + } else if (actions.contains("session_end")) { + // previous unspecified version + action = "session_end" + } + } + + return externalAccountManagementUrl.removeSuffix("/") + "?action=${action}&device_id=${deviceId}" + } } 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 e852c61185b..6b9a06a6046 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 @@ -106,7 +106,11 @@ internal class DefaultAuthenticationService @Inject constructor( } // unstable MSC3824 action param - appendParamToUrl("org.matrix.msc3824.action", action.toString()) + // This can be removed once servers have been updated to support the stable one. + appendParamToUrl("org.matrix.msc3824.action", action.value) + + // stable param: + appendParamToUrl("action", action.value) } } @@ -297,8 +301,8 @@ internal class DefaultAuthenticationService @Inject constructor( authAPI.getLoginFlows() } - // If an m.login.sso flow is present that is flagged as being for MSC3824 OIDC compatibility then we only return that flow - val oidcCompatibilityFlow = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == "m.login.sso" && it.delegatedOidcCompatibility == true } + // If an m.login.sso flow is present that is flagged as being for MSC3824 OAuth compatibility then we only return that flow + val oidcCompatibilityFlow = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == "m.login.sso" && it.delegatedOidcCompatibility } 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 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 2e52740ed48..35972d98933 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 @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.auth.data import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider +import org.matrix.android.sdk.api.extensions.orFalse @JsonClass(generateAdapter = true) internal data class LoginFlowResponse( @@ -46,12 +47,20 @@ internal data class LoginFlow( val ssoIdentityProvider: List? = null, /** - * Whether this login flow is preferred for OIDC-aware clients. + * Whether this login flow is preferred for OAuth 2.0-aware clients like we are. * * See [MSC3824](https://github.com/matrix-org/matrix-spec-proposals/pull/3824) */ + @Json(name = "oauth_aware_preferred") + val oauthAwarePreferred: Boolean? = null, + + /** + * Unstable name from MSC3824. + * + * @deprecated Use {@link oauthAwarePreferred} instead. + */ @Json(name = "org.matrix.msc3824.delegated_oidc_compatibility") - val delegatedOidcCompatibility: Boolean? = null, + val unstableDelegatedOidcCompatibility: Boolean? = null, /** * Whether a login flow of type m.login.token could accept a token issued using /login/get_token. @@ -60,4 +69,7 @@ internal data class LoginFlow( */ @Json(name = "get_login_token") val getLoginToken: Boolean? = null -) +) { + val delegatedOidcCompatibility: Boolean + get() = this.oauthAwarePreferred.orFalse() || this.unstableDelegatedOidcCompatibility.orFalse() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt index 8cdabaf1504..1c6ba850d74 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -49,6 +49,7 @@ internal object HomeServerCapabilitiesMapper { canRemotelyTogglePushNotificationsOfDevices = entity.canRemotelyTogglePushNotificationsOfDevices, canRedactRelatedEvents = entity.canRedactEventWithRelations, externalAccountManagementUrl = entity.externalAccountManagementUrl, + externalAccountManagementSupportedActions = entity.externalAccountManagementSupportedActions?.split(","), authenticationIssuer = entity.authenticationIssuer, disableNetworkConstraint = entity.disableNetworkConstraint, canUseAuthenticatedMedia = entity.canUseAuthenticatedMedia, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt index 0096071d547..d77d9025953 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt @@ -36,6 +36,7 @@ internal open class HomeServerCapabilitiesEntity( var canRemotelyTogglePushNotificationsOfDevices: Boolean = false, var canRedactEventWithRelations: Boolean = false, var externalAccountManagementUrl: String? = null, + var externalAccountManagementSupportedActions: String? = null, var authenticationIssuer: String? = null, var disableNetworkConstraint: Boolean? = null, var canUseAuthenticatedMedia: Boolean = false, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt new file mode 100644 index 00000000000..9a12cbc2166 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2025 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.session.homeserver + +import org.matrix.android.sdk.api.auth.data.AuthMetadata +import org.matrix.android.sdk.internal.auth.version.Versions +import org.matrix.android.sdk.internal.network.NetworkConstants +import retrofit2.http.GET + +internal interface AuthMetadataAPI { + /** + * Request the homeserver OAuth 2.0 auth metadata. + */ + @GET(NetworkConstants.URI_API_PREFIX_PATH_V1 + "auth_metadata") + suspend fun getAuthMetadata(): AuthMetadata +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt new file mode 100644 index 00000000000..a3efe04a141 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt @@ -0,0 +1,41 @@ +/* + * 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. + * 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.session.homeserver + +import dagger.Binds +import dagger.Module +import dagger.Provides +import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.android.sdk.internal.wellknown.WellknownModule +import retrofit2.Retrofit + +@Module(includes = [WellknownModule::class]) +internal abstract class AuthMetadataModule { + + @Module + companion object { + @Provides + @JvmStatic + @SessionScope + fun providesAuthMetadataAPI(retrofit: Retrofit): AuthMetadataAPI { + return retrofit.create(AuthMetadataAPI::class.java) + } + } + + @Binds + abstract fun bindGetHomeServerCapabilitiesTask(task: DefaultGetHomeServerCapabilitiesTask): GetHomeServerCapabilitiesTask +} 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 5314237c3c2..e82aa71fa8f 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 @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.homeserver import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.MatrixPatterns.getServerName +import org.matrix.android.sdk.api.auth.data.AuthMetadata 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 @@ -66,7 +67,8 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( private val configExtractor: IntegrationManagerConfigExtractor, private val homeServerConnectionConfig: HomeServerConnectionConfig, @UserId - private val userId: String + private val userId: String, + private val authMetadataAPI: AuthMetadataAPI, ) : GetHomeServerCapabilitiesTask { override suspend fun execute(params: GetHomeServerCapabilitiesTask.Params) { @@ -104,6 +106,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( } }.getOrNull() + val authMetadata = runCatching { + executeRequest(globalErrorReceiver = null) { + authMetadataAPI.getAuthMetadata() + } + }.getOrNull(); + // Domain may include a port (eg, matrix.org:8080) // Per https://spec.matrix.org/latest/client-server-api/#well-known-uri we should extract the hostname from the server name // So we take everything before the last : as the domain for the well-known task. @@ -117,14 +125,15 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( ) }.getOrNull() - insertInDb(capabilities, mediaConfig, versions, wellknownResult) + insertInDb(capabilities, mediaConfig, versions, wellknownResult, authMetadata) } private suspend fun insertInDb( getCapabilitiesResult: GetCapabilitiesResult?, getMediaConfigResult: GetMediaConfigResult?, getVersionResult: Versions?, - getWellknownResult: WellknownResult? + getWellknownResult: WellknownResult?, + authMetadata: AuthMetadata?, ) { monarchy.awaitTransaction { realm -> val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm) @@ -174,11 +183,23 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( Timber.v("Extracted integration config : $config") realm.insertOrUpdate(config) } + // Getting the OAuth 2.0 metadata from well-known was in unstable MSC: homeServerCapabilitiesEntity.authenticationIssuer = getWellknownResult.wellKnown.unstableDelegatedAuthConfig?.issuer homeServerCapabilitiesEntity.externalAccountManagementUrl = getWellknownResult.wellKnown.unstableDelegatedAuthConfig?.accountManagementUrl homeServerCapabilitiesEntity.disableNetworkConstraint = getWellknownResult.wellKnown.disableNetworkConstraint } + // If the server returns OAuth 2.0 metadata then prefer that over the well-known values: + if (authMetadata != null) { + homeServerCapabilitiesEntity.authenticationIssuer = authMetadata.issuer; + if (authMetadata.accountManagementUri != null) { + homeServerCapabilitiesEntity.externalAccountManagementUrl = authMetadata.accountManagementUri; + } + if (authMetadata.accountManagementActionsSupported != null) { + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions = authMetadata.accountManagementActionsSupported.joinToString(",") + } + } + homeServerCapabilitiesEntity.canLoginWithQrCode = canLoginWithQrCode(getCapabilitiesResult, getVersionResult) homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesModule.kt index 2a1573dd98f..88988addcea 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesModule.kt @@ -34,6 +34,13 @@ internal abstract class HomeServerCapabilitiesModule { fun providesCapabilitiesAPI(retrofit: Retrofit): CapabilitiesAPI { return retrofit.create(CapabilitiesAPI::class.java) } + + @Provides + @JvmStatic + @SessionScope + fun providesAuthMetadataAPI(retrofit: Retrofit): AuthMetadataAPI { + return retrofit.create(AuthMetadataAPI::class.java) + } } @Binds diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 1c9fb718585..0282bf9a73b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -337,12 +337,12 @@ class DevicesViewModel @AssistedInject constructor( private fun handleDelete(action: DevicesAction.Delete) { val deviceId = action.deviceId - val accountManagementUrl = session.homeServerCapabilitiesService().getHomeServerCapabilities().externalAccountManagementUrl - if (accountManagementUrl != null) { + val externalLogoutDeviceUrl = session.homeServerCapabilitiesService().getHomeServerCapabilities().getLogoutDeviceURL(deviceId); + if (externalLogoutDeviceUrl != null) { // Open external browser to delete this session _viewEvents.post( DevicesViewEvents.OpenBrowser( - url = accountManagementUrl.removeSuffix("/") + "?action=session_end&device_id=$deviceId" + url = externalLogoutDeviceUrl ) ) } else { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 0d90f4f2c98..56a13a77c0f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -129,12 +129,12 @@ class SessionOverviewFragment : } private fun confirmSignoutOtherSession() = withState(viewModel) { state -> - if (state.externalAccountManagementUrl != null) { + if (state.externalDeleteDeviceUrl != null) { // Manage in external account manager openUrlInChromeCustomTab( requireContext(), null, - state.externalAccountManagementUrl.removeSuffix("/") + "?action=session_end&device_id=${state.deviceId}" + state.externalDeleteDeviceUrl, ) } else { activity?.let { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 8a34f6ce6ed..54cdde22e15 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -66,16 +66,16 @@ class SessionOverviewViewModel @AssistedInject constructor( observeNotificationsStatus(initialState.deviceId) refreshIpAddressVisibility() observePreferences() - initExternalAccountManagementUrl() + initExternalDeleteDeviceUrl() } - private fun initExternalAccountManagementUrl() { + private fun initExternalDeleteDeviceUrl() { setState { copy( - externalAccountManagementUrl = activeSessionHolder.getSafeActiveSession() + externalDeleteDeviceUrl = activeSessionHolder.getSafeActiveSession() ?.homeServerCapabilitiesService() ?.getHomeServerCapabilities() - ?.externalAccountManagementUrl + ?.getLogoutDeviceURL(deviceId) ) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt index f795d29969f..da1847a397b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt @@ -20,7 +20,7 @@ data class SessionOverviewViewState( val isLoading: Boolean = false, val notificationsStatus: NotificationsStatus = NotificationsStatus.NOT_SUPPORTED, val isShowingIpAddress: Boolean = false, - val externalAccountManagementUrl: String? = null, + val externalDeleteDeviceUrl: String? = null, ) : MavericksState { constructor(args: SessionOverviewArgs) : this( deviceId = args.deviceId diff --git a/vector/src/test/java/im/vector/app/test/fixtures/HomeserverCapabilityFixture.kt b/vector/src/test/java/im/vector/app/test/fixtures/HomeserverCapabilityFixture.kt index a66fc201c70..ff30a37895f 100644 --- a/vector/src/test/java/im/vector/app/test/fixtures/HomeserverCapabilityFixture.kt +++ b/vector/src/test/java/im/vector/app/test/fixtures/HomeserverCapabilityFixture.kt @@ -21,6 +21,7 @@ fun aHomeServerCapabilities( roomVersions: RoomVersionCapabilities? = null, canRemotelyTogglePushNotificationsOfDevices: Boolean = true, externalAccountManagementUrl: String? = null, + externalAccountManagementSupportedActions: List? = null, ) = HomeServerCapabilities( canChangePassword = canChangePassword, canChangeDisplayName = canChangeDisplayName, @@ -32,4 +33,5 @@ fun aHomeServerCapabilities( roomVersions = roomVersions, canRemotelyTogglePushNotificationsOfDevices = canRemotelyTogglePushNotificationsOfDevices, externalAccountManagementUrl = externalAccountManagementUrl, + externalAccountManagementSupportedActions = externalAccountManagementSupportedActions, ) From e68101c118bbe2b1afbc5110bf3f1bf4ee838d4b Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 19 Dec 2025 11:11:03 +0000 Subject: [PATCH 2/9] Use all values from auth metadata even if null --- .../session/homeserver/GetHomeServerCapabilitiesTask.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 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 e82aa71fa8f..00de4b986d8 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 @@ -192,12 +192,8 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( // If the server returns OAuth 2.0 metadata then prefer that over the well-known values: if (authMetadata != null) { homeServerCapabilitiesEntity.authenticationIssuer = authMetadata.issuer; - if (authMetadata.accountManagementUri != null) { - homeServerCapabilitiesEntity.externalAccountManagementUrl = authMetadata.accountManagementUri; - } - if (authMetadata.accountManagementActionsSupported != null) { - homeServerCapabilitiesEntity.externalAccountManagementSupportedActions = authMetadata.accountManagementActionsSupported.joinToString(",") - } + homeServerCapabilitiesEntity.externalAccountManagementUrl = authMetadata.accountManagementUri; + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions = if (authMetadata.accountManagementActionsSupported != null) authMetadata.accountManagementActionsSupported.joinToString(",") else null } homeServerCapabilitiesEntity.canLoginWithQrCode = canLoginWithQrCode(getCapabilitiesResult, getVersionResult) From a3684fa2439008cadb34ad26c58e58dbe6d7450a Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 19 Dec 2025 11:11:08 +0000 Subject: [PATCH 3/9] Test cases --- .../homeserver/HomeServerCapabilitiesTest.kt | 83 +++++++++ ...efaultGetHomeServerCapabilitiesTaskTest.kt | 166 ++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt create mode 100644 matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt new file mode 100644 index 00000000000..9bb1f1df841 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2025 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.session.homeserver + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class HomeServerCapabilitiesTest { + + private val deviceId = "TEST_DEVICE_ID" + + @Test + fun `given externalAccountManagementUrl is null, when getLogoutDeviceURL, then return null`() { + val capabilities = HomeServerCapabilities( + externalAccountManagementUrl = null + ) + assertNull(capabilities.getLogoutDeviceURL(deviceId)) + } + + @Test + fun `given supported actions is null, when getLogoutDeviceURL, then uses default stable action`() { + val capabilities = HomeServerCapabilities( + externalAccountManagementUrl = "https://example.com", + externalAccountManagementSupportedActions = null + ) + val expectedUrl = "https://example.com?action=org.matrix.device_delete&device_id=$deviceId" + assertEquals(expectedUrl, capabilities.getLogoutDeviceURL(deviceId)) + } + + @Test + fun `given supported actions contains stable action, when getLogoutDeviceURL, then uses stable action`() { + val capabilities = HomeServerCapabilities( + externalAccountManagementUrl = "https://example.com", + externalAccountManagementSupportedActions = listOf("org.matrix.device_delete", "org.matrix.session_end", "session_end") + ) + val expectedUrl = "https://example.com?action=org.matrix.device_delete&device_id=$deviceId" + assertEquals(expectedUrl, capabilities.getLogoutDeviceURL(deviceId)) + } + + @Test + fun `given supported actions contains unstable action, when getLogoutDeviceURL, then uses unstable action`() { + val capabilities = HomeServerCapabilities( + externalAccountManagementUrl = "https://example.com", + externalAccountManagementSupportedActions = listOf("org.matrix.session_end", "session_end") + ) + val expectedUrl = "https://example.com?action=org.matrix.session_end&device_id=$deviceId" + assertEquals(expectedUrl, capabilities.getLogoutDeviceURL(deviceId)) + } + + @Test + fun `given supported actions contains legacy action, when getLogoutDeviceURL, then uses legacy action`() { + val capabilities = HomeServerCapabilities( + externalAccountManagementUrl = "https://example.com", + externalAccountManagementSupportedActions = listOf("session_end") + ) + val expectedUrl = "https://example.com?action=session_end&device_id=$deviceId" + assertEquals(expectedUrl, capabilities.getLogoutDeviceURL(deviceId)) + } + + @Test + fun `given url with trailing slash, when getLogoutDeviceURL, then slash is removed`() { + val capabilities = HomeServerCapabilities( + externalAccountManagementUrl = "https://example.com/account/" + ) + val expectedUrl = "https://example.com/account?action=org.matrix.device_delete&device_id=$deviceId" + assertEquals(expectedUrl, capabilities.getLogoutDeviceURL(deviceId)) + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt new file mode 100644 index 00000000000..7ce6758a2c5 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt @@ -0,0 +1,166 @@ +/* + * Copyright 2025 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.session.homeserver + +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.auth.data.AuthMetadata +import org.matrix.android.sdk.api.auth.data.DelegatedAuthConfig +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.auth.data.WellKnown +import org.matrix.android.sdk.api.auth.wellknown.WellknownResult +import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver +import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManagerConfigExtractor +import org.matrix.android.sdk.internal.session.media.AuthenticatedMediaAPI +import org.matrix.android.sdk.internal.session.media.UnauthenticatedMediaAPI +import org.matrix.android.sdk.internal.wellknown.GetWellknownTask +import org.matrix.android.sdk.test.fakes.FakeMonarchy + +class DefaultGetHomeServerCapabilitiesTaskTest { + + private val capabilitiesAPI: CapabilitiesAPI = mockk() + private val unauthenticatedMediaAPI: UnauthenticatedMediaAPI = mockk() + private val authenticatedMediaAPI: AuthenticatedMediaAPI = mockk() + private val monarchy = FakeMonarchy() + private val globalErrorReceiver: GlobalErrorReceiver = mockk(relaxed = true) + private val getWellknownTask: GetWellknownTask = mockk() + private val configExtractor: IntegrationManagerConfigExtractor = mockk() + private val homeServerConnectionConfig: HomeServerConnectionConfig = mockk() + private val authMetadataAPI: AuthMetadataAPI = mockk() + + private val task = DefaultGetHomeServerCapabilitiesTask( + capabilitiesAPI, + unauthenticatedMediaAPI, + authenticatedMediaAPI, + monarchy.instance, + globalErrorReceiver, + getWellknownTask, + configExtractor, + homeServerConnectionConfig, + "userId", + authMetadataAPI + ) + + private val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity() + + @Before + fun setUp() { + coEvery { configExtractor.extract(any())} returns null + monarchy.givenWhereReturns(result = homeServerCapabilitiesEntity) + } + + private val wellKnownWithoutDelegation = WellknownResult.Prompt( + homeServerUrl = "https://test", + identityServerUrl = null, + wellKnown = WellKnown( + homeServer = mockk(), + identityServer = mockk(), + unstableDelegatedAuthConfig = null, + ) + ) + + private val wellKnownWithDelegationToTest1 = WellknownResult.Prompt( + homeServerUrl = "https://test", + identityServerUrl = null, + wellKnown = WellKnown( + homeServer = mockk(), + identityServer = mockk(), + unstableDelegatedAuthConfig = DelegatedAuthConfig( + issuer = "https://test1", + accountManagementUrl = "https://test1/account" + ) + ) + ) + + private val authMetadataForTest2 = AuthMetadata( + issuer = "https://test2", + accountManagementUri = "https://test2/account", + accountManagementActionsSupported = listOf("org.matrix.device_delete", "org.matrix.profile") + ) + + private val authMetadataForTest2WithoutAccountManagement = AuthMetadata( + issuer = "https://test2", + accountManagementUri = null, + accountManagementActionsSupported = null + ) + + @Test + fun `given no OAuth config, when execute, then fields are null`() = runTest { + // Given + coEvery { getWellknownTask.execute(any()) } throws Exception() + coEvery { authMetadataAPI.getAuthMetadata() } throws Exception() + + // When + task.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) + + // Then + homeServerCapabilitiesEntity.authenticationIssuer shouldBeEqualTo null + homeServerCapabilitiesEntity.externalAccountManagementUrl shouldBeEqualTo null + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions shouldBeEqualTo null + } + + @Test + fun `given well-known, when execute, populates fields`() = runTest { + // Given + coEvery { getWellknownTask.execute(any()) } returns wellKnownWithDelegationToTest1 + coEvery { authMetadataAPI.getAuthMetadata() } throws Exception() + + // When + task.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) + + // Then + homeServerCapabilitiesEntity.authenticationIssuer shouldBeEqualTo "https://test1" + homeServerCapabilitiesEntity.externalAccountManagementUrl shouldBeEqualTo "https://test1/account" + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions shouldBeEqualTo null + } + + @Test + fun `given auth metadata, when execute, populates fields`() = runTest { + // Given + coEvery { getWellknownTask.execute(any()) } returns wellKnownWithoutDelegation + coEvery { authMetadataAPI.getAuthMetadata() } returns authMetadataForTest2 + + + // When + task.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) + + // Then + homeServerCapabilitiesEntity.authenticationIssuer shouldBeEqualTo "https://test2" + homeServerCapabilitiesEntity.externalAccountManagementUrl shouldBeEqualTo "https://test2/account" + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions shouldBeEqualTo "org.matrix.device_delete,org.matrix.profile" + } + + @Test + fun `given well-known and auth metadata, when execute, treats auth metadata as authoritative`() = runTest { + // Given + coEvery { getWellknownTask.execute(any()) } returns wellKnownWithDelegationToTest1 + coEvery { authMetadataAPI.getAuthMetadata() } returns authMetadataForTest2WithoutAccountManagement + + // When + task.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) + + // Then + homeServerCapabilitiesEntity.authenticationIssuer shouldBeEqualTo "https://test2" + homeServerCapabilitiesEntity.externalAccountManagementUrl shouldBeEqualTo null + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions shouldBeEqualTo null + } +} From 5117c9363952be63069c24f3677e2155405c8dc0 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 19 Dec 2025 11:15:55 +0000 Subject: [PATCH 4/9] Changelog --- changelog.d/9102.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/9102.misc diff --git a/changelog.d/9102.misc b/changelog.d/9102.misc new file mode 100644 index 00000000000..705a7a57fbd --- /dev/null +++ b/changelog.d/9102.misc @@ -0,0 +1 @@ +Update OAuth-awareness to support the stable version of MSC3824. From 4d46daf0d266d62b4134103cefd81e9b1c5cb625 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 19 Dec 2025 11:40:42 +0000 Subject: [PATCH 5/9] Lint --- .../org/matrix/android/sdk/api/auth/data/AuthMetadata.kt | 1 - .../sdk/api/session/homeserver/HomeServerCapabilities.kt | 4 +--- .../sdk/internal/session/homeserver/AuthMetadataAPI.kt | 1 - .../session/homeserver/GetHomeServerCapabilitiesTask.kt | 6 +++--- .../homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt | 3 +-- .../app/features/settings/devices/DevicesViewModel.kt | 2 +- 6 files changed, 6 insertions(+), 11 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt index 80a7066671b..f78e95c6f1b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.auth.data import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.api.extensions.orFalse /** * This is a subset of the server metadata discovery for the OAuth 2.0 API diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index 4536b527fb2..3dae2d4f604 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -16,8 +16,6 @@ package org.matrix.android.sdk.api.session.homeserver -import org.matrix.android.sdk.api.extensions.orFalse - data class HomeServerCapabilities( /** * True if it is possible to change the password of the account. @@ -172,7 +170,7 @@ data class HomeServerCapabilities( fun getLogoutDeviceURL(deviceId: String): String? { if (externalAccountManagementUrl == null) { - return null; + return null } // default to the stable value: diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt index 9a12cbc2166..fbbee8de47e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.internal.session.homeserver import org.matrix.android.sdk.api.auth.data.AuthMetadata -import org.matrix.android.sdk.internal.auth.version.Versions import org.matrix.android.sdk.internal.network.NetworkConstants import retrofit2.http.GET 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 00de4b986d8..06895de8acd 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 @@ -110,7 +110,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( executeRequest(globalErrorReceiver = null) { authMetadataAPI.getAuthMetadata() } - }.getOrNull(); + }.getOrNull() // Domain may include a port (eg, matrix.org:8080) // Per https://spec.matrix.org/latest/client-server-api/#well-known-uri we should extract the hostname from the server name @@ -191,8 +191,8 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( // If the server returns OAuth 2.0 metadata then prefer that over the well-known values: if (authMetadata != null) { - homeServerCapabilitiesEntity.authenticationIssuer = authMetadata.issuer; - homeServerCapabilitiesEntity.externalAccountManagementUrl = authMetadata.accountManagementUri; + homeServerCapabilitiesEntity.authenticationIssuer = authMetadata.issuer + homeServerCapabilitiesEntity.externalAccountManagementUrl = authMetadata.accountManagementUri homeServerCapabilitiesEntity.externalAccountManagementSupportedActions = if (authMetadata.accountManagementActionsSupported != null) authMetadata.accountManagementActionsSupported.joinToString(",") else null } diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt index 7ce6758a2c5..6872786bdd2 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt @@ -64,7 +64,7 @@ class DefaultGetHomeServerCapabilitiesTaskTest { @Before fun setUp() { - coEvery { configExtractor.extract(any())} returns null + coEvery { configExtractor.extract(any()) } returns null monarchy.givenWhereReturns(result = homeServerCapabilitiesEntity) } @@ -139,7 +139,6 @@ class DefaultGetHomeServerCapabilitiesTaskTest { coEvery { getWellknownTask.execute(any()) } returns wellKnownWithoutDelegation coEvery { authMetadataAPI.getAuthMetadata() } returns authMetadataForTest2 - // When task.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 0282bf9a73b..3ec7cd64aee 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -337,7 +337,7 @@ class DevicesViewModel @AssistedInject constructor( private fun handleDelete(action: DevicesAction.Delete) { val deviceId = action.deviceId - val externalLogoutDeviceUrl = session.homeServerCapabilitiesService().getHomeServerCapabilities().getLogoutDeviceURL(deviceId); + val externalLogoutDeviceUrl = session.homeServerCapabilitiesService().getHomeServerCapabilities().getLogoutDeviceURL(deviceId) if (externalLogoutDeviceUrl != null) { // Open external browser to delete this session _viewEvents.post( From 9af7512537bdadff30bb9fdb92656cff2bfb668a Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 19 Dec 2025 11:57:10 +0000 Subject: [PATCH 6/9] Lint --- .../sdk/api/session/homeserver/HomeServerCapabilities.kt | 2 +- .../android/sdk/internal/auth/data/LoginFlowResponse.kt | 4 ++-- .../session/homeserver/GetHomeServerCapabilitiesTask.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index 3dae2d4f604..5404eecc496 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -87,7 +87,7 @@ data class HomeServerCapabilities( val externalAccountManagementUrl: String? = null, /** - * External account management supported actions for use with OAuth API, provided by MSC4191 /auth_metadata discovery + * External account management supported actions for use with OAuth API, provided by MSC4191 /auth_metadata discovery. */ val externalAccountManagementSupportedActions: List? = null, 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 35972d98933..6d8d02fabb2 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 @@ -57,8 +57,8 @@ internal data class LoginFlow( /** * Unstable name from MSC3824. * - * @deprecated Use {@link oauthAwarePreferred} instead. */ + @Deprecated("Use oauthAwarePreferred instead") @Json(name = "org.matrix.msc3824.delegated_oidc_compatibility") val unstableDelegatedOidcCompatibility: Boolean? = null, @@ -70,6 +70,6 @@ internal data class LoginFlow( @Json(name = "get_login_token") val getLoginToken: Boolean? = null ) { - val delegatedOidcCompatibility: Boolean + @Suppress("DEPRECATION") val delegatedOidcCompatibility: Boolean get() = this.oauthAwarePreferred.orFalse() || this.unstableDelegatedOidcCompatibility.orFalse() } 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 06895de8acd..31d71286c91 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 @@ -193,7 +193,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( if (authMetadata != null) { homeServerCapabilitiesEntity.authenticationIssuer = authMetadata.issuer homeServerCapabilitiesEntity.externalAccountManagementUrl = authMetadata.accountManagementUri - homeServerCapabilitiesEntity.externalAccountManagementSupportedActions = if (authMetadata.accountManagementActionsSupported != null) authMetadata.accountManagementActionsSupported.joinToString(",") else null + homeServerCapabilitiesEntity.externalAccountManagementSupportedActions = authMetadata.accountManagementActionsSupported?.joinToString(",") } homeServerCapabilitiesEntity.canLoginWithQrCode = canLoginWithQrCode(getCapabilitiesResult, getVersionResult) From 0367786ccfa3ffbfb63cc2fc4f21cfb0c378318b Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 7 Jan 2026 12:19:28 +0000 Subject: [PATCH 7/9] Update matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt Co-authored-by: Benoit Marty --- .../java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt index f78e95c6f1b..62a2382842a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/AuthMetadata.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Matrix.org Foundation C.I.C. + * Copyright 2026 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 88c53c2b559d97000e2a0ce4bbf346621281f511 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 7 Jan 2026 12:39:46 +0000 Subject: [PATCH 8/9] Remove unused file --- .../session/homeserver/AuthMetadataModule.kt | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt deleted file mode 100644 index a3efe04a141..00000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataModule.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * 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.session.homeserver - -import dagger.Binds -import dagger.Module -import dagger.Provides -import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.wellknown.WellknownModule -import retrofit2.Retrofit - -@Module(includes = [WellknownModule::class]) -internal abstract class AuthMetadataModule { - - @Module - companion object { - @Provides - @JvmStatic - @SessionScope - fun providesAuthMetadataAPI(retrofit: Retrofit): AuthMetadataAPI { - return retrofit.create(AuthMetadataAPI::class.java) - } - } - - @Binds - abstract fun bindGetHomeServerCapabilitiesTask(task: DefaultGetHomeServerCapabilitiesTask): GetHomeServerCapabilitiesTask -} From df2bf39d4d9e4544b3c59c293e00ea7de2d32fcc Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 7 Jan 2026 17:22:20 +0000 Subject: [PATCH 9/9] Be consistent with copyright year --- .../android/sdk/internal/session/homeserver/AuthMetadataAPI.kt | 2 +- .../sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt | 2 +- .../homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt index fbbee8de47e..cf6cab289dc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/AuthMetadataAPI.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 The Matrix.org Foundation C.I.C. + * Copyright 2026 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/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt index 9bb1f1df841..75a828fccec 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 The Matrix.org Foundation C.I.C. + * Copyright 2026 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/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt index 6872786bdd2..fd228578c7f 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTaskTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 The Matrix.org Foundation C.I.C. + * Copyright 2026 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.