Use embedded version of Element Call (#4470)
* Use embedded version of Element Call: for in-app room calls, the app will use an embedded version of Element Call shipped with the app instead of using an external service. * Remove `ElementCallBaseUrlProvider` so we don't use the Element well known file to get the base URL anymore * Remove `ElementCallConfig.DEFAULT_BASE_URL` since it's not used anymore * Restore the usage of the custom EC base URL in developer settings as the actual base URL, it present * Add a way to customise the embedded EC analytic credentials * Update CI to use the EC analytic credentials as secrets * Improve the custom URL placeholder to include the `/room` suffix
This commit is contained in:
parent
03f4122b3f
commit
ba626fc173
32 changed files with 177 additions and 288 deletions
|
|
@ -189,12 +189,12 @@ class RustMatrixAuthenticationService @Inject constructor(
|
|||
return withContext(coroutineDispatchers.io) {
|
||||
runCatching {
|
||||
val client = currentClient ?: error("You need to call `setHomeserver()` first")
|
||||
val oAuthAuthenticationData = client.urlForOidc(
|
||||
val oAuthAuthorizationData = client.urlForOidc(
|
||||
oidcConfiguration = oidcConfigurationProvider.get(),
|
||||
prompt = prompt.toRustPrompt(),
|
||||
)
|
||||
val url = oAuthAuthenticationData.loginUrl()
|
||||
pendingOAuthAuthorizationData = oAuthAuthenticationData
|
||||
val url = oAuthAuthorizationData.loginUrl()
|
||||
pendingOAuthAuthorizationData = oAuthAuthorizationData
|
||||
OidcDetails(url)
|
||||
}.mapFailure { failure ->
|
||||
failure.mapAuthenticationException()
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector 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.libraries.matrix.impl.call
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.call.ElementCallBaseUrlProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultElementCallBaseUrlProvider @Inject constructor(
|
||||
private val elementWellKnownParser: ElementWellKnownParser,
|
||||
) : ElementCallBaseUrlProvider {
|
||||
override suspend fun provides(matrixClient: MatrixClient): String? {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(matrixClient.userIdServerName())
|
||||
append("/.well-known/element/element.json")
|
||||
}
|
||||
return matrixClient.getUrl(url)
|
||||
.onFailure { failure ->
|
||||
Timber.w(failure, "Failed to fetch well-known element.json")
|
||||
}
|
||||
.getOrNull()
|
||||
?.let { wellKnownStr ->
|
||||
elementWellKnownParser.parse(wellKnownStr)
|
||||
.onFailure { failure ->
|
||||
// Can be a HTML 404.
|
||||
Timber.w(failure, "Failed to parse content")
|
||||
}
|
||||
.getOrNull()
|
||||
}
|
||||
?.call
|
||||
?.widgetUrl
|
||||
}
|
||||
}
|
||||
|
|
@ -8,15 +8,13 @@
|
|||
package io.element.android.libraries.matrix.impl.widget
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.appconfig.RageshakeConfig
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.core.meta.BuildType
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.widget.CallAnalyticCredentialsProvider
|
||||
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
import io.element.android.services.analytics.api.store.AnalyticsStore
|
||||
import io.element.android.services.analyticsproviders.posthog.PosthogEndpointConfigProvider
|
||||
import io.element.android.services.analyticsproviders.sentry.SentryConfig
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.flow.first
|
||||
import org.matrix.rustcomponents.sdk.EncryptionSystem
|
||||
import org.matrix.rustcomponents.sdk.VirtualElementCallWidgetOptions
|
||||
|
|
@ -27,12 +25,11 @@ import org.matrix.rustcomponents.sdk.Intent as CallIntent
|
|||
@ContributesBinding(AppScope::class)
|
||||
class DefaultCallWidgetSettingsProvider @Inject constructor(
|
||||
private val buildMeta: BuildMeta,
|
||||
private val posthogEndpointConfigProvider: PosthogEndpointConfigProvider,
|
||||
private val analyticsStore: AnalyticsStore,
|
||||
private val callAnalyticsCredentialsProvider: CallAnalyticCredentialsProvider,
|
||||
private val analyticsService: AnalyticsService,
|
||||
) : CallWidgetSettingsProvider {
|
||||
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean): MatrixWidgetSettings {
|
||||
val analyticsEnabled = analyticsStore.userConsentFlow.first()
|
||||
val posthogEndpointConfig = posthogEndpointConfigProvider.provide()
|
||||
val isAnalyticsEnabled = analyticsService.getUserConsent().first()
|
||||
val options = VirtualElementCallWidgetOptions(
|
||||
elementCallUrl = baseUrl,
|
||||
widgetId = widgetId,
|
||||
|
|
@ -44,12 +41,12 @@ class DefaultCallWidgetSettingsProvider @Inject constructor(
|
|||
encryption = if (encrypted) EncryptionSystem.PerParticipantKeys else EncryptionSystem.Unencrypted,
|
||||
intent = CallIntent.START_CALL,
|
||||
hideScreensharing = false,
|
||||
posthogUserId = null,
|
||||
posthogApiHost = posthogEndpointConfig.host.takeIf { analyticsEnabled },
|
||||
posthogApiKey = posthogEndpointConfig.apiKey.takeIf { analyticsEnabled },
|
||||
rageshakeSubmitUrl = RageshakeConfig.BUG_REPORT_URL,
|
||||
sentryDsn = SentryConfig.DSN.takeIf { analyticsEnabled },
|
||||
sentryEnvironment = if (buildMeta.buildType == BuildType.RELEASE) SentryConfig.ENV_RELEASE else SentryConfig.ENV_DEBUG,
|
||||
posthogUserId = callAnalyticsCredentialsProvider.posthogUserId.takeIf { isAnalyticsEnabled },
|
||||
posthogApiHost = callAnalyticsCredentialsProvider.posthogApiHost.takeIf { isAnalyticsEnabled },
|
||||
posthogApiKey = callAnalyticsCredentialsProvider.posthogApiKey.takeIf { isAnalyticsEnabled },
|
||||
rageshakeSubmitUrl = callAnalyticsCredentialsProvider.rageshakeSubmitUrl,
|
||||
sentryDsn = callAnalyticsCredentialsProvider.sentryDsn.takeIf { isAnalyticsEnabled },
|
||||
sentryEnvironment = if (buildMeta.buildType == BuildType.RELEASE) "RELEASE" else "DEBUG",
|
||||
parentUrl = null,
|
||||
hideHeader = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector 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.libraries.matrix.impl.call
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.matrix.rustcomponents.sdk.ElementCallWellKnown
|
||||
import org.matrix.rustcomponents.sdk.ElementWellKnown
|
||||
|
||||
class DefaultElementCallBaseUrlProviderTest {
|
||||
@Test
|
||||
fun `provides returns null when getUrl returns an error`() = runTest {
|
||||
val userIdServerNameLambda = lambdaRecorder<String> { "example.com" }
|
||||
val getUrlLambda = lambdaRecorder<String, Result<String>> { _ ->
|
||||
Result.failure(AN_EXCEPTION)
|
||||
}
|
||||
val sut = DefaultElementCallBaseUrlProvider(
|
||||
FakeElementWellKnownParser(
|
||||
Result.success(createElementWellKnown(""))
|
||||
)
|
||||
)
|
||||
val matrixClient = FakeMatrixClient(
|
||||
userIdServerNameLambda = userIdServerNameLambda,
|
||||
getUrlLambda = getUrlLambda,
|
||||
)
|
||||
val result = sut.provides(matrixClient)
|
||||
assertThat(result).isNull()
|
||||
userIdServerNameLambda.assertions().isCalledOnce()
|
||||
getUrlLambda.assertions().isCalledOnce()
|
||||
.with(value("https://example.com/.well-known/element/element.json"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `provides returns null when content parsing fails`() = runTest {
|
||||
val userIdServerNameLambda = lambdaRecorder<String> { "example.com" }
|
||||
val getUrlLambda = lambdaRecorder<String, Result<String>> { _ ->
|
||||
Result.success("""{"call":{"widget_url":"https://example.com/call"}}""")
|
||||
}
|
||||
val sut = DefaultElementCallBaseUrlProvider(
|
||||
createFakeElementWellKnownParser(
|
||||
Result.failure(AN_EXCEPTION)
|
||||
)
|
||||
)
|
||||
val matrixClient = FakeMatrixClient(
|
||||
userIdServerNameLambda = userIdServerNameLambda,
|
||||
getUrlLambda = getUrlLambda,
|
||||
)
|
||||
val result = sut.provides(matrixClient)
|
||||
assertThat(result).isNull()
|
||||
userIdServerNameLambda.assertions().isCalledOnce()
|
||||
getUrlLambda.assertions().isCalledOnce()
|
||||
.with(value("https://example.com/.well-known/element/element.json"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `provides returns value when getUrl returns correct content`() = runTest {
|
||||
val userIdServerNameLambda = lambdaRecorder<String> { "example.com" }
|
||||
val getUrlLambda = lambdaRecorder<String, Result<String>> { _ ->
|
||||
Result.success("""{"call":{"widget_url":"https://example.com/call"}}""")
|
||||
}
|
||||
val sut = DefaultElementCallBaseUrlProvider(
|
||||
createFakeElementWellKnownParser(
|
||||
Result.success(createElementWellKnown("aUrl"))
|
||||
)
|
||||
)
|
||||
val matrixClient = FakeMatrixClient(
|
||||
userIdServerNameLambda = userIdServerNameLambda,
|
||||
getUrlLambda = getUrlLambda,
|
||||
)
|
||||
val result = sut.provides(matrixClient)
|
||||
assertThat(result).isEqualTo("aUrl")
|
||||
userIdServerNameLambda.assertions().isCalledOnce()
|
||||
getUrlLambda.assertions().isCalledOnce()
|
||||
.with(value("https://example.com/.well-known/element/element.json"))
|
||||
}
|
||||
|
||||
private fun createFakeElementWellKnownParser(result: Result<ElementWellKnown>): FakeElementWellKnownParser {
|
||||
return FakeElementWellKnownParser(result)
|
||||
}
|
||||
|
||||
private fun createElementWellKnown(widgetUrl: String): ElementWellKnown {
|
||||
return ElementWellKnown(
|
||||
call = ElementCallWellKnown(
|
||||
widgetUrl = widgetUrl,
|
||||
),
|
||||
registrationHelperUrl = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue