Improve the callback uri format and customization. (#4664)
* Remove unused SUPPORT_EMAIL_ADDRESS * Improve the callback uri format and customization. Use io.element.android for the scheme of Oidc redirection for Element X. For nightly the scheme will be io.element.android.nightly For debug the scheme will be io.element.android.debug Element Pro is using `io.element`
This commit is contained in:
parent
1904c98c9a
commit
c61ee59528
20 changed files with 166 additions and 49 deletions
|
|
@ -7,25 +7,34 @@
|
|||
|
||||
package io.element.android.libraries.oidc.impl
|
||||
|
||||
import io.element.android.libraries.matrix.api.auth.OidcConfig
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
||||
import io.element.android.libraries.oidc.api.OidcAction
|
||||
import javax.inject.Inject
|
||||
|
||||
fun interface OidcUrlParser {
|
||||
fun parse(url: String): OidcAction?
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple parser for oidc url interception.
|
||||
* TODO Find documentation about the format.
|
||||
*/
|
||||
class OidcUrlParser @Inject constructor() {
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultOidcUrlParser @Inject constructor(
|
||||
private val oidcRedirectUrlProvider: OidcRedirectUrlProvider,
|
||||
) : OidcUrlParser {
|
||||
/**
|
||||
* Return a OidcAction, or null if the url is not a OidcUrl.
|
||||
* Note:
|
||||
* When user press button "Cancel", we get the url:
|
||||
* `io.element:/callback?error=access_denied&state=IFF1UETGye2ZA8pO`
|
||||
* `io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO`
|
||||
* On success, we get:
|
||||
* `io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB`
|
||||
* `io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB`
|
||||
*/
|
||||
fun parse(url: String): OidcAction? {
|
||||
if (url.startsWith(OidcConfig.REDIRECT_URI).not()) return null
|
||||
override fun parse(url: String): OidcAction? {
|
||||
if (url.startsWith(oidcRedirectUrlProvider.provide()).not()) return null
|
||||
if (url.contains("error=access_denied")) return OidcAction.GoBack
|
||||
if (url.contains("code=")) return OidcAction.Success(url)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,14 @@ import io.element.android.libraries.architecture.NodeInputs
|
|||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
||||
import io.element.android.libraries.oidc.impl.OidcUrlParser
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
class OidcNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
presenterFactory: OidcPresenter.Factory,
|
||||
private val oidcUrlParser: OidcUrlParser,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
data class Inputs(
|
||||
val oidcDetails: OidcDetails,
|
||||
|
|
@ -38,6 +40,7 @@ class OidcNode @AssistedInject constructor(
|
|||
val state = presenter.present()
|
||||
OidcView(
|
||||
state = state,
|
||||
oidcUrlParser = oidcUrlParser,
|
||||
modifier = modifier,
|
||||
onNavigateBack = ::navigateUp,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ import io.element.android.libraries.oidc.impl.OidcUrlParser
|
|||
@Composable
|
||||
fun OidcView(
|
||||
state: OidcState,
|
||||
oidcUrlParser: OidcUrlParser,
|
||||
onNavigateBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isPreview = LocalInspectionMode.current
|
||||
val oidcUrlParser = remember { OidcUrlParser() }
|
||||
var webView by remember { mutableStateOf<WebView?>(null) }
|
||||
fun shouldOverrideUrl(url: String): Boolean {
|
||||
val action = oidcUrlParser.parse(url)
|
||||
|
|
@ -111,6 +111,7 @@ fun OidcView(
|
|||
internal fun OidcViewPreview(@PreviewParameter(OidcStateProvider::class) state: OidcState) = ElementPreview {
|
||||
OidcView(
|
||||
state = state,
|
||||
oidcUrlParser = { null },
|
||||
onNavigateBack = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,44 +8,51 @@
|
|||
package io.element.android.libraries.oidc.impl
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.auth.OidcConfig
|
||||
import io.element.android.libraries.matrix.test.auth.FAKE_REDIRECT_URL
|
||||
import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider
|
||||
import io.element.android.libraries.oidc.api.OidcAction
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class OidcUrlParserTest {
|
||||
class DefaultOidcUrlParserTest {
|
||||
@Test
|
||||
fun `test empty url`() {
|
||||
val sut = OidcUrlParser()
|
||||
val sut = createDefaultOidcUrlParser()
|
||||
assertThat(sut.parse("")).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test regular url`() {
|
||||
val sut = OidcUrlParser()
|
||||
val sut = createDefaultOidcUrlParser()
|
||||
assertThat(sut.parse("https://matrix.org")).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test cancel url`() {
|
||||
val sut = OidcUrlParser()
|
||||
val aCancelUrl = OidcConfig.REDIRECT_URI + "?error=access_denied&state=IFF1UETGye2ZA8pO"
|
||||
val sut = createDefaultOidcUrlParser()
|
||||
val aCancelUrl = "$FAKE_REDIRECT_URL?error=access_denied&state=IFF1UETGye2ZA8pO"
|
||||
assertThat(sut.parse(aCancelUrl)).isEqualTo(OidcAction.GoBack)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test success url`() {
|
||||
val sut = OidcUrlParser()
|
||||
val aSuccessUrl = OidcConfig.REDIRECT_URI + "?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
|
||||
val sut = createDefaultOidcUrlParser()
|
||||
val aSuccessUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
|
||||
assertThat(sut.parse(aSuccessUrl)).isEqualTo(OidcAction.Success(aSuccessUrl))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test unknown url`() {
|
||||
val sut = OidcUrlParser()
|
||||
val anUnknownUrl = OidcConfig.REDIRECT_URI + "?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
|
||||
val sut = createDefaultOidcUrlParser()
|
||||
val anUnknownUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
|
||||
Assert.assertThrows(IllegalStateException::class.java) {
|
||||
assertThat(sut.parse(anUnknownUrl))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDefaultOidcUrlParser(): DefaultOidcUrlParser {
|
||||
return DefaultOidcUrlParser(
|
||||
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue