mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 21:32:34 +00:00
Apply the GetUrlResolver pattern using unauthenticated matrix clients where possible
This commit is contained in:
committed by
Jorge Martin Espinosa
parent
25eca29cd2
commit
90d4fbe0bd
+7
-1
@@ -10,6 +10,7 @@ package io.element.android.features.enterprise.api
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import io.element.android.compound.colors.SemanticColorsLightDark
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -17,7 +18,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
interface EnterpriseService {
|
||||
val isEnterpriseBuild: Boolean
|
||||
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
|
||||
suspend fun tweakMasUrl(url: String, homeserver: String): String
|
||||
suspend fun tweakMasUrl(url: String, homeserver: String, getUrlResolver: GetUrlResolver): String
|
||||
fun defaultHomeserverList(): List<String>
|
||||
suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean
|
||||
|
||||
@@ -47,6 +48,11 @@ interface EnterpriseService {
|
||||
*/
|
||||
fun overriddenElementWellKnown(): ElementWellKnown?
|
||||
|
||||
/**
|
||||
* Gets the Element Server Suite (ESS) config endpoint URL for the given domain.
|
||||
*/
|
||||
fun essConfigEndpointUrl(domain: String): String?
|
||||
|
||||
companion object {
|
||||
const val ANY_ACCOUNT_PROVIDER = "*"
|
||||
}
|
||||
|
||||
+4
-1
@@ -14,6 +14,7 @@ import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.compound.colors.SemanticColorsLightDark
|
||||
import io.element.android.features.enterprise.api.BugReportUrl
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -24,7 +25,7 @@ class DefaultEnterpriseService : EnterpriseService {
|
||||
override val isEnterpriseBuild = false
|
||||
|
||||
override suspend fun isEnterpriseUser(sessionId: SessionId) = false
|
||||
override suspend fun tweakMasUrl(url: String, homeserver: String) = url
|
||||
override suspend fun tweakMasUrl(url: String, homeserver: String, getUrlResolver: GetUrlResolver) = url
|
||||
override fun defaultHomeserverList(): List<String> = emptyList()
|
||||
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true
|
||||
|
||||
@@ -48,4 +49,6 @@ class DefaultEnterpriseService : EnterpriseService {
|
||||
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? = null
|
||||
|
||||
override fun overriddenElementWellKnown(): ElementWellKnown? = null
|
||||
|
||||
override fun essConfigEndpointUrl(domain: String): String? = null
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.enterprise.impl.scanner
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.scanner.ContentScannerUrlProvider
|
||||
|
||||
/**
|
||||
* Default FOSS implementation of [ContentScannerUrlProvider] that returns `null` for the content scanner URL.
|
||||
*/
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultContentScannerUrlProvider : ContentScannerUrlProvider {
|
||||
override suspend fun getContentScannerUrl(sessionId: SessionId): Result<String?> = Result.success(null)
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class Factory : ContentScannerUrlProvider.Factory {
|
||||
override fun create(getUrlResolver: GetUrlResolver): ContentScannerUrlProvider {
|
||||
return DefaultContentScannerUrlProvider()
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-10
@@ -13,13 +13,15 @@ import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.features.login.api.accesscontrol.AccountProviderAccessControl
|
||||
import io.element.android.features.login.impl.changeserver.AccountProviderAccessException
|
||||
import io.element.android.libraries.core.uri.ensureProtocol
|
||||
import io.element.android.libraries.matrix.api.TemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultAccountProviderAccessControl(
|
||||
private val enterpriseService: EnterpriseService,
|
||||
private val wellknownRetriever: WellknownRetriever,
|
||||
private val wellknownRetrieverFactory: WellknownRetriever.Factory,
|
||||
private val temporaryMatrixClientFactory: TemporaryMatrixClientFactory,
|
||||
) : AccountProviderAccessControl {
|
||||
override suspend fun isAllowedToConnectToAccountProvider(accountProviderUrl: String) = try {
|
||||
assertIsAllowedToConnectToAccountProvider(
|
||||
@@ -38,14 +40,21 @@ class DefaultAccountProviderAccessControl(
|
||||
) {
|
||||
if (enterpriseService.isEnterpriseBuild.not()) {
|
||||
// Ensure that Element Pro is not required for this account provider
|
||||
val wellKnown = wellknownRetriever.getElementWellKnown(
|
||||
baseUrl = accountProviderUrl.ensureProtocol(),
|
||||
).dataOrNull()
|
||||
if (wellKnown?.enforceElementPro == true) {
|
||||
throw AccountProviderAccessException.NeedElementProException(
|
||||
unauthorisedAccountProviderTitle = title,
|
||||
applicationId = ELEMENT_PRO_APPLICATION_ID,
|
||||
)
|
||||
val temporaryMatrixClient = temporaryMatrixClientFactory.createTemporaryMatrixClient(accountProviderUrl).getOrThrow()
|
||||
temporaryMatrixClient.use {
|
||||
val wellknownRetriever = wellknownRetrieverFactory.create(temporaryMatrixClient)
|
||||
val wellKnown = wellknownRetriever.getElementWellKnown(
|
||||
host = accountProviderUrl,
|
||||
// It's expected this is hardcoded to the well-known endpoint
|
||||
source = EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT,
|
||||
).dataOrNull()
|
||||
|
||||
if (wellKnown?.enforceElementPro == true) {
|
||||
throw AccountProviderAccessException.NeedElementProException(
|
||||
unauthorisedAccountProviderTitle = title,
|
||||
applicationId = ELEMENT_PRO_APPLICATION_ID,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enterpriseService.isAllowedToConnectToHomeserver(accountProviderUrl).not()) {
|
||||
|
||||
+22
-12
@@ -13,6 +13,8 @@ import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.appconfig.AuthenticationConfig
|
||||
import io.element.android.features.login.impl.screens.createaccount.AccountCreationNotSupported
|
||||
import io.element.android.libraries.matrix.api.TemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import timber.log.Timber
|
||||
|
||||
@@ -22,24 +24,32 @@ interface WebClientUrlForAuthenticationRetriever {
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultWebClientUrlForAuthenticationRetriever(
|
||||
private val wellknownRetriever: WellknownRetriever,
|
||||
private val wellknownRetrieverFactory: WellknownRetriever.Factory,
|
||||
private val temporaryMatrixClientFactory: TemporaryMatrixClientFactory,
|
||||
) : WebClientUrlForAuthenticationRetriever {
|
||||
override suspend fun retrieve(homeServerUrl: String): String {
|
||||
if (homeServerUrl != AuthenticationConfig.MATRIX_ORG_URL) {
|
||||
Timber.w("Temporary account creation flow is only supported on matrix.org")
|
||||
throw AccountCreationNotSupported()
|
||||
}
|
||||
val wellknown = wellknownRetriever.getElementWellKnown(homeServerUrl).dataOrNull()
|
||||
?: throw AccountCreationNotSupported()
|
||||
val registrationHelperUrl = wellknown.registrationHelperUrl
|
||||
return if (registrationHelperUrl != null) {
|
||||
registrationHelperUrl.toUri()
|
||||
.buildUpon()
|
||||
.appendQueryParameter("hs_url", homeServerUrl)
|
||||
.build()
|
||||
.toString()
|
||||
} else {
|
||||
throw AccountCreationNotSupported()
|
||||
val temporaryMatrixClient = temporaryMatrixClientFactory.createTemporaryMatrixClient(homeServerUrl).getOrThrow()
|
||||
return temporaryMatrixClient.use {
|
||||
val wellknownRetriever = wellknownRetrieverFactory.create(temporaryMatrixClient)
|
||||
val wellknown = wellknownRetriever.getElementWellKnown(
|
||||
host = homeServerUrl,
|
||||
source = EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT
|
||||
).dataOrNull() ?: throw AccountCreationNotSupported()
|
||||
|
||||
val registrationHelperUrl = wellknown.registrationHelperUrl
|
||||
if (registrationHelperUrl != null) {
|
||||
registrationHelperUrl.toUri()
|
||||
.buildUpon()
|
||||
.appendQueryParameter("hs_url", homeServerUrl)
|
||||
.build()
|
||||
.toString()
|
||||
} else {
|
||||
throw AccountCreationNotSupported()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user