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:
Benoit Marty
2025-05-05 17:46:17 +02:00
committed by GitHub
parent 024aa49e60
commit 9ea4853e88
20 changed files with 166 additions and 49 deletions

View File

@@ -106,14 +106,25 @@ android {
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName)") logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName)")
buildTypes { buildTypes {
val oidcRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
getByName("debug") { getByName("debug") {
resValue("string", "app_name", "$baseAppName dbg") resValue("string", "app_name", "$baseAppName dbg")
resValue(
"string",
"login_redirect_scheme",
"$oidcRedirectSchemeBase.debug",
)
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
} }
getByName("release") { getByName("release") {
resValue("string", "app_name", baseAppName) resValue("string", "app_name", baseAppName)
resValue(
"string",
"login_redirect_scheme",
oidcRedirectSchemeBase,
)
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
postprocessing { postprocessing {
@@ -131,6 +142,11 @@ android {
applicationIdSuffix = ".nightly" applicationIdSuffix = ".nightly"
versionNameSuffix = "-nightly" versionNameSuffix = "-nightly"
resValue("string", "app_name", "$baseAppName nightly") resValue("string", "app_name", "$baseAppName nightly")
resValue(
"string",
"login_redirect_scheme",
"$oidcRedirectSchemeBase.nightly",
)
matchingFallbacks += listOf("release") matchingFallbacks += listOf("release")
signingConfig = signingConfigs.getByName("nightly") signingConfig = signingConfigs.getByName("nightly")
@@ -284,6 +300,7 @@ dependencies {
testImplementation(libs.test.truth) testImplementation(libs.test.truth)
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.toolbox.test)
koverDependencies() koverDependencies()
} }

View File

@@ -60,8 +60,7 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<!-- Note: the scheme must match the scheme of the value of OidcConfig.REDIRECT_URI --> <data android:scheme="@string/login_redirect_scheme" />
<data android:scheme="io.element" />
</intent-filter> </intent-filter>
<!-- <!--
Element web links Element web links

View File

@@ -0,0 +1,25 @@
/*
* Copyright 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.x.oidc
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.services.toolbox.api.strings.StringProvider
import io.element.android.x.R
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultOidcRedirectUrlProvider @Inject constructor(
private val stringProvider: StringProvider,
) : OidcRedirectUrlProvider {
override fun provide() = buildString {
append(stringProvider.getString(R.string.login_redirect_scheme))
append(":/")
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 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.x.oidc
import com.google.common.truth.Truth.assertThat
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import io.element.android.x.R
import org.junit.Test
class DefaultOidcRedirectUrlProviderTest {
@Test
fun `test provide`() {
val stringProvider = FakeStringProvider(
defaultResult = "str"
)
val sut = DefaultOidcRedirectUrlProvider(
stringProvider = stringProvider,
)
val result = sut.provide()
assertThat(result).isEqualTo("str:/")
assertThat(stringProvider.lastResIdParam).isEqualTo(R.string.login_redirect_scheme)
}
}

View File

@@ -20,10 +20,11 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.libraries.matrix.test.A_THREAD_ID
import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.oidc.api.OidcAction import io.element.android.libraries.oidc.api.OidcAction
import io.element.android.libraries.oidc.impl.DefaultOidcIntentResolver import io.element.android.libraries.oidc.impl.DefaultOidcIntentResolver
import io.element.android.libraries.oidc.impl.OidcUrlParser import io.element.android.libraries.oidc.impl.DefaultOidcUrlParser
import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaError
import org.junit.Assert.assertThrows import org.junit.Assert.assertThrows
import org.junit.Test import org.junit.Test
@@ -119,7 +120,7 @@ class IntentResolverTest {
val sut = createIntentResolver() val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW action = Intent.ACTION_VIEW
data = "io.element:/callback?error=access_denied&state=IFF1UETGye2ZA8pO".toUri() data = "io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO".toUri()
} }
val result = sut.resolve(intent) val result = sut.resolve(intent)
assertThat(result).isEqualTo( assertThat(result).isEqualTo(
@@ -134,13 +135,13 @@ class IntentResolverTest {
val sut = createIntentResolver() val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW action = Intent.ACTION_VIEW
data = "io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB".toUri() data = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB".toUri()
} }
val result = sut.resolve(intent) val result = sut.resolve(intent)
assertThat(result).isEqualTo( assertThat(result).isEqualTo(
ResolvedIntent.Oidc( ResolvedIntent.Oidc(
oidcAction = OidcAction.Success( oidcAction = OidcAction.Success(
url = "io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" url = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
) )
) )
) )
@@ -151,7 +152,7 @@ class IntentResolverTest {
val sut = createIntentResolver() val sut = createIntentResolver()
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
action = Intent.ACTION_VIEW action = Intent.ACTION_VIEW
data = "io.element:/callback/invalid".toUri() data = "io.element.android:/invalid".toUri()
} }
assertThrows(IllegalStateException::class.java) { assertThrows(IllegalStateException::class.java) {
sut.resolve(intent) sut.resolve(intent)
@@ -246,7 +247,9 @@ class IntentResolverTest {
return IntentResolver( return IntentResolver(
deeplinkParser = DeeplinkParser(), deeplinkParser = DeeplinkParser(),
oidcIntentResolver = DefaultOidcIntentResolver( oidcIntentResolver = DefaultOidcIntentResolver(
oidcUrlParser = OidcUrlParser() oidcUrlParser = DefaultOidcUrlParser(
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
)
), ),
permalinkParser = FakePermalinkParser( permalinkParser = FakePermalinkParser(
result = permalinkParserResult result = permalinkParserResult

View File

@@ -11,7 +11,7 @@ Server list: https://github.com/element-hq/oidc-playground
Metadata iOS: (from https://github.com/element-hq/element-x-ios/blob/5f9d07377cebc4f21d9668b1a25f6e3bb22f64a1/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift#L28) Metadata iOS: (from https://github.com/element-hq/element-x-ios/blob/5f9d07377cebc4f21d9668b1a25f6e3bb22f64a1/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift#L28)
clientName: InfoPlistReader.main.bundleDisplayName, clientName: InfoPlistReader.main.bundleDisplayName,
redirectUri: "io.element:/callback", redirectUri: "io.element.android:/",
clientUri: "https://element.io", clientUri: "https://element.io",
tosUri: "https://element.io/user-terms-of-service", tosUri: "https://element.io/user-terms-of-service",
policyUri: "https://element.io/privacy" policyUri: "https://element.io/privacy"
@@ -19,7 +19,7 @@ policyUri: "https://element.io/privacy"
Android: Android:
clientName = "Element", clientName = "Element",
redirectUri = "io.element:/callback", redirectUri = "io.element.android:/",
clientUri = "https://element.io", clientUri = "https://element.io",
tosUri = "https://element.io/user-terms-of-service", tosUri = "https://element.io/user-terms-of-service",
policyUri = "https://element.io/privacy" policyUri = "https://element.io/privacy"

View File

@@ -27,13 +27,6 @@ android {
name = "CLIENT_URI", name = "CLIENT_URI",
value = BuildTimeConfig.URL_WEBSITE ?: "https://element.io" value = BuildTimeConfig.URL_WEBSITE ?: "https://element.io"
) )
buildConfigFieldStr(
name = "REDIRECT_URI",
value = buildString {
append(BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element")
append(":/callback")
}
)
buildConfigFieldStr( buildConfigFieldStr(
name = "LOGO_URI", name = "LOGO_URI",
value = BuildTimeConfig.URL_LOGO ?: "https://element.io/mobile-icon.png" value = BuildTimeConfig.URL_LOGO ?: "https://element.io/mobile-icon.png"

View File

@@ -12,11 +12,6 @@ import io.element.android.libraries.matrix.api.BuildConfig
object OidcConfig { object OidcConfig {
const val CLIENT_URI = BuildConfig.CLIENT_URI const val CLIENT_URI = BuildConfig.CLIENT_URI
// Notes:
// 1. the scheme must match the value declared in the AndroidManifest.xml
// 2. the scheme must be the reverse of the host of CLIENT_URI
const val REDIRECT_URI = BuildConfig.REDIRECT_URI
// Note: host must match with the host of CLIENT_URI // Note: host must match with the host of CLIENT_URI
const val LOGO_URI = BuildConfig.LOGO_URI const val LOGO_URI = BuildConfig.LOGO_URI

View File

@@ -0,0 +1,12 @@
/*
* Copyright 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.matrix.api.auth
interface OidcRedirectUrlProvider {
fun provide(): String
}

View File

@@ -9,15 +9,17 @@ package io.element.android.libraries.matrix.impl.auth
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.auth.OidcConfig import io.element.android.libraries.matrix.api.auth.OidcConfig
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
import org.matrix.rustcomponents.sdk.OidcConfiguration import org.matrix.rustcomponents.sdk.OidcConfiguration
import javax.inject.Inject import javax.inject.Inject
class OidcConfigurationProvider @Inject constructor( class OidcConfigurationProvider @Inject constructor(
private val buildMeta: BuildMeta, private val buildMeta: BuildMeta,
private val oidcRedirectUrlProvider: OidcRedirectUrlProvider,
) { ) {
fun get(): OidcConfiguration = OidcConfiguration( fun get(): OidcConfiguration = OidcConfiguration(
clientName = buildMeta.applicationName, clientName = buildMeta.applicationName,
redirectUri = OidcConfig.REDIRECT_URI, redirectUri = oidcRedirectUrlProvider.provide(),
clientUri = OidcConfig.CLIENT_URI, clientUri = OidcConfig.CLIENT_URI,
logoUri = OidcConfig.LOGO_URI, logoUri = OidcConfig.LOGO_URI,
tosUri = OidcConfig.TOS_URI, tosUri = OidcConfig.TOS_URI,

View File

@@ -8,7 +8,8 @@
package io.element.android.libraries.matrix.impl.auth package io.element.android.libraries.matrix.impl.auth
import com.google.common.truth.Truth.assertThat 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.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.core.aBuildMeta
import org.junit.Test import org.junit.Test
@@ -16,11 +17,12 @@ class OidcConfigurationProviderTest {
@Test @Test
fun get() { fun get() {
val result = OidcConfigurationProvider( val result = OidcConfigurationProvider(
aBuildMeta( buildMeta = aBuildMeta(
applicationName = "myName", applicationName = "myName",
) ),
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
).get() ).get()
assertThat(result.clientName).isEqualTo("myName") assertThat(result.clientName).isEqualTo("myName")
assertThat(result.redirectUri).isEqualTo(OidcConfig.REDIRECT_URI) assertThat(result.redirectUri).isEqualTo(FAKE_REDIRECT_URL)
} }
} }

View File

@@ -11,6 +11,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.impl.createRustMatrixClientFactory import io.element.android.libraries.matrix.impl.createRustMatrixClientFactory
import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory
import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider
import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.api.SessionStore
import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore
@@ -49,7 +50,10 @@ class RustMatrixAuthenticationServiceTest {
sessionStore = sessionStore, sessionStore = sessionStore,
rustMatrixClientFactory = rustMatrixClientFactory, rustMatrixClientFactory = rustMatrixClientFactory,
passphraseGenerator = FakePassphraseGenerator(), passphraseGenerator = FakePassphraseGenerator(),
oidcConfigurationProvider = OidcConfigurationProvider(aBuildMeta()), oidcConfigurationProvider = OidcConfigurationProvider(
buildMeta = aBuildMeta(),
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
),
) )
} }
} }

View File

@@ -0,0 +1,18 @@
/*
* Copyright 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.matrix.test.auth
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
const val FAKE_REDIRECT_URL = "io.element.android:/"
class FakeOidcRedirectUrlProvider(
private val provideResult: String = FAKE_REDIRECT_URL,
) : OidcRedirectUrlProvider {
override fun provide() = provideResult
}

View File

@@ -39,5 +39,5 @@ fun aBuildMeta(
gitRevision = gitRevision, gitRevision = gitRevision,
gitBranchName = gitBranchName, gitBranchName = gitBranchName,
flavorDescription = flavorDescription, flavorDescription = flavorDescription,
flavorShortDescription = flavorShortDescription flavorShortDescription = flavorShortDescription,
) )

View File

@@ -7,25 +7,34 @@
package io.element.android.libraries.oidc.impl 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 io.element.android.libraries.oidc.api.OidcAction
import javax.inject.Inject import javax.inject.Inject
fun interface OidcUrlParser {
fun parse(url: String): OidcAction?
}
/** /**
* Simple parser for oidc url interception. * Simple parser for oidc url interception.
* TODO Find documentation about the format. * 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. * Return a OidcAction, or null if the url is not a OidcUrl.
* Note: * Note:
* When user press button "Cancel", we get the url: * 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: * On success, we get:
* `io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB` * `io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB`
*/ */
fun parse(url: String): OidcAction? { override fun parse(url: String): OidcAction? {
if (url.startsWith(OidcConfig.REDIRECT_URI).not()) return null if (url.startsWith(oidcRedirectUrlProvider.provide()).not()) return null
if (url.contains("error=access_denied")) return OidcAction.GoBack if (url.contains("error=access_denied")) return OidcAction.GoBack
if (url.contains("code=")) return OidcAction.Success(url) if (url.contains("code=")) return OidcAction.Success(url)

View File

@@ -19,12 +19,14 @@ import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.inputs import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.auth.OidcDetails
import io.element.android.libraries.oidc.impl.OidcUrlParser
@ContributesNode(AppScope::class) @ContributesNode(AppScope::class)
class OidcNode @AssistedInject constructor( class OidcNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
presenterFactory: OidcPresenter.Factory, presenterFactory: OidcPresenter.Factory,
private val oidcUrlParser: OidcUrlParser,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
data class Inputs( data class Inputs(
val oidcDetails: OidcDetails, val oidcDetails: OidcDetails,
@@ -38,6 +40,7 @@ class OidcNode @AssistedInject constructor(
val state = presenter.present() val state = presenter.present()
OidcView( OidcView(
state = state, state = state,
oidcUrlParser = oidcUrlParser,
modifier = modifier, modifier = modifier,
onNavigateBack = ::navigateUp, onNavigateBack = ::navigateUp,
) )

View File

@@ -34,11 +34,11 @@ import io.element.android.libraries.oidc.impl.OidcUrlParser
@Composable @Composable
fun OidcView( fun OidcView(
state: OidcState, state: OidcState,
oidcUrlParser: OidcUrlParser,
onNavigateBack: () -> Unit, onNavigateBack: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val isPreview = LocalInspectionMode.current val isPreview = LocalInspectionMode.current
val oidcUrlParser = remember { OidcUrlParser() }
var webView by remember { mutableStateOf<WebView?>(null) } var webView by remember { mutableStateOf<WebView?>(null) }
fun shouldOverrideUrl(url: String): Boolean { fun shouldOverrideUrl(url: String): Boolean {
val action = oidcUrlParser.parse(url) val action = oidcUrlParser.parse(url)
@@ -111,6 +111,7 @@ fun OidcView(
internal fun OidcViewPreview(@PreviewParameter(OidcStateProvider::class) state: OidcState) = ElementPreview { internal fun OidcViewPreview(@PreviewParameter(OidcStateProvider::class) state: OidcState) = ElementPreview {
OidcView( OidcView(
state = state, state = state,
oidcUrlParser = { null },
onNavigateBack = {}, onNavigateBack = {},
) )
} }

View File

@@ -8,44 +8,51 @@
package io.element.android.libraries.oidc.impl package io.element.android.libraries.oidc.impl
import com.google.common.truth.Truth.assertThat 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 io.element.android.libraries.oidc.api.OidcAction
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
class OidcUrlParserTest { class DefaultOidcUrlParserTest {
@Test @Test
fun `test empty url`() { fun `test empty url`() {
val sut = OidcUrlParser() val sut = createDefaultOidcUrlParser()
assertThat(sut.parse("")).isNull() assertThat(sut.parse("")).isNull()
} }
@Test @Test
fun `test regular url`() { fun `test regular url`() {
val sut = OidcUrlParser() val sut = createDefaultOidcUrlParser()
assertThat(sut.parse("https://matrix.org")).isNull() assertThat(sut.parse("https://matrix.org")).isNull()
} }
@Test @Test
fun `test cancel url`() { fun `test cancel url`() {
val sut = OidcUrlParser() val sut = createDefaultOidcUrlParser()
val aCancelUrl = OidcConfig.REDIRECT_URI + "?error=access_denied&state=IFF1UETGye2ZA8pO" val aCancelUrl = "$FAKE_REDIRECT_URL?error=access_denied&state=IFF1UETGye2ZA8pO"
assertThat(sut.parse(aCancelUrl)).isEqualTo(OidcAction.GoBack) assertThat(sut.parse(aCancelUrl)).isEqualTo(OidcAction.GoBack)
} }
@Test @Test
fun `test success url`() { fun `test success url`() {
val sut = OidcUrlParser() val sut = createDefaultOidcUrlParser()
val aSuccessUrl = OidcConfig.REDIRECT_URI + "?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" val aSuccessUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
assertThat(sut.parse(aSuccessUrl)).isEqualTo(OidcAction.Success(aSuccessUrl)) assertThat(sut.parse(aSuccessUrl)).isEqualTo(OidcAction.Success(aSuccessUrl))
} }
@Test @Test
fun `test unknown url`() { fun `test unknown url`() {
val sut = OidcUrlParser() val sut = createDefaultOidcUrlParser()
val anUnknownUrl = OidcConfig.REDIRECT_URI + "?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" val anUnknownUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
Assert.assertThrows(IllegalStateException::class.java) { Assert.assertThrows(IllegalStateException::class.java) {
assertThat(sut.parse(anUnknownUrl)) assertThat(sut.parse(anUnknownUrl))
} }
} }
private fun createDefaultOidcUrlParser(): DefaultOidcUrlParser {
return DefaultOidcUrlParser(
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
)
}
} }

View File

@@ -21,7 +21,6 @@ object BuildTimeConfig {
val URL_ACCEPTABLE_USE: String? = null val URL_ACCEPTABLE_USE: String? = null
val URL_PRIVACY: String? = null val URL_PRIVACY: String? = null
val URL_POLICY: String? = null val URL_POLICY: String? = null
val SUPPORT_EMAIL_ADDRESS: String? = null
val SERVICES_MAPTILER_BASE_URL: String? = null val SERVICES_MAPTILER_BASE_URL: String? = null
val SERVICES_MAPTILER_APIKEY: String? = null val SERVICES_MAPTILER_APIKEY: String? = null
val SERVICES_MAPTILER_LIGHT_MAPID: String? = null val SERVICES_MAPTILER_LIGHT_MAPID: String? = null

View File

@@ -8,7 +8,7 @@
# Format is: # Format is:
# Error # Error
# adb shell am start -a android.intent.action.VIEW -d "io.element:/callback?error=access_denied\\&state=IFF1UETGye2ZA8pO" # adb shell am start -a android.intent.action.VIEW -d "io.element.android:/?error=access_denied\\&state=IFF1UETGye2ZA8pO"
# Success # Success
adb shell am start -a android.intent.action.VIEW -d "io.element:/callback?state=IFF1UETGye2ZA8pO\\&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" adb shell am start -a android.intent.action.VIEW -d "io.element.android:/?state=IFF1UETGye2ZA8pO\\&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"