Rename OIDC components and variables to OAuth (#6686)

* Rename `OIDC` components and variables to `OAuth`. This matches the new behavior in the SDK.
This commit is contained in:
Jorge Martin Espinosa 2026-04-29 11:41:47 +02:00 committed by GitHub
parent 7dd81dc838
commit 367995303d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
96 changed files with 479 additions and 482 deletions

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.oauth.impl
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.oauth.api.OAuthAction
import io.element.android.libraries.oauth.api.OAuthActionFlow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableStateFlow
@ContributesBinding(AppScope::class)
@SingleIn(AppScope::class)
class DefaultOAuthActionFlow : OAuthActionFlow {
private val mutableStateFlow = MutableStateFlow<OAuthAction?>(null)
override fun post(oAuthAction: OAuthAction) {
mutableStateFlow.value = oAuthAction
}
override suspend fun collect(collector: FlowCollector<OAuthAction?>) {
mutableStateFlow.collect(collector)
}
override fun reset() {
mutableStateFlow.value = null
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.oauth.impl
import android.content.Intent
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.oauth.api.OAuthAction
import io.element.android.libraries.oauth.api.OAuthIntentResolver
@ContributesBinding(AppScope::class)
class DefaultOAuthIntentResolver(
private val oAuthUrlParser: OAuthUrlParser,
) : OAuthIntentResolver {
override fun resolve(intent: Intent): OAuthAction? {
return oAuthUrlParser.parse(intent.dataString.orEmpty())
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.oauth.impl
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider
import io.element.android.libraries.oauth.api.OAuthAction
fun interface OAuthUrlParser {
fun parse(url: String): OAuthAction?
}
/**
* Simple parser for OAuth url interception.
* TODO Find documentation about the format.
*/
@ContributesBinding(AppScope::class)
class DefaultOAuthUrlParser(
private val oAuthRedirectUrlProvider: OAuthRedirectUrlProvider,
) : OAuthUrlParser {
/**
* Return a [OAuthAction], or null if the url is not an OAuth url.
* Note:
* When user press button "Cancel", we get the url:
* `io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO`
* On success, we get:
* `io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB`
*/
override fun parse(url: String): OAuthAction? {
if (url.startsWith(oAuthRedirectUrlProvider.provide()).not()) return null
if (url.contains("error=access_denied")) return OAuthAction.GoBack()
if (url.contains("code=")) return OAuthAction.Success(url)
// Other case not supported, let's crash the app for now
error("Not supported: $url")
}
}

View file

@ -0,0 +1,33 @@
/*
* 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.libraries.oauth.impl
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.oauth.api.OAuthAction
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.junit.Test
class DefaultOAuthActionFlowTest {
@Test
fun `collect gets all the posted events`() = runTest {
val data = mutableListOf<OAuthAction?>()
val sut = DefaultOAuthActionFlow()
backgroundScope.launch {
sut.collect { action ->
data.add(action)
}
}
sut.post(OAuthAction.GoBack())
delay(1)
sut.reset()
delay(1)
assertThat(data).containsExactly(OAuthAction.GoBack(), null)
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.libraries.oauth.impl
import android.app.Activity
import android.content.Intent
import androidx.core.net.toUri
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider
import io.element.android.libraries.oauth.api.OAuthAction
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
@RunWith(RobolectricTestRunner::class)
class DefaultOAuthIntentResolverTest {
@Test
fun `test resolve OAuth go back`() {
val sut = createDefaultOAuthIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO".toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(OAuthAction.GoBack())
}
@Test
fun `test resolve OAuth success`() {
val sut = createDefaultOAuthIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB".toUri()
}
val result = sut.resolve(intent)
assertThat(result).isEqualTo(
OAuthAction.Success(
url = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
)
)
}
@Test
fun `test resolve OAuth invalid`() {
val sut = createDefaultOAuthIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW
data = "io.element.android:/invalid".toUri()
}
assertThrows(IllegalStateException::class.java) {
sut.resolve(intent)
}
}
private fun createDefaultOAuthIntentResolver(): DefaultOAuthIntentResolver {
return DefaultOAuthIntentResolver(
oAuthUrlParser = DefaultOAuthUrlParser(
oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(),
),
)
}
}

View file

@ -0,0 +1,58 @@
/*
* 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.libraries.oauth.impl
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.test.auth.FAKE_REDIRECT_URL
import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider
import io.element.android.libraries.oauth.api.OAuthAction
import org.junit.Assert
import org.junit.Test
class DefaultOAuthUrlParserTest {
@Test
fun `test empty url`() {
val sut = createDefaultOAuthUrlParser()
assertThat(sut.parse("")).isNull()
}
@Test
fun `test regular url`() {
val sut = createDefaultOAuthUrlParser()
assertThat(sut.parse("https://matrix.org")).isNull()
}
@Test
fun `test cancel url`() {
val sut = createDefaultOAuthUrlParser()
val aCancelUrl = "$FAKE_REDIRECT_URL?error=access_denied&state=IFF1UETGye2ZA8pO"
assertThat(sut.parse(aCancelUrl)).isEqualTo(OAuthAction.GoBack())
}
@Test
fun `test success url`() {
val sut = createDefaultOAuthUrlParser()
val aSuccessUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
assertThat(sut.parse(aSuccessUrl)).isEqualTo(OAuthAction.Success(aSuccessUrl))
}
@Test
fun `test unknown url`() {
val sut = createDefaultOAuthUrlParser()
val anUnknownUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
Assert.assertThrows(IllegalStateException::class.java) {
assertThat(sut.parse(anUnknownUrl))
}
}
private fun createDefaultOAuthUrlParser(): DefaultOAuthUrlParser {
return DefaultOAuthUrlParser(
oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(),
)
}
}