Fix rustls failing the certification revocation checks on app start (#7817)

* Fix rustls failing the certification revocation checks on app start
* Also add dispatchers.io to `isElementProEnforced`
This commit is contained in:
Jorge Martin Espinosa
2026-09-30 12:10:59 +02:00
committed by GitHub
parent a2b2c2360a
commit 55b0273a4b
4 changed files with 17 additions and 7 deletions
@@ -15,6 +15,7 @@ import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.features.enterprise.api.BugReportUrl import io.element.android.features.enterprise.api.BugReportUrl
import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.androidutils.json.JsonProvider import io.element.android.libraries.androidutils.json.JsonProvider
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.extensions.mapCatchingExceptions import io.element.android.libraries.core.extensions.mapCatchingExceptions
import io.element.android.libraries.core.uri.ensureProtocol import io.element.android.libraries.core.uri.ensureProtocol
import io.element.android.libraries.matrix.api.ClientUrlContentFetcher import io.element.android.libraries.matrix.api.ClientUrlContentFetcher
@@ -23,6 +24,7 @@ import io.element.android.libraries.matrix.api.accountprovider.AccountProvider
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.withContext
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import timber.log.Timber import timber.log.Timber
@@ -31,15 +33,16 @@ import timber.log.Timber
class DefaultEnterpriseService( class DefaultEnterpriseService(
private val temporaryMatrixClientFactory: TemporaryMatrixClientFactory, private val temporaryMatrixClientFactory: TemporaryMatrixClientFactory,
private val jsonProvider: JsonProvider, private val jsonProvider: JsonProvider,
private val dispatchers: CoroutineDispatchers,
) : EnterpriseService { ) : EnterpriseService {
override suspend fun isEnterpriseUser(sessionId: SessionId) = false override suspend fun isEnterpriseUser(sessionId: SessionId) = false
override suspend fun tweakMasUrl(url: String, urlContentFetcher: ClientUrlContentFetcher) = url override suspend fun tweakMasUrl(url: String, urlContentFetcher: ClientUrlContentFetcher) = url
override fun accountProviderAllowList(): List<AccountProvider> = emptyList() override fun accountProviderAllowList(): List<AccountProvider> = emptyList()
override fun canConnectToAnyAccountProvider(): Boolean = true override fun canConnectToAnyAccountProvider(): Boolean = true
override suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider) = true override suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider) = true
override suspend fun isElementProEnforced(serverName: String): Boolean { override suspend fun isElementProEnforced(serverName: String): Boolean = withContext(dispatchers.io) {
val temporaryMatrixClient = temporaryMatrixClientFactory.create(serverName).getOrElse { return false } val temporaryMatrixClient = temporaryMatrixClientFactory.create(serverName).getOrElse { return@withContext false }
return temporaryMatrixClient.use { client -> temporaryMatrixClient.use { client ->
val baseUrl = serverName.ensureProtocol().removeSuffix("/") val baseUrl = serverName.ensureProtocol().removeSuffix("/")
// We'll always perform a network request here since we're not interested in any cached value. // We'll always perform a network request here since we're not interested in any cached value.
client.getUrl("$baseUrl/.well-known/element/element.json") client.getUrl("$baseUrl/.well-known/element/element.json")
@@ -21,19 +21,21 @@ import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderGeneric import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderGeneric
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.junit.Test import org.junit.Test
class DefaultEnterpriseServiceTest { class DefaultEnterpriseServiceTest {
@Test @Test
fun accountProviderAllowList() { fun accountProviderAllowList() = runTest {
val defaultEnterpriseService = createDefaultEnterpriseService() val defaultEnterpriseService = createDefaultEnterpriseService()
assertThat(defaultEnterpriseService.accountProviderAllowList()).isEmpty() assertThat(defaultEnterpriseService.accountProviderAllowList()).isEmpty()
} }
@Test @Test
fun `canConnectToAnyAccountProvider is always true`() { fun `canConnectToAnyAccountProvider is always true`() = runTest {
val defaultEnterpriseService = createDefaultEnterpriseService() val defaultEnterpriseService = createDefaultEnterpriseService()
assertThat(defaultEnterpriseService.canConnectToAnyAccountProvider()).isTrue() assertThat(defaultEnterpriseService.canConnectToAnyAccountProvider()).isTrue()
} }
@@ -132,11 +134,12 @@ class DefaultEnterpriseServiceTest {
closeLambda.assertions().isCalledOnce() closeLambda.assertions().isCalledOnce()
} }
private fun createDefaultEnterpriseService( private fun TestScope.createDefaultEnterpriseService(
client: FakeTemporaryMatrixClient = FakeTemporaryMatrixClient(), client: FakeTemporaryMatrixClient = FakeTemporaryMatrixClient(),
jsonProvider: JsonProvider = { Json } jsonProvider: JsonProvider = { Json }
) = DefaultEnterpriseService( ) = DefaultEnterpriseService(
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(createResult = { Result.success(client) }), temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(createResult = { Result.success(client) }),
jsonProvider = jsonProvider, jsonProvider = jsonProvider,
dispatchers = testCoroutineDispatchers(),
) )
} }
@@ -25,6 +25,7 @@ import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.SingleIn import dev.zacsweers.metro.SingleIn
import io.element.android.features.login.impl.BuildConfig import io.element.android.features.login.impl.BuildConfig
import io.element.android.libraries.androidutils.service.ServiceBinder import io.element.android.libraries.androidutils.service.ServiceBinder
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.core.uri.ensureProtocol import io.element.android.libraries.core.uri.ensureProtocol
import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.di.annotations.AppCoroutineScope
@@ -69,6 +70,7 @@ class DefaultElementClassicConnection(
private val coroutineScope: CoroutineScope, private val coroutineScope: CoroutineScope,
private val matrixAuthenticationService: MatrixAuthenticationService, private val matrixAuthenticationService: MatrixAuthenticationService,
private val homeServerLoginCompatibilityChecker: HomeServerLoginCompatibilityChecker, private val homeServerLoginCompatibilityChecker: HomeServerLoginCompatibilityChecker,
private val dispatchers: CoroutineDispatchers,
) : ElementClassicConnection { ) : ElementClassicConnection {
// Messenger for communicating with the service. // Messenger for communicating with the service.
private var messenger: Messenger? = null private var messenger: Messenger? = null
@@ -221,7 +223,7 @@ class DefaultElementClassicConnection(
fun onSessionReceived(data: Bundle) { fun onSessionReceived(data: Bundle) {
// The data must be extracted from the bundle before we launch the coroutine, else the bundle will be emptied // The data must be extracted from the bundle before we launch the coroutine, else the bundle will be emptied
val state = data.toElementClassicConnectionState() val state = data.toElementClassicConnectionState()
coroutineScope.launch { coroutineScope.launch(dispatchers.io) {
val updatedState = ensureHomeserverIsSupported(state) val updatedState = ensureHomeserverIsSupported(state)
emitState(updatedState) emitState(updatedState)
val userId = (updatedState as? ElementClassicConnectionState.ElementClassicReady)?.elementClassicSession?.userId val userId = (updatedState as? ElementClassicConnectionState.ElementClassicReady)?.elementClassicSession?.userId
@@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationSer
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.robolectric.RobolectricTest
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
@@ -499,5 +500,6 @@ class DefaultElementClassicConnectionTest : RobolectricTest() {
coroutineScope = coroutineScope, coroutineScope = coroutineScope,
matrixAuthenticationService = matrixAuthenticationService, matrixAuthenticationService = matrixAuthenticationService,
homeServerLoginCompatibilityChecker = homeServerLoginCompatibilityChecker, homeServerLoginCompatibilityChecker = homeServerLoginCompatibilityChecker,
dispatchers = testCoroutineDispatchers(),
) )
} }