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:
parent
414da30d33
commit
1ef74f0cde
96 changed files with 479 additions and 482 deletions
|
|
@ -103,13 +103,13 @@ android {
|
||||||
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]")
|
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]")
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
val oidcRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
|
val oAuthRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
|
||||||
getByName("debug") {
|
getByName("debug") {
|
||||||
resValue("string", "app_name", "$baseAppName dbg")
|
resValue("string", "app_name", "$baseAppName dbg")
|
||||||
resValue(
|
resValue(
|
||||||
"string",
|
"string",
|
||||||
"login_redirect_scheme",
|
"login_redirect_scheme",
|
||||||
"$oidcRedirectSchemeBase.debug",
|
"$oAuthRedirectSchemeBase.debug",
|
||||||
)
|
)
|
||||||
applicationIdSuffix = ".debug"
|
applicationIdSuffix = ".debug"
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
|
@ -120,7 +120,7 @@ android {
|
||||||
resValue(
|
resValue(
|
||||||
"string",
|
"string",
|
||||||
"login_redirect_scheme",
|
"login_redirect_scheme",
|
||||||
oidcRedirectSchemeBase,
|
oAuthRedirectSchemeBase,
|
||||||
)
|
)
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ android {
|
||||||
resValue(
|
resValue(
|
||||||
"string",
|
"string",
|
||||||
"login_redirect_scheme",
|
"login_redirect_scheme",
|
||||||
"$oidcRedirectSchemeBase.nightly",
|
"$oAuthRedirectSchemeBase.nightly",
|
||||||
)
|
)
|
||||||
matchingFallbacks += listOf("release")
|
matchingFallbacks += listOf("release")
|
||||||
signingConfig = signingConfigs.getByName("nightly")
|
signingConfig = signingConfigs.getByName("nightly")
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@
|
||||||
android:scheme="elementx" />
|
android:scheme="elementx" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<!--
|
<!--
|
||||||
Oidc redirection
|
OAuth redirection
|
||||||
-->
|
-->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ package io.element.android.x.oidc
|
||||||
|
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import io.element.android.x.R
|
import io.element.android.x.R
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class DefaultOidcRedirectUrlProvider(
|
class DefaultOAuthRedirectUrlProvider(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
) : OidcRedirectUrlProvider {
|
) : OAuthRedirectUrlProvider {
|
||||||
override fun provide() = buildString {
|
override fun provide() = buildString {
|
||||||
append(stringProvider.getString(R.string.login_redirect_scheme))
|
append(stringProvider.getString(R.string.login_redirect_scheme))
|
||||||
append(":/")
|
append(":/")
|
||||||
|
|
@ -13,13 +13,13 @@ import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
import io.element.android.x.R
|
import io.element.android.x.R
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class DefaultOidcRedirectUrlProviderTest {
|
class DefaultOAuthRedirectUrlProviderTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test provide`() {
|
fun `test provide`() {
|
||||||
val stringProvider = FakeStringProvider(
|
val stringProvider = FakeStringProvider(
|
||||||
defaultResult = "str"
|
defaultResult = "str"
|
||||||
)
|
)
|
||||||
val sut = DefaultOidcRedirectUrlProvider(
|
val sut = DefaultOAuthRedirectUrlProvider(
|
||||||
stringProvider = stringProvider,
|
stringProvider = stringProvider,
|
||||||
)
|
)
|
||||||
val result = sut.provide()
|
val result = sut.provide()
|
||||||
|
|
@ -33,7 +33,7 @@ dependencies {
|
||||||
implementation(projects.libraries.deeplink.api)
|
implementation(projects.libraries.deeplink.api)
|
||||||
implementation(projects.libraries.featureflag.api)
|
implementation(projects.libraries.featureflag.api)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
implementation(projects.libraries.oidc.api)
|
implementation(projects.libraries.oauth.api)
|
||||||
implementation(projects.libraries.preferences.api)
|
implementation(projects.libraries.preferences.api)
|
||||||
implementation(projects.libraries.push.api)
|
implementation(projects.libraries.push.api)
|
||||||
implementation(projects.libraries.pushproviders.api)
|
implementation(projects.libraries.pushproviders.api)
|
||||||
|
|
@ -59,7 +59,7 @@ dependencies {
|
||||||
testImplementation(projects.features.login.test)
|
testImplementation(projects.features.login.test)
|
||||||
testImplementation(projects.features.share.test)
|
testImplementation(projects.features.share.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.oidc.test)
|
testImplementation(projects.libraries.oauth.test)
|
||||||
testImplementation(projects.libraries.preferences.test)
|
testImplementation(projects.libraries.preferences.test)
|
||||||
testImplementation(projects.libraries.push.test)
|
testImplementation(projects.libraries.push.test)
|
||||||
testImplementation(projects.libraries.pushproviders.test)
|
testImplementation(projects.libraries.pushproviders.test)
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.core.asEventId
|
import io.element.android.libraries.matrix.api.core.asEventId
|
||||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
import io.element.android.libraries.sessionstorage.api.LoggedInState
|
import io.element.android.libraries.sessionstorage.api.LoggedInState
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import io.element.android.libraries.ui.common.nodes.emptyNode
|
import io.element.android.libraries.ui.common.nodes.emptyNode
|
||||||
|
|
@ -95,7 +95,7 @@ class RootFlowNode(
|
||||||
private val signedOutEntryPoint: SignedOutEntryPoint,
|
private val signedOutEntryPoint: SignedOutEntryPoint,
|
||||||
private val accountSelectEntryPoint: AccountSelectEntryPoint,
|
private val accountSelectEntryPoint: AccountSelectEntryPoint,
|
||||||
private val intentResolver: IntentResolver,
|
private val intentResolver: IntentResolver,
|
||||||
private val oidcActionFlow: OidcActionFlow,
|
private val oAuthActionFlow: OAuthActionFlow,
|
||||||
private val featureFlagService: FeatureFlagService,
|
private val featureFlagService: FeatureFlagService,
|
||||||
private val announcementService: AnnouncementService,
|
private val announcementService: AnnouncementService,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
|
|
@ -392,7 +392,7 @@ class RootFlowNode(
|
||||||
navigateTo(resolvedIntent.deeplinkData)
|
navigateTo(resolvedIntent.deeplinkData)
|
||||||
}
|
}
|
||||||
is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params)
|
is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params)
|
||||||
is ResolvedIntent.Oidc -> onOidcAction(resolvedIntent.oidcAction)
|
is ResolvedIntent.OAuth -> onOAuthAction(resolvedIntent.oAuthAction)
|
||||||
is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData)
|
is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData)
|
||||||
is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.shareIntentData)
|
is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.shareIntentData)
|
||||||
}
|
}
|
||||||
|
|
@ -529,8 +529,8 @@ class RootFlowNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onOidcAction(oidcAction: OidcAction) {
|
private fun onOAuthAction(oAuthAction: OAuthAction) {
|
||||||
oidcActionFlow.post(oidcAction)
|
oAuthActionFlow.post(oAuthAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun attachSession(sessionId: SessionId): LoggedInFlowNode {
|
private suspend fun attachSession(sessionId: SessionId): LoggedInFlowNode {
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ import io.element.android.libraries.deeplink.api.DeeplinkData
|
||||||
import io.element.android.libraries.deeplink.api.DeeplinkParser
|
import io.element.android.libraries.deeplink.api.DeeplinkParser
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcIntentResolver
|
import io.element.android.libraries.oauth.api.OAuthIntentResolver
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
sealed interface ResolvedIntent {
|
sealed interface ResolvedIntent {
|
||||||
data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent
|
data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent
|
||||||
data class Oidc(val oidcAction: OidcAction) : ResolvedIntent
|
data class OAuth(val oAuthAction: OAuthAction) : ResolvedIntent
|
||||||
data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent
|
data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent
|
||||||
data class Login(val params: LoginParams) : ResolvedIntent
|
data class Login(val params: LoginParams) : ResolvedIntent
|
||||||
data class IncomingShare(val shareIntentData: ShareIntentData) : ResolvedIntent
|
data class IncomingShare(val shareIntentData: ShareIntentData) : ResolvedIntent
|
||||||
|
|
@ -34,7 +34,7 @@ sealed interface ResolvedIntent {
|
||||||
class IntentResolver(
|
class IntentResolver(
|
||||||
private val deeplinkParser: DeeplinkParser,
|
private val deeplinkParser: DeeplinkParser,
|
||||||
private val loginIntentResolver: LoginIntentResolver,
|
private val loginIntentResolver: LoginIntentResolver,
|
||||||
private val oidcIntentResolver: OidcIntentResolver,
|
private val oAuthIntentResolver: OAuthIntentResolver,
|
||||||
private val permalinkParser: PermalinkParser,
|
private val permalinkParser: PermalinkParser,
|
||||||
private val shareIntentHandler: ShareIntentHandler,
|
private val shareIntentHandler: ShareIntentHandler,
|
||||||
) {
|
) {
|
||||||
|
|
@ -45,9 +45,9 @@ class IntentResolver(
|
||||||
val deepLinkData = deeplinkParser.getFromIntent(intent)
|
val deepLinkData = deeplinkParser.getFromIntent(intent)
|
||||||
if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData)
|
if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData)
|
||||||
|
|
||||||
// Coming during login using Oidc?
|
// Coming during login using OAuth?
|
||||||
val oidcAction = oidcIntentResolver.resolve(intent)
|
val oAuthAction = oAuthIntentResolver.resolve(intent)
|
||||||
if (oidcAction != null) return ResolvedIntent.Oidc(oidcAction)
|
if (oAuthAction != null) return ResolvedIntent.OAuth(oAuthAction)
|
||||||
|
|
||||||
val actionViewData = intent
|
val actionViewData = intent
|
||||||
.takeIf { it.action == Intent.ACTION_VIEW }
|
.takeIf { it.action == Intent.ACTION_VIEW }
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ 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.permalink.FakePermalinkParser
|
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.test.FakeOidcIntentResolver
|
import io.element.android.libraries.oauth.test.FakeOAuthIntentResolver
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
@ -170,9 +170,9 @@ class IntentResolverTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test resolve oidc`() {
|
fun `test resolve OAuth`() {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
oidcIntentResolverResult = { OidcAction.GoBack() },
|
oAuthIntentResolverResult = { OAuthAction.GoBack() },
|
||||||
)
|
)
|
||||||
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
|
||||||
|
|
@ -180,8 +180,8 @@ class IntentResolverTest {
|
||||||
}
|
}
|
||||||
val result = sut.resolve(intent)
|
val result = sut.resolve(intent)
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).isEqualTo(
|
||||||
ResolvedIntent.Oidc(
|
ResolvedIntent.OAuth(
|
||||||
oidcAction = OidcAction.GoBack()
|
oAuthAction = OAuthAction.GoBack()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ class IntentResolverTest {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
loginIntentResolverResult = { null },
|
loginIntentResolverResult = { null },
|
||||||
permalinkParserResult = { permalinkData },
|
permalinkParserResult = { permalinkData },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
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
|
||||||
|
|
@ -213,7 +213,7 @@ class IntentResolverTest {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
||||||
loginIntentResolverResult = { null },
|
loginIntentResolverResult = { null },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
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
|
||||||
|
|
@ -230,7 +230,7 @@ class IntentResolverTest {
|
||||||
)
|
)
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
permalinkParserResult = { permalinkData },
|
permalinkParserResult = { permalinkData },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_BATTERY_LOW
|
action = Intent.ACTION_BATTERY_LOW
|
||||||
|
|
@ -244,7 +244,7 @@ class IntentResolverTest {
|
||||||
fun `test incoming share simple`() {
|
fun `test incoming share simple`() {
|
||||||
val shareIntentData = ShareIntentData.PlainText("Hello")
|
val shareIntentData = ShareIntentData.PlainText("Hello")
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
onIncomingShareIntent = { shareIntentData },
|
onIncomingShareIntent = { shareIntentData },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
|
|
@ -260,7 +260,7 @@ class IntentResolverTest {
|
||||||
val fileUri = "content://com.example.app/file1.jpg".toUri()
|
val fileUri = "content://com.example.app/file1.jpg".toUri()
|
||||||
val shareIntentData = ShareIntentData.Uris(text = "Hello", uris = listOf(UriToShare(fileUri, "image/jpg")))
|
val shareIntentData = ShareIntentData.Uris(text = "Hello", uris = listOf(UriToShare(fileUri, "image/jpg")))
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
onIncomingShareIntent = { shareIntentData },
|
onIncomingShareIntent = { shareIntentData },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
|
|
@ -277,7 +277,7 @@ class IntentResolverTest {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
||||||
loginIntentResolverResult = { null },
|
loginIntentResolverResult = { null },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
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
|
||||||
|
|
@ -292,7 +292,7 @@ class IntentResolverTest {
|
||||||
val aLoginParams = LoginParams("accountProvider", null)
|
val aLoginParams = LoginParams("accountProvider", null)
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
loginIntentResolverResult = { aLoginParams },
|
loginIntentResolverResult = { aLoginParams },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
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
|
||||||
|
|
@ -306,7 +306,7 @@ class IntentResolverTest {
|
||||||
deeplinkParserResult: DeeplinkData? = null,
|
deeplinkParserResult: DeeplinkData? = null,
|
||||||
permalinkParserResult: (String) -> PermalinkData = { lambdaError() },
|
permalinkParserResult: (String) -> PermalinkData = { lambdaError() },
|
||||||
loginIntentResolverResult: (String) -> LoginParams? = { lambdaError() },
|
loginIntentResolverResult: (String) -> LoginParams? = { lambdaError() },
|
||||||
oidcIntentResolverResult: (Intent) -> OidcAction? = { lambdaError() },
|
oAuthIntentResolverResult: (Intent) -> OAuthAction? = { lambdaError() },
|
||||||
onIncomingShareIntent: (Intent) -> ShareIntentData? = { null },
|
onIncomingShareIntent: (Intent) -> ShareIntentData? = { null },
|
||||||
): IntentResolver {
|
): IntentResolver {
|
||||||
return IntentResolver(
|
return IntentResolver(
|
||||||
|
|
@ -314,8 +314,8 @@ class IntentResolverTest {
|
||||||
loginIntentResolver = FakeLoginIntentResolver(
|
loginIntentResolver = FakeLoginIntentResolver(
|
||||||
parseResult = loginIntentResolverResult,
|
parseResult = loginIntentResolverResult,
|
||||||
),
|
),
|
||||||
oidcIntentResolver = FakeOidcIntentResolver(
|
oAuthIntentResolver = FakeOAuthIntentResolver(
|
||||||
resolveResult = oidcIntentResolverResult,
|
resolveResult = oAuthIntentResolverResult,
|
||||||
),
|
),
|
||||||
permalinkParser = FakePermalinkParser(
|
permalinkParser = FakePermalinkParser(
|
||||||
result = permalinkParserResult
|
result = permalinkParserResult
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
This file contains some rough notes about Oidc implementation, with some examples of actual data.
|
This file contains some rough notes about OAuth implementation, with some examples of actual data.
|
||||||
|
|
||||||
[ios implementation](https://github.com/element-hq/element-x-ios/compare/develop...doug/oidc-temp)
|
[ios implementation](https://github.com/element-hq/element-x-ios/compare/develop...doug/oidc-temp)
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ tosUri = "https://element.io/user-terms-of-service",
|
||||||
policyUri = "https://element.io/privacy"
|
policyUri = "https://element.io/privacy"
|
||||||
|
|
||||||
|
|
||||||
Example of OidcData (from presentUrl callback):
|
Example of OAuthData (from presentUrl callback):
|
||||||
url: https://auth-oidc.lab.element.dev/authorize?response_type=code&client_id=01GYCAGG3PA70CJ97ZVP0WFJY3&redirect_uri=io.element%3A%2Fcallback&scope=openid+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AYAgcPW4mcG&state=ex6mNJVFZ5jn9wL8&nonce=NZ93DOyIGQd9exPQ&code_challenge_method=S256&code_challenge=FFRcPALNSPCh-ZgpyTRFu_h8NZJVncfvihbfT9CyX8U&prompt=consent
|
url: https://auth-oidc.lab.element.dev/authorize?response_type=code&client_id=01GYCAGG3PA70CJ97ZVP0WFJY3&redirect_uri=io.element%3A%2Fcallback&scope=openid+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AYAgcPW4mcG&state=ex6mNJVFZ5jn9wL8&nonce=NZ93DOyIGQd9exPQ&code_challenge_method=S256&code_challenge=FFRcPALNSPCh-ZgpyTRFu_h8NZJVncfvihbfT9CyX8U&prompt=consent
|
||||||
|
|
||||||
Formatted url:
|
Formatted url:
|
||||||
|
|
@ -43,8 +43,8 @@ https://auth-oidc.lab.element.dev/authorize?
|
||||||
state: ex6mNJVFZ5jn9wL8
|
state: ex6mNJVFZ5jn9wL8
|
||||||
|
|
||||||
|
|
||||||
Oidc client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs
|
OAuth client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs
|
||||||
Oidc sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs
|
OAuth sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs
|
||||||
|
|
||||||
|
|
||||||
Test server:
|
Test server:
|
||||||
|
|
@ -43,7 +43,7 @@ dependencies {
|
||||||
implementation(projects.libraries.permissions.api)
|
implementation(projects.libraries.permissions.api)
|
||||||
implementation(projects.libraries.sessionStorage.api)
|
implementation(projects.libraries.sessionStorage.api)
|
||||||
implementation(projects.libraries.qrcode)
|
implementation(projects.libraries.qrcode)
|
||||||
implementation(projects.libraries.oidc.api)
|
implementation(projects.libraries.oauth.api)
|
||||||
implementation(projects.libraries.uiUtils)
|
implementation(projects.libraries.uiUtils)
|
||||||
implementation(projects.libraries.wellknown.api)
|
implementation(projects.libraries.wellknown.api)
|
||||||
implementation(libs.androidx.browser)
|
implementation(libs.androidx.browser)
|
||||||
|
|
@ -56,7 +56,7 @@ dependencies {
|
||||||
testImplementation(projects.features.enterprise.test)
|
testImplementation(projects.features.enterprise.test)
|
||||||
testImplementation(projects.libraries.featureflag.test)
|
testImplementation(projects.libraries.featureflag.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.oidc.test)
|
testImplementation(projects.libraries.oauth.test)
|
||||||
testImplementation(projects.libraries.permissions.test)
|
testImplementation(projects.libraries.permissions.test)
|
||||||
testImplementation(projects.libraries.sessionStorage.test)
|
testImplementation(projects.libraries.sessionStorage.test)
|
||||||
testImplementation(projects.libraries.wellknown.test)
|
testImplementation(projects.libraries.wellknown.test)
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ dependencies {
|
||||||
implementation(projects.libraries.permissions.api)
|
implementation(projects.libraries.permissions.api)
|
||||||
implementation(projects.libraries.sessionStorage.api)
|
implementation(projects.libraries.sessionStorage.api)
|
||||||
implementation(projects.libraries.qrcode)
|
implementation(projects.libraries.qrcode)
|
||||||
implementation(projects.libraries.oidc.api)
|
implementation(projects.libraries.oauth.api)
|
||||||
implementation(projects.libraries.uiUtils)
|
implementation(projects.libraries.uiUtils)
|
||||||
implementation(projects.libraries.wellknown.api)
|
implementation(projects.libraries.wellknown.api)
|
||||||
implementation(libs.androidx.browser)
|
implementation(libs.androidx.browser)
|
||||||
|
|
@ -83,7 +83,7 @@ dependencies {
|
||||||
testImplementation(projects.features.preferences.test)
|
testImplementation(projects.features.preferences.test)
|
||||||
testImplementation(projects.libraries.featureflag.test)
|
testImplementation(projects.libraries.featureflag.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.oidc.test)
|
testImplementation(projects.libraries.oauth.test)
|
||||||
testImplementation(projects.libraries.permissions.test)
|
testImplementation(projects.libraries.permissions.test)
|
||||||
testImplementation(projects.libraries.sessionStorage.test)
|
testImplementation(projects.libraries.sessionStorage.test)
|
||||||
testImplementation(projects.libraries.wellknown.test)
|
testImplementation(projects.libraries.wellknown.test)
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -64,7 +64,7 @@ class LoginFlowNode(
|
||||||
@Assisted buildContext: BuildContext,
|
@Assisted buildContext: BuildContext,
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
private val accountProviderDataSource: AccountProviderDataSource,
|
private val accountProviderDataSource: AccountProviderDataSource,
|
||||||
private val oidcActionFlow: OidcActionFlow,
|
private val oAuthActionFlow: OAuthActionFlow,
|
||||||
@AppCoroutineScope
|
@AppCoroutineScope
|
||||||
private val appCoroutineScope: CoroutineScope,
|
private val appCoroutineScope: CoroutineScope,
|
||||||
private val elementClassicConnection: ElementClassicConnection,
|
private val elementClassicConnection: ElementClassicConnection,
|
||||||
|
|
@ -100,7 +100,7 @@ class LoginFlowNode(
|
||||||
// by pressing back or by closing the Custom Chrome Tab.
|
// by pressing back or by closing the Custom Chrome Tab.
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
delay(5000)
|
delay(5000)
|
||||||
oidcActionFlow.post(OidcAction.GoBack(toUnblock = true))
|
oAuthActionFlow.post(OAuthAction.GoBack(toUnblock = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,8 +161,8 @@ class LoginFlowNode(
|
||||||
backstack.push(NavTarget.LoginPassword())
|
backstack.push(NavTarget.LoginPassword())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToOidc(oidcDetails: OidcDetails) {
|
override fun navigateToOAuth(oAuthDetails: OAuthDetails) {
|
||||||
navigateToMas(oidcDetails)
|
navigateToMas(oAuthDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToCreateAccount(url: String) {
|
override fun navigateToCreateAccount(url: String) {
|
||||||
|
|
@ -197,8 +197,8 @@ class LoginFlowNode(
|
||||||
callback.navigateToBugReport()
|
callback.navigateToBugReport()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToOidc(oidcDetails: OidcDetails) {
|
override fun navigateToOAuth(oAuthDetails: OAuthDetails) {
|
||||||
navigateToMas(oidcDetails)
|
navigateToMas(oAuthDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToCreateAccount(url: String) {
|
override fun navigateToCreateAccount(url: String) {
|
||||||
|
|
@ -243,8 +243,8 @@ class LoginFlowNode(
|
||||||
}
|
}
|
||||||
NavTarget.ChooseAccountProvider -> {
|
NavTarget.ChooseAccountProvider -> {
|
||||||
val callback = object : ChooseAccountProviderNode.Callback {
|
val callback = object : ChooseAccountProviderNode.Callback {
|
||||||
override fun navigateToOidc(oidcDetails: OidcDetails) {
|
override fun navigateToOAuth(oAuthDetails: OAuthDetails) {
|
||||||
navigateToMas(oidcDetails)
|
navigateToMas(oAuthDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToCreateAccount(url: String) {
|
override fun navigateToCreateAccount(url: String) {
|
||||||
|
|
@ -270,8 +270,8 @@ class LoginFlowNode(
|
||||||
isAccountCreation = navTarget.isAccountCreation,
|
isAccountCreation = navTarget.isAccountCreation,
|
||||||
)
|
)
|
||||||
val callback = object : ConfirmAccountProviderNode.Callback {
|
val callback = object : ConfirmAccountProviderNode.Callback {
|
||||||
override fun navigateToOidc(oidcDetails: OidcDetails) {
|
override fun navigateToOAuth(oAuthDetails: OAuthDetails) {
|
||||||
navigateToMas(oidcDetails)
|
navigateToMas(oAuthDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToCreateAccount(url: String) {
|
override fun navigateToCreateAccount(url: String) {
|
||||||
|
|
@ -333,10 +333,10 @@ class LoginFlowNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToMas(oidcDetails: OidcDetails) {
|
private fun navigateToMas(oAuthDetails: OAuthDetails) {
|
||||||
activity?.let {
|
activity?.let {
|
||||||
externalAppStarted = true
|
externalAppStarted = true
|
||||||
it.openUrlInChromeCustomTab(null, darkTheme, oidcDetails.url)
|
it.openUrlInChromeCustomTab(null, darkTheme, oAuthDetails.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ sealed class ChangeServerError : Exception() {
|
||||||
// AccountAlreadyLoggedIn error should not happen at this point
|
// AccountAlreadyLoggedIn error should not happen at this point
|
||||||
is AuthenticationException.AccountAlreadyLoggedIn -> Error(messageStr = error.message)
|
is AuthenticationException.AccountAlreadyLoggedIn -> Error(messageStr = error.message)
|
||||||
is AuthenticationException.Generic -> Error(messageStr = error.message)
|
is AuthenticationException.Generic -> Error(messageStr = error.message)
|
||||||
is AuthenticationException.Oidc -> Error(messageStr = error.message)
|
is AuthenticationException.OAuth -> Error(messageStr = error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is AccountProviderAccessException.NeedElementProException -> NeedElementPro(
|
is AccountProviderAccessException.NeedElementProException -> NeedElementPro(
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ import io.element.android.features.login.impl.web.WebClientUrlForAuthenticationR
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcPrompt
|
import io.element.android.libraries.matrix.api.auth.OAuthPrompt
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for managing the login flow, including handling OIDC actions and
|
* This class is responsible for managing the login flow, including handling OIDC actions and
|
||||||
|
|
@ -35,7 +35,7 @@ import io.element.android.libraries.oidc.api.OidcActionFlow
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
class LoginHelper(
|
class LoginHelper(
|
||||||
private val oidcActionFlow: OidcActionFlow,
|
private val oAuthActionFlow: OAuthActionFlow,
|
||||||
private val authenticationService: MatrixAuthenticationService,
|
private val authenticationService: MatrixAuthenticationService,
|
||||||
private val webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever,
|
private val webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever,
|
||||||
) {
|
) {
|
||||||
|
|
@ -44,9 +44,9 @@ class LoginHelper(
|
||||||
@Composable
|
@Composable
|
||||||
fun collectLoginMode(): State<AsyncData<LoginMode>> {
|
fun collectLoginMode(): State<AsyncData<LoginMode>> {
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
oidcActionFlow.collect { oidcAction ->
|
oAuthActionFlow.collect { oAuthAction ->
|
||||||
if (oidcAction != null) {
|
if (oAuthAction != null) {
|
||||||
onOidcAction(oidcAction)
|
onOAuthAction(oAuthAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,11 +73,11 @@ class LoginHelper(
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
}.map { matrixHomeServerDetails ->
|
}.map { matrixHomeServerDetails ->
|
||||||
if (matrixHomeServerDetails.supportsOidcLogin) {
|
if (matrixHomeServerDetails.supportsOAuthLogin) {
|
||||||
// Retrieve the details right now
|
// Retrieve the details right now
|
||||||
val oidcPrompt = if (isAccountCreation) OidcPrompt.Create else OidcPrompt.Login
|
val oAuthPrompt = if (isAccountCreation) OAuthPrompt.Create else OAuthPrompt.Login
|
||||||
LoginMode.Oidc(
|
LoginMode.OAuth(
|
||||||
authenticationService.getOidcUrl(prompt = oidcPrompt, loginHint = loginHint).getOrThrow()
|
authenticationService.getOAuthUrl(prompt = oAuthPrompt, loginHint = loginHint).getOrThrow()
|
||||||
)
|
)
|
||||||
} else if (isAccountCreation) {
|
} else if (isAccountCreation) {
|
||||||
val url = webClientUrlForAuthenticationRetriever.retrieve(homeserverUrl)
|
val url = webClientUrlForAuthenticationRetriever.retrieve(homeserverUrl)
|
||||||
|
|
@ -99,16 +99,16 @@ class LoginHelper(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onOidcAction(oidcAction: OidcAction) {
|
private suspend fun onOAuthAction(oAuthAction: OAuthAction) {
|
||||||
if (oidcAction is OidcAction.GoBack && oidcAction.toUnblock && loginModeState.value !is AsyncData.Loading) {
|
if (oAuthAction is OAuthAction.GoBack && oAuthAction.toUnblock && loginModeState.value !is AsyncData.Loading) {
|
||||||
// Ignore GoBack action if the current state is not Loading. This GoBack action is coming from LoginFlowNode.
|
// Ignore GoBack action if the current state is not Loading. This GoBack action is coming from LoginFlowNode.
|
||||||
// This can happen if there is an error, for instance attempt to login again on the same account.
|
// This can happen if there is an error, for instance attempt to login again on the same account.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
loginModeState.value = AsyncData.Loading()
|
loginModeState.value = AsyncData.Loading()
|
||||||
when (oidcAction) {
|
when (oAuthAction) {
|
||||||
is OidcAction.GoBack -> {
|
is OAuthAction.GoBack -> {
|
||||||
authenticationService.cancelOidcLogin()
|
authenticationService.cancelOAuthLogin()
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
loginModeState.value = AsyncData.Uninitialized
|
loginModeState.value = AsyncData.Uninitialized
|
||||||
}
|
}
|
||||||
|
|
@ -116,13 +116,13 @@ class LoginHelper(
|
||||||
loginModeState.value = AsyncData.Failure(failure)
|
loginModeState.value = AsyncData.Failure(failure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OidcAction.Success -> {
|
is OAuthAction.Success -> {
|
||||||
authenticationService.loginWithOidc(oidcAction.url)
|
authenticationService.loginWithOAuth(oAuthAction.url)
|
||||||
.onFailure { failure ->
|
.onFailure { failure ->
|
||||||
loginModeState.value = AsyncData.Failure(failure)
|
loginModeState.value = AsyncData.Failure(failure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oidcActionFlow.reset()
|
oAuthActionFlow.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@
|
||||||
|
|
||||||
package io.element.android.features.login.impl.login
|
package io.element.android.features.login.impl.login
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
|
|
||||||
sealed interface LoginMode {
|
sealed interface LoginMode {
|
||||||
data object PasswordLogin : LoginMode
|
data object PasswordLogin : LoginMode
|
||||||
data class Oidc(val oidcDetails: OidcDetails) : LoginMode
|
data class OAuth(val oAuthDetails: OAuthDetails) : LoginMode
|
||||||
data class AccountCreation(val url: String) : LoginMode
|
data class AccountCreation(val url: String) : LoginMode
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
|
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
|
||||||
import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -32,7 +32,7 @@ fun LoginModeView(
|
||||||
loginMode: AsyncData<LoginMode>,
|
loginMode: AsyncData<LoginMode>,
|
||||||
onClearError: () -> Unit,
|
onClearError: () -> Unit,
|
||||||
onLearnMoreClick: () -> Unit,
|
onLearnMoreClick: () -> Unit,
|
||||||
onOidcDetails: (OidcDetails) -> Unit,
|
onOAuthDetails: (OAuthDetails) -> Unit,
|
||||||
onNeedLoginPassword: () -> Unit,
|
onNeedLoginPassword: () -> Unit,
|
||||||
onCreateAccountContinue: (url: String) -> Unit
|
onCreateAccountContinue: (url: String) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
@ -118,7 +118,7 @@ fun LoginModeView(
|
||||||
is AsyncData.Loading -> Unit // The Continue button shows the loading state
|
is AsyncData.Loading -> Unit // The Continue button shows the loading state
|
||||||
is AsyncData.Success -> {
|
is AsyncData.Success -> {
|
||||||
when (val loginModeData = loginMode.data) {
|
when (val loginModeData = loginMode.data) {
|
||||||
is LoginMode.Oidc -> onOidcDetails(loginModeData.oidcDetails)
|
is LoginMode.OAuth -> onOAuthDetails(loginModeData.oAuthDetails)
|
||||||
LoginMode.PasswordLogin -> onNeedLoginPassword()
|
LoginMode.PasswordLogin -> onNeedLoginPassword()
|
||||||
is LoginMode.AccountCreation -> onCreateAccountContinue(loginModeData.url)
|
is LoginMode.AccountCreation -> onCreateAccountContinue(loginModeData.url)
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +137,7 @@ internal fun LoginModeViewPreview(@PreviewParameter(LoginModeViewErrorProvider::
|
||||||
loginMode = AsyncData.Failure(error),
|
loginMode = AsyncData.Failure(error),
|
||||||
onClearError = {},
|
onClearError = {},
|
||||||
onLearnMoreClick = {},
|
onLearnMoreClick = {},
|
||||||
onOidcDetails = {},
|
onOAuthDetails = {},
|
||||||
onNeedLoginPassword = {},
|
onNeedLoginPassword = {},
|
||||||
onCreateAccountContinue = {}
|
onCreateAccountContinue = {}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,8 @@ class QrCodeLoginFlowNode(
|
||||||
is QrLoginException.SlidingSyncNotAvailable -> {
|
is QrLoginException.SlidingSyncNotAvailable -> {
|
||||||
backstack.replace(NavTarget.Error(QrCodeErrorScreenType.SlidingSyncNotAvailable))
|
backstack.replace(NavTarget.Error(QrCodeErrorScreenType.SlidingSyncNotAvailable))
|
||||||
}
|
}
|
||||||
is QrLoginException.OidcMetadataInvalid -> {
|
is QrLoginException.OAuthMetadataInvalid -> {
|
||||||
Timber.e(error, "OIDC metadata is invalid")
|
Timber.e(error, "OAuth metadata is invalid")
|
||||||
backstack.replace(NavTarget.Error(QrCodeErrorScreenType.UnknownError))
|
backstack.replace(NavTarget.Error(QrCodeErrorScreenType.UnknownError))
|
||||||
}
|
}
|
||||||
QrLoginException.CheckCodeAlreadySent,
|
QrLoginException.CheckCodeAlreadySent,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import dev.zacsweers.metro.AssistedInject
|
||||||
import io.element.android.annotations.ContributesNode
|
import io.element.android.annotations.ContributesNode
|
||||||
import io.element.android.features.login.impl.util.openLearnMorePage
|
import io.element.android.features.login.impl.util.openLearnMorePage
|
||||||
import io.element.android.libraries.architecture.callback
|
import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
|
|
@ -31,7 +31,7 @@ class ChooseAccountProviderNode(
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToLoginPassword()
|
fun navigateToLoginPassword()
|
||||||
fun navigateToOidc(oidcDetails: OidcDetails)
|
fun navigateToOAuth(oAuthDetails: OAuthDetails)
|
||||||
fun navigateToCreateAccount(url: String)
|
fun navigateToCreateAccount(url: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ class ChooseAccountProviderNode(
|
||||||
state = state,
|
state = state,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackClick = ::navigateUp,
|
onBackClick = ::navigateUp,
|
||||||
onOidcDetails = callback::navigateToOidc,
|
onOAuthDetails = callback::navigateToOAuth,
|
||||||
onNeedLoginPassword = callback::navigateToLoginPassword,
|
onNeedLoginPassword = callback::navigateToLoginPassword,
|
||||||
onLearnMoreClick = { openLearnMorePage(context) },
|
onLearnMoreClick = { openLearnMorePage(context) },
|
||||||
onCreateAccountContinue = callback::navigateToCreateAccount,
|
onCreateAccountContinue = callback::navigateToCreateAccount,
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,14 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Button
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChooseAccountProviderView(
|
fun ChooseAccountProviderView(
|
||||||
state: ChooseAccountProviderState,
|
state: ChooseAccountProviderState,
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
onOidcDetails: (OidcDetails) -> Unit,
|
onOAuthDetails: (OAuthDetails) -> Unit,
|
||||||
onNeedLoginPassword: () -> Unit,
|
onNeedLoginPassword: () -> Unit,
|
||||||
onLearnMoreClick: () -> Unit,
|
onLearnMoreClick: () -> Unit,
|
||||||
onCreateAccountContinue: (url: String) -> Unit,
|
onCreateAccountContinue: (url: String) -> Unit,
|
||||||
|
|
@ -129,7 +129,7 @@ fun ChooseAccountProviderView(
|
||||||
state.eventSink(ChooseAccountProviderEvents.ClearError)
|
state.eventSink(ChooseAccountProviderEvents.ClearError)
|
||||||
},
|
},
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onOidcDetails = onOidcDetails,
|
onOAuthDetails = onOAuthDetails,
|
||||||
onNeedLoginPassword = onNeedLoginPassword,
|
onNeedLoginPassword = onNeedLoginPassword,
|
||||||
onCreateAccountContinue = onCreateAccountContinue,
|
onCreateAccountContinue = onCreateAccountContinue,
|
||||||
)
|
)
|
||||||
|
|
@ -144,7 +144,7 @@ internal fun ChooseAccountProviderViewPreview(@PreviewParameter(ChooseAccountPro
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = { },
|
onBackClick = { },
|
||||||
onLearnMoreClick = { },
|
onLearnMoreClick = { },
|
||||||
onOidcDetails = { },
|
onOAuthDetails = { },
|
||||||
onNeedLoginPassword = { },
|
onNeedLoginPassword = { },
|
||||||
onCreateAccountContinue = { },
|
onCreateAccountContinue = { },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import io.element.android.libraries.architecture.BaseFlowNode
|
||||||
import io.element.android.libraries.architecture.appyx.rememberFaderOrSliderTransitionHandler
|
import io.element.android.libraries.architecture.appyx.rememberFaderOrSliderTransitionHandler
|
||||||
import io.element.android.libraries.architecture.callback
|
import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -54,7 +54,7 @@ class ClassicFlowNode(
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToOnBoarding(allowBackNavigation: Boolean)
|
fun navigateToOnBoarding(allowBackNavigation: Boolean)
|
||||||
fun navigateToLoginPassword()
|
fun navigateToLoginPassword()
|
||||||
fun navigateToOidc(oidcDetails: OidcDetails)
|
fun navigateToOAuth(oAuthDetails: OAuthDetails)
|
||||||
fun navigateToCreateAccount(url: String)
|
fun navigateToCreateAccount(url: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,8 +111,8 @@ class ClassicFlowNode(
|
||||||
callback.navigateToLoginPassword()
|
callback.navigateToLoginPassword()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToOidc(oidcDetails: OidcDetails) {
|
override fun navigateToOAuth(oAuthDetails: OAuthDetails) {
|
||||||
callback.navigateToOidc(oidcDetails)
|
callback.navigateToOAuth(oAuthDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToCreateAccount(url: String) {
|
override fun navigateToCreateAccount(url: String) {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import io.element.android.features.login.impl.util.openLearnMorePage
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.callback
|
import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
|
|
@ -35,7 +35,7 @@ class LoginWithClassicNode(
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToOtherOptions()
|
fun navigateToOtherOptions()
|
||||||
fun navigateToLoginPassword()
|
fun navigateToLoginPassword()
|
||||||
fun navigateToOidc(oidcDetails: OidcDetails)
|
fun navigateToOAuth(oAuthDetails: OAuthDetails)
|
||||||
fun navigateToCreateAccount(url: String)
|
fun navigateToCreateAccount(url: String)
|
||||||
fun navigateToMissingKeyBackup()
|
fun navigateToMissingKeyBackup()
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +60,7 @@ class LoginWithClassicNode(
|
||||||
state = state,
|
state = state,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onOtherOptionsClick = callback::navigateToOtherOptions,
|
onOtherOptionsClick = callback::navigateToOtherOptions,
|
||||||
onOidcDetails = callback::navigateToOidc,
|
onOAuthDetails = callback::navigateToOAuth,
|
||||||
onNeedLoginPassword = callback::navigateToLoginPassword,
|
onNeedLoginPassword = callback::navigateToLoginPassword,
|
||||||
onLearnMoreClick = { openLearnMorePage(context) },
|
onLearnMoreClick = { openLearnMorePage(context) },
|
||||||
onCreateAccountContinue = callback::navigateToCreateAccount,
|
onCreateAccountContinue = callback::navigateToCreateAccount,
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Button
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -59,7 +59,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
fun LoginWithClassicView(
|
fun LoginWithClassicView(
|
||||||
state: LoginWithClassicState,
|
state: LoginWithClassicState,
|
||||||
onOtherOptionsClick: () -> Unit,
|
onOtherOptionsClick: () -> Unit,
|
||||||
onOidcDetails: (OidcDetails) -> Unit,
|
onOAuthDetails: (OAuthDetails) -> Unit,
|
||||||
onNeedLoginPassword: () -> Unit,
|
onNeedLoginPassword: () -> Unit,
|
||||||
onLearnMoreClick: () -> Unit,
|
onLearnMoreClick: () -> Unit,
|
||||||
onCreateAccountContinue: (url: String) -> Unit,
|
onCreateAccountContinue: (url: String) -> Unit,
|
||||||
|
|
@ -200,7 +200,7 @@ fun LoginWithClassicView(
|
||||||
state.eventSink(LoginWithClassicEvent.ClearError)
|
state.eventSink(LoginWithClassicEvent.ClearError)
|
||||||
},
|
},
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onOidcDetails = onOidcDetails,
|
onOAuthDetails = onOAuthDetails,
|
||||||
onNeedLoginPassword = onNeedLoginPassword,
|
onNeedLoginPassword = onNeedLoginPassword,
|
||||||
onCreateAccountContinue = onCreateAccountContinue,
|
onCreateAccountContinue = onCreateAccountContinue,
|
||||||
)
|
)
|
||||||
|
|
@ -212,7 +212,7 @@ internal fun LoginWithClassicViewPreview(@PreviewParameter(LoginWithClassicState
|
||||||
LoginWithClassicView(
|
LoginWithClassicView(
|
||||||
state = state,
|
state = state,
|
||||||
onOtherOptionsClick = {},
|
onOtherOptionsClick = {},
|
||||||
onOidcDetails = {},
|
onOAuthDetails = {},
|
||||||
onNeedLoginPassword = {},
|
onNeedLoginPassword = {},
|
||||||
onLearnMoreClick = {},
|
onLearnMoreClick = {},
|
||||||
onCreateAccountContinue = {},
|
onCreateAccountContinue = {},
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import io.element.android.features.login.impl.util.openLearnMorePage
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.callback
|
import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
|
|
@ -44,7 +44,7 @@ class ConfirmAccountProviderNode(
|
||||||
|
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToLoginPassword()
|
fun navigateToLoginPassword()
|
||||||
fun navigateToOidc(oidcDetails: OidcDetails)
|
fun navigateToOAuth(oAuthDetails: OAuthDetails)
|
||||||
fun navigateToCreateAccount(url: String)
|
fun navigateToCreateAccount(url: String)
|
||||||
fun navigateToChangeAccountProvider()
|
fun navigateToChangeAccountProvider()
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ class ConfirmAccountProviderNode(
|
||||||
ConfirmAccountProviderView(
|
ConfirmAccountProviderView(
|
||||||
state = state,
|
state = state,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onOidcDetails = callback::navigateToOidc,
|
onOAuthDetails = callback::navigateToOAuth,
|
||||||
onNeedLoginPassword = callback::navigateToLoginPassword,
|
onNeedLoginPassword = callback::navigateToLoginPassword,
|
||||||
onCreateAccountContinue = callback::navigateToCreateAccount,
|
onCreateAccountContinue = callback::navigateToCreateAccount,
|
||||||
onChange = callback::navigateToChangeAccountProvider,
|
onChange = callback::navigateToChangeAccountProvider,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Button
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -38,7 +38,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
@Composable
|
@Composable
|
||||||
fun ConfirmAccountProviderView(
|
fun ConfirmAccountProviderView(
|
||||||
state: ConfirmAccountProviderState,
|
state: ConfirmAccountProviderState,
|
||||||
onOidcDetails: (OidcDetails) -> Unit,
|
onOAuthDetails: (OAuthDetails) -> Unit,
|
||||||
onNeedLoginPassword: () -> Unit,
|
onNeedLoginPassword: () -> Unit,
|
||||||
onLearnMoreClick: () -> Unit,
|
onLearnMoreClick: () -> Unit,
|
||||||
onCreateAccountContinue: (url: String) -> Unit,
|
onCreateAccountContinue: (url: String) -> Unit,
|
||||||
|
|
@ -103,7 +103,7 @@ fun ConfirmAccountProviderView(
|
||||||
eventSink(ConfirmAccountProviderEvents.ClearError)
|
eventSink(ConfirmAccountProviderEvents.ClearError)
|
||||||
},
|
},
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onOidcDetails = onOidcDetails,
|
onOAuthDetails = onOAuthDetails,
|
||||||
onNeedLoginPassword = onNeedLoginPassword,
|
onNeedLoginPassword = onNeedLoginPassword,
|
||||||
onCreateAccountContinue = onCreateAccountContinue,
|
onCreateAccountContinue = onCreateAccountContinue,
|
||||||
)
|
)
|
||||||
|
|
@ -117,7 +117,7 @@ internal fun ConfirmAccountProviderViewPreview(
|
||||||
) = ElementPreview {
|
) = ElementPreview {
|
||||||
ConfirmAccountProviderView(
|
ConfirmAccountProviderView(
|
||||||
state = state,
|
state = state,
|
||||||
onOidcDetails = {},
|
onOAuthDetails = {},
|
||||||
onNeedLoginPassword = {},
|
onNeedLoginPassword = {},
|
||||||
onCreateAccountContinue = {},
|
onCreateAccountContinue = {},
|
||||||
onLearnMoreClick = {},
|
onLearnMoreClick = {},
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import io.element.android.features.login.impl.util.openLearnMorePage
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.callback
|
import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
|
|
@ -40,7 +40,7 @@ class OnBoardingNode(
|
||||||
fun navigateToQrCode()
|
fun navigateToQrCode()
|
||||||
fun navigateToBugReport()
|
fun navigateToBugReport()
|
||||||
fun navigateToLoginPassword()
|
fun navigateToLoginPassword()
|
||||||
fun navigateToOidc(oidcDetails: OidcDetails)
|
fun navigateToOAuth(oAuthDetails: OAuthDetails)
|
||||||
fun navigateToCreateAccount(url: String)
|
fun navigateToCreateAccount(url: String)
|
||||||
fun navigateToDeveloperSettings()
|
fun navigateToDeveloperSettings()
|
||||||
fun onDone()
|
fun onDone()
|
||||||
|
|
@ -71,7 +71,7 @@ class OnBoardingNode(
|
||||||
onCreateAccount = callback::navigateToSignUpFlow,
|
onCreateAccount = callback::navigateToSignUpFlow,
|
||||||
onSignInWithQrCode = callback::navigateToQrCode,
|
onSignInWithQrCode = callback::navigateToQrCode,
|
||||||
onReportProblem = callback::navigateToBugReport,
|
onReportProblem = callback::navigateToBugReport,
|
||||||
onOidcDetails = callback::navigateToOidc,
|
onOAuthDetails = callback::navigateToOAuth,
|
||||||
onNeedLoginPassword = callback::navigateToLoginPassword,
|
onNeedLoginPassword = callback::navigateToLoginPassword,
|
||||||
onLearnMoreClick = { openLearnMorePage(context) },
|
onLearnMoreClick = { openLearnMorePage(context) },
|
||||||
onCreateAccountContinue = callback::navigateToCreateAccount,
|
onCreateAccountContinue = callback::navigateToCreateAccount,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.IconSource
|
import io.element.android.libraries.designsystem.theme.components.IconSource
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -68,7 +68,7 @@ fun OnBoardingView(
|
||||||
onSignInWithQrCode: () -> Unit,
|
onSignInWithQrCode: () -> Unit,
|
||||||
onSignIn: (mustChooseAccountProvider: Boolean) -> Unit,
|
onSignIn: (mustChooseAccountProvider: Boolean) -> Unit,
|
||||||
onCreateAccount: () -> Unit,
|
onCreateAccount: () -> Unit,
|
||||||
onOidcDetails: (OidcDetails) -> Unit,
|
onOAuthDetails: (OAuthDetails) -> Unit,
|
||||||
onNeedLoginPassword: () -> Unit,
|
onNeedLoginPassword: () -> Unit,
|
||||||
onLearnMoreClick: () -> Unit,
|
onLearnMoreClick: () -> Unit,
|
||||||
onCreateAccountContinue: (url: String) -> Unit,
|
onCreateAccountContinue: (url: String) -> Unit,
|
||||||
|
|
@ -82,7 +82,7 @@ fun OnBoardingView(
|
||||||
state.eventSink(OnBoardingEvents.ClearError)
|
state.eventSink(OnBoardingEvents.ClearError)
|
||||||
},
|
},
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onOidcDetails = onOidcDetails,
|
onOAuthDetails = onOAuthDetails,
|
||||||
onNeedLoginPassword = onNeedLoginPassword,
|
onNeedLoginPassword = onNeedLoginPassword,
|
||||||
onCreateAccountContinue = onCreateAccountContinue,
|
onCreateAccountContinue = onCreateAccountContinue,
|
||||||
)
|
)
|
||||||
|
|
@ -354,7 +354,7 @@ internal fun OnBoardingViewPreview(
|
||||||
onSignIn = {},
|
onSignIn = {},
|
||||||
onCreateAccount = {},
|
onCreateAccount = {},
|
||||||
onReportProblem = {},
|
onReportProblem = {},
|
||||||
onOidcDetails = {},
|
onOAuthDetails = {},
|
||||||
onNeedLoginPassword = {},
|
onNeedLoginPassword = {},
|
||||||
onLearnMoreClick = {},
|
onLearnMoreClick = {},
|
||||||
onCreateAccountContinue = {},
|
onCreateAccountContinue = {},
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import io.element.android.features.login.api.LoginEntryPoint
|
||||||
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
|
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
|
||||||
import io.element.android.features.login.impl.classic.FakeElementClassicConnection
|
import io.element.android.features.login.impl.classic.FakeElementClassicConnection
|
||||||
import io.element.android.features.preferences.test.FakePreferencesEntryPoint
|
import io.element.android.features.preferences.test.FakePreferencesEntryPoint
|
||||||
import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow
|
import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
import io.element.android.tests.testutils.node.TestParentNode
|
import io.element.android.tests.testutils.node.TestParentNode
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -39,7 +39,7 @@ class DefaultLoginEntryPointTest {
|
||||||
buildContext = buildContext,
|
buildContext = buildContext,
|
||||||
plugins = plugins,
|
plugins = plugins,
|
||||||
accountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
accountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
||||||
oidcActionFlow = FakeOidcActionFlow(),
|
oAuthActionFlow = FakeOAuthActionFlow(),
|
||||||
appCoroutineScope = backgroundScope,
|
appCoroutineScope = backgroundScope,
|
||||||
elementClassicConnection = FakeElementClassicConnection(),
|
elementClassicConnection = FakeElementClassicConnection(),
|
||||||
preferencesEntryPoint = FakePreferencesEntryPoint(),
|
preferencesEntryPoint = FakePreferencesEntryPoint(),
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class ChangeServerPresenterTest {
|
||||||
fun `present - change server ok`() = runTest {
|
fun `present - change server ok`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
createPresenter(
|
createPresenter(
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class QrCodeLoginFlowNodeTest {
|
||||||
qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.ConnectionInsecure)
|
qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.ConnectionInsecure)
|
||||||
assertThat(flowNode.currentNavTarget()).isEqualTo(QrCodeLoginFlowNode.NavTarget.Error(QrCodeErrorScreenType.InsecureChannelDetected))
|
assertThat(flowNode.currentNavTarget()).isEqualTo(QrCodeLoginFlowNode.NavTarget.Error(QrCodeErrorScreenType.InsecureChannelDetected))
|
||||||
|
|
||||||
qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.OidcMetadataInvalid)
|
qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.OAuthMetadataInvalid)
|
||||||
assertThat(flowNode.currentNavTarget()).isEqualTo(QrCodeLoginFlowNode.NavTarget.Error(QrCodeErrorScreenType.UnknownError))
|
assertThat(flowNode.currentNavTarget()).isEqualTo(QrCodeLoginFlowNode.NavTarget.Error(QrCodeErrorScreenType.UnknownError))
|
||||||
|
|
||||||
qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.Unknown)
|
qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.Unknown)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import androidx.compose.ui.test.performClick
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import io.element.android.features.login.impl.accountprovider.anAccountProvider
|
import io.element.android.features.login.impl.accountprovider.anAccountProvider
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
|
|
@ -84,7 +84,7 @@ class ChooseAccountProviderViewTest {
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setChooseAccountProviderView(
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setChooseAccountProviderView(
|
||||||
state: ChooseAccountProviderState,
|
state: ChooseAccountProviderState,
|
||||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||||
onOidcDetails: (OidcDetails) -> Unit = EnsureNeverCalledWithParam(),
|
onOAuthDetails: (OAuthDetails) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
onNeedLoginPassword: () -> Unit = EnsureNeverCalled(),
|
onNeedLoginPassword: () -> Unit = EnsureNeverCalled(),
|
||||||
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
||||||
onCreateAccountContinue: (url: String) -> Unit = EnsureNeverCalledWithParam(),
|
onCreateAccountContinue: (url: String) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
|
|
@ -93,7 +93,7 @@ class ChooseAccountProviderViewTest {
|
||||||
ChooseAccountProviderView(
|
ChooseAccountProviderView(
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
onOidcDetails = onOidcDetails,
|
onOAuthDetails = onOAuthDetails,
|
||||||
onNeedLoginPassword = onNeedLoginPassword,
|
onNeedLoginPassword = onNeedLoginPassword,
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onCreateAccountContinue = onCreateAccountContinue,
|
onCreateAccountContinue = onCreateAccountContinue,
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails
|
import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow
|
import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -74,7 +74,7 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
fun `present - continue oidc`() = runTest {
|
fun `present - continue oidc`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
|
|
@ -89,21 +89,21 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
val successState = awaitItem()
|
val successState = awaitItem()
|
||||||
assertThat(successState.submitEnabled).isFalse()
|
assertThat(successState.submitEnabled).isFalse()
|
||||||
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - oidc - cancel with failure`() = runTest {
|
fun `present - OAuth - cancel with failure`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val defaultOidcActionFlow = FakeOidcActionFlow()
|
val defaultOAuthActionFlow = FakeOAuthActionFlow()
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
matrixAuthenticationService = authenticationService,
|
matrixAuthenticationService = authenticationService,
|
||||||
defaultOidcActionFlow = defaultOidcActionFlow,
|
defaultOAuthActionFlow = defaultOAuthActionFlow,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
|
@ -114,25 +114,25 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
val successState = awaitItem()
|
val successState = awaitItem()
|
||||||
assertThat(successState.submitEnabled).isFalse()
|
assertThat(successState.submitEnabled).isFalse()
|
||||||
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
authenticationService.givenOidcCancelError(AN_EXCEPTION)
|
authenticationService.givenOAuthCancelError(AN_EXCEPTION)
|
||||||
defaultOidcActionFlow.post(OidcAction.GoBack())
|
defaultOAuthActionFlow.post(OAuthAction.GoBack())
|
||||||
val cancelFailureState = awaitItem()
|
val cancelFailureState = awaitItem()
|
||||||
assertThat(cancelFailureState.loginMode).isInstanceOf(AsyncData.Failure::class.java)
|
assertThat(cancelFailureState.loginMode).isInstanceOf(AsyncData.Failure::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - oidc - cancel with success`() = runTest {
|
fun `present - OAuth - cancel with success`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val defaultOidcActionFlow = FakeOidcActionFlow()
|
val defaultOAuthActionFlow = FakeOAuthActionFlow()
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
matrixAuthenticationService = authenticationService,
|
matrixAuthenticationService = authenticationService,
|
||||||
defaultOidcActionFlow = defaultOidcActionFlow,
|
defaultOAuthActionFlow = defaultOAuthActionFlow,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
|
@ -143,24 +143,24 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
val successState = awaitItem()
|
val successState = awaitItem()
|
||||||
assertThat(successState.submitEnabled).isFalse()
|
assertThat(successState.submitEnabled).isFalse()
|
||||||
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
defaultOidcActionFlow.post(OidcAction.GoBack())
|
defaultOAuthActionFlow.post(OAuthAction.GoBack())
|
||||||
val cancelFinalState = awaitItem()
|
val cancelFinalState = awaitItem()
|
||||||
assertThat(cancelFinalState.loginMode).isInstanceOf(AsyncData.Uninitialized::class.java)
|
assertThat(cancelFinalState.loginMode).isInstanceOf(AsyncData.Uninitialized::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - oidc - cancel to unblock`() = runTest {
|
fun `present - OAuth - cancel to unblock`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val defaultOidcActionFlow = FakeOidcActionFlow()
|
val defaultOAuthActionFlow = FakeOAuthActionFlow()
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
matrixAuthenticationService = authenticationService,
|
matrixAuthenticationService = authenticationService,
|
||||||
defaultOidcActionFlow = defaultOidcActionFlow,
|
defaultOAuthActionFlow = defaultOAuthActionFlow,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
|
@ -168,23 +168,23 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
val loadingState = awaitItem()
|
val loadingState = awaitItem()
|
||||||
assertThat(loadingState.submitEnabled).isTrue()
|
assertThat(loadingState.submitEnabled).isTrue()
|
||||||
assertThat(loadingState.loginMode).isInstanceOf(AsyncData.Loading::class.java)
|
assertThat(loadingState.loginMode).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
defaultOidcActionFlow.post(OidcAction.GoBack(toUnblock = true))
|
defaultOAuthActionFlow.post(OAuthAction.GoBack(toUnblock = true))
|
||||||
val cancelFinalState = awaitItem()
|
val cancelFinalState = awaitItem()
|
||||||
assertThat(cancelFinalState.loginMode).isInstanceOf(AsyncData.Uninitialized::class.java)
|
assertThat(cancelFinalState.loginMode).isInstanceOf(AsyncData.Uninitialized::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - oidc - success with failure`() = runTest {
|
fun `present - OAuth - success with failure`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val defaultOidcActionFlow = FakeOidcActionFlow()
|
val defaultOAuthActionFlow = FakeOAuthActionFlow()
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
matrixAuthenticationService = authenticationService,
|
matrixAuthenticationService = authenticationService,
|
||||||
defaultOidcActionFlow = defaultOidcActionFlow,
|
defaultOAuthActionFlow = defaultOAuthActionFlow,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
|
@ -195,9 +195,9 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
val successState = awaitItem()
|
val successState = awaitItem()
|
||||||
assertThat(successState.submitEnabled).isFalse()
|
assertThat(successState.submitEnabled).isFalse()
|
||||||
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
authenticationService.givenLoginError(AN_EXCEPTION)
|
authenticationService.givenLoginError(AN_EXCEPTION)
|
||||||
defaultOidcActionFlow.post(OidcAction.Success("aUrl"))
|
defaultOAuthActionFlow.post(OAuthAction.Success("aUrl"))
|
||||||
val cancelLoadingState = awaitItem()
|
val cancelLoadingState = awaitItem()
|
||||||
assertThat(cancelLoadingState.loginMode).isInstanceOf(AsyncData.Loading::class.java)
|
assertThat(cancelLoadingState.loginMode).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
val cancelFailureState = awaitItem()
|
val cancelFailureState = awaitItem()
|
||||||
|
|
@ -206,16 +206,16 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - oidc - success with success`() = runTest {
|
fun `present - OAuth - success with success`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val defaultOidcActionFlow = FakeOidcActionFlow()
|
val defaultOidcActionFlow = FakeOAuthActionFlow()
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
matrixAuthenticationService = authenticationService,
|
matrixAuthenticationService = authenticationService,
|
||||||
defaultOidcActionFlow = defaultOidcActionFlow,
|
defaultOAuthActionFlow = defaultOidcActionFlow,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
|
@ -226,8 +226,8 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
val successState = awaitItem()
|
val successState = awaitItem()
|
||||||
assertThat(successState.submitEnabled).isFalse()
|
assertThat(successState.submitEnabled).isFalse()
|
||||||
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
defaultOidcActionFlow.post(OidcAction.Success("aUrl"))
|
defaultOidcActionFlow.post(OAuthAction.Success("aUrl"))
|
||||||
val successSuccessState = awaitItem()
|
val successSuccessState = awaitItem()
|
||||||
assertThat(successSuccessState.loginMode).isInstanceOf(AsyncData.Loading::class.java)
|
assertThat(successSuccessState.loginMode).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
}
|
}
|
||||||
|
|
@ -311,10 +311,10 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - confirm account creation with oidc is successful`() = runTest {
|
fun `present - confirm account creation with OAuth is successful`() = runTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
|
|
@ -327,16 +327,16 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
skipItems(1) // Loading
|
skipItems(1) // Loading
|
||||||
val submittedState = awaitItem()
|
val submittedState = awaitItem()
|
||||||
assertThat(submittedState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(submittedState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - confirm account creation with oidc and url continues with oidc`() = runTest {
|
fun `present - confirm account creation with OAuth and url continues with OAuth`() = runTest {
|
||||||
val aUrl = "aUrl"
|
val aUrl = "aUrl"
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
|
Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val presenter = createConfirmAccountProviderPresenter(
|
val presenter = createConfirmAccountProviderPresenter(
|
||||||
|
|
@ -350,12 +350,12 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
skipItems(1) // Loading
|
skipItems(1) // Loading
|
||||||
val submittedState = awaitItem()
|
val submittedState = awaitItem()
|
||||||
assertThat(submittedState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
assertThat(submittedState.loginMode).isInstanceOf(AsyncData.Success::class.java)
|
||||||
assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java)
|
assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - confirm account creation without oidc and with url continuing with url`() = runTest {
|
fun `present - confirm account creation without OAuth and with url continuing with url`() = runTest {
|
||||||
val aUrl = "aUrl"
|
val aUrl = "aUrl"
|
||||||
val authenticationService = FakeMatrixAuthenticationService(
|
val authenticationService = FakeMatrixAuthenticationService(
|
||||||
setHomeserverResult = {
|
setHomeserverResult = {
|
||||||
|
|
@ -380,14 +380,14 @@ class ConfirmAccountProviderPresenterTest {
|
||||||
params: ConfirmAccountProviderPresenter.Params = ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
|
params: ConfirmAccountProviderPresenter.Params = ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
|
||||||
accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
||||||
matrixAuthenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
matrixAuthenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
||||||
defaultOidcActionFlow: OidcActionFlow = FakeOidcActionFlow(),
|
defaultOAuthActionFlow: OAuthActionFlow = FakeOAuthActionFlow(),
|
||||||
webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(),
|
webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(),
|
||||||
) = ConfirmAccountProviderPresenter(
|
) = ConfirmAccountProviderPresenter(
|
||||||
params = params,
|
params = params,
|
||||||
accountProviderDataSource = accountProviderDataSource,
|
accountProviderDataSource = accountProviderDataSource,
|
||||||
loginHelper = createLoginHelper(
|
loginHelper = createLoginHelper(
|
||||||
authenticationService = matrixAuthenticationService,
|
authenticationService = matrixAuthenticationService,
|
||||||
oidcActionFlow = defaultOidcActionFlow,
|
oAuthActionFlow = defaultOAuthActionFlow,
|
||||||
webClientUrlForAuthenticationRetriever = webClientUrlForAuthenticationRetriever,
|
webClientUrlForAuthenticationRetriever = webClientUrlForAuthenticationRetriever,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ import io.element.android.libraries.matrix.test.A_HOMESERVER_URL_2
|
||||||
import io.element.android.libraries.matrix.test.A_LOGIN_HINT
|
import io.element.android.libraries.matrix.test.A_LOGIN_HINT
|
||||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow
|
import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||||
import io.element.android.libraries.sessionstorage.test.aSessionData
|
import io.element.android.libraries.sessionstorage.test.aSessionData
|
||||||
|
|
@ -312,11 +312,11 @@ private fun createPresenter(
|
||||||
)
|
)
|
||||||
|
|
||||||
fun createLoginHelper(
|
fun createLoginHelper(
|
||||||
oidcActionFlow: OidcActionFlow = FakeOidcActionFlow(),
|
oAuthActionFlow: OAuthActionFlow = FakeOAuthActionFlow(),
|
||||||
authenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
authenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
||||||
webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(),
|
webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(),
|
||||||
): LoginHelper = LoginHelper(
|
): LoginHelper = LoginHelper(
|
||||||
oidcActionFlow = oidcActionFlow,
|
oAuthActionFlow = oAuthActionFlow,
|
||||||
authenticationService = authenticationService,
|
authenticationService = authenticationService,
|
||||||
webClientUrlForAuthenticationRetriever = webClientUrlForAuthenticationRetriever,
|
webClientUrlForAuthenticationRetriever = webClientUrlForAuthenticationRetriever,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import com.google.testing.junit.testparameterinjector.TestParameter
|
||||||
import io.element.android.features.login.impl.R
|
import io.element.android.features.login.impl.R
|
||||||
import io.element.android.features.login.impl.login.LoginMode
|
import io.element.android.features.login.impl.login.LoginMode
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
|
|
@ -224,14 +224,14 @@ class OnboardingViewTest {
|
||||||
@Test
|
@Test
|
||||||
fun `when success Oidc - the expected callback is invoked and the event is received`() {
|
fun `when success Oidc - the expected callback is invoked and the event is received`() {
|
||||||
val eventSink = EventsRecorder<OnBoardingEvents>()
|
val eventSink = EventsRecorder<OnBoardingEvents>()
|
||||||
val oidcDetails = OidcDetails("aUrl")
|
val oAuthDetails = OAuthDetails("aUrl")
|
||||||
ensureCalledOnceWithParam(oidcDetails) { callback ->
|
ensureCalledOnceWithParam(oAuthDetails) { callback ->
|
||||||
rule.setOnboardingView(
|
rule.setOnboardingView(
|
||||||
state = anOnBoardingState(
|
state = anOnBoardingState(
|
||||||
loginMode = AsyncData.Success(LoginMode.Oidc(oidcDetails)),
|
loginMode = AsyncData.Success(LoginMode.OAuth(oAuthDetails)),
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
),
|
),
|
||||||
onOidcDetails = callback,
|
onOAuthDetails = callback,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
eventSink.assertSingle(OnBoardingEvents.ClearError)
|
eventSink.assertSingle(OnBoardingEvents.ClearError)
|
||||||
|
|
@ -240,8 +240,8 @@ class OnboardingViewTest {
|
||||||
@Test
|
@Test
|
||||||
fun `when success AccountCreation - the expected callback is invoked and the event is received`() {
|
fun `when success AccountCreation - the expected callback is invoked and the event is received`() {
|
||||||
val eventSink = EventsRecorder<OnBoardingEvents>()
|
val eventSink = EventsRecorder<OnBoardingEvents>()
|
||||||
val oidcDetails = OidcDetails("aUrl")
|
val oAuthDetails = OAuthDetails("aUrl")
|
||||||
ensureCalledOnceWithParam(oidcDetails.url) { callback ->
|
ensureCalledOnceWithParam(oAuthDetails.url) { callback ->
|
||||||
rule.setOnboardingView(
|
rule.setOnboardingView(
|
||||||
state = anOnBoardingState(
|
state = anOnBoardingState(
|
||||||
loginMode = AsyncData.Success(LoginMode.AccountCreation("aUrl")),
|
loginMode = AsyncData.Success(LoginMode.AccountCreation("aUrl")),
|
||||||
|
|
@ -261,7 +261,7 @@ class OnboardingViewTest {
|
||||||
onSignIn: (Boolean) -> Unit = EnsureNeverCalledWithParam(),
|
onSignIn: (Boolean) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
onCreateAccount: () -> Unit = EnsureNeverCalled(),
|
onCreateAccount: () -> Unit = EnsureNeverCalled(),
|
||||||
onReportProblem: () -> Unit = EnsureNeverCalled(),
|
onReportProblem: () -> Unit = EnsureNeverCalled(),
|
||||||
onOidcDetails: (OidcDetails) -> Unit = EnsureNeverCalledWithParam(),
|
onOAuthDetails: (OAuthDetails) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
onNeedLoginPassword: () -> Unit = EnsureNeverCalled(),
|
onNeedLoginPassword: () -> Unit = EnsureNeverCalled(),
|
||||||
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
||||||
onCreateAccountContinue: (url: String) -> Unit = EnsureNeverCalledWithParam(),
|
onCreateAccountContinue: (url: String) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
|
|
@ -275,7 +275,7 @@ class OnboardingViewTest {
|
||||||
onSignIn = onSignIn,
|
onSignIn = onSignIn,
|
||||||
onCreateAccount = onCreateAccount,
|
onCreateAccount = onCreateAccount,
|
||||||
onReportProblem = onReportProblem,
|
onReportProblem = onReportProblem,
|
||||||
onOidcDetails = onOidcDetails,
|
onOAuthDetails = onOAuthDetails,
|
||||||
onNeedLoginPassword = onNeedLoginPassword,
|
onNeedLoginPassword = onNeedLoginPassword,
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onCreateAccountContinue = onCreateAccountContinue,
|
onCreateAccountContinue = onCreateAccountContinue,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import io.element.android.libraries.featureflag.test.FakeFeature
|
||||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||||
import io.element.android.libraries.indicator.api.IndicatorService
|
import io.element.android.libraries.indicator.api.IndicatorService
|
||||||
import io.element.android.libraries.indicator.test.FakeIndicatorService
|
import io.element.android.libraries.indicator.test.FakeIndicatorService
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ dependencies {
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
implementation(projects.libraries.matrixui)
|
implementation(projects.libraries.matrixui)
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.oidc.api)
|
implementation(projects.libraries.oauth.api)
|
||||||
implementation(projects.libraries.uiStrings)
|
implementation(projects.libraries.uiStrings)
|
||||||
implementation(projects.libraries.testtags)
|
implementation(projects.libraries.testtags)
|
||||||
api(libs.statemachine)
|
api(libs.statemachine)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityOAuthResetHandle
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -123,12 +123,12 @@ class ResetIdentityFlowNode(
|
||||||
null -> {
|
null -> {
|
||||||
Timber.d("No reset handle return, the reset is done.")
|
Timber.d("No reset handle return, the reset is done.")
|
||||||
}
|
}
|
||||||
is IdentityOidcResetHandle -> {
|
is IdentityOAuthResetHandle -> {
|
||||||
Timber.d("Launching reset confirmation in MAS")
|
Timber.d("Launching reset confirmation in MAS")
|
||||||
activity.openUrlInChromeCustomTab(null, darkTheme, handle.url)
|
activity.openUrlInChromeCustomTab(null, darkTheme, handle.url)
|
||||||
Timber.d("Starting resetOidc")
|
Timber.d("Starting resetOAuth")
|
||||||
resetJob = launch { handle.resetOidc() }
|
resetJob = launch { handle.resetOAuth() }
|
||||||
resetJob?.invokeOnCompletion { Timber.d("resetOidc ended") }
|
resetJob?.invokeOnCompletion { Timber.d("resetOAuth ended") }
|
||||||
}
|
}
|
||||||
is IdentityPasswordResetHandle -> backstack.push(NavTarget.ResetPassword)
|
is IdentityPasswordResetHandle -> backstack.push(NavTarget.ResetPassword)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ private fun aSessionData(
|
||||||
accessToken = "anAccessToken",
|
accessToken = "anAccessToken",
|
||||||
refreshToken = "aRefreshToken",
|
refreshToken = "aRefreshToken",
|
||||||
homeserverUrl = "aHomeserverUrl",
|
homeserverUrl = "aHomeserverUrl",
|
||||||
oidcData = null,
|
oAuthData = null,
|
||||||
loginTimestamp = null,
|
loginTimestamp = null,
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = LoginType.UNKNOWN,
|
loginType = LoginType.UNKNOWN,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||||
import io.element.android.libraries.matrix.api.media.MediaPreviewService
|
import io.element.android.libraries.matrix.api.media.MediaPreviewService
|
||||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@ sealed class AuthenticationException(message: String?) : Exception(message) {
|
||||||
class InvalidServerName(message: String?) : AuthenticationException(message)
|
class InvalidServerName(message: String?) : AuthenticationException(message)
|
||||||
class SlidingSyncVersion(message: String?) : AuthenticationException(message)
|
class SlidingSyncVersion(message: String?) : AuthenticationException(message)
|
||||||
class ServerUnreachable(message: String?) : AuthenticationException(message)
|
class ServerUnreachable(message: String?) : AuthenticationException(message)
|
||||||
class Oidc(message: String?) : AuthenticationException(message)
|
class OAuth(message: String?) : AuthenticationException(message)
|
||||||
class Generic(message: String?) : AuthenticationException(message)
|
class Generic(message: String?) : AuthenticationException(message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,21 +37,21 @@ interface MatrixAuthenticationService {
|
||||||
suspend fun importCreatedSession(externalSession: ExternalSession): Result<SessionId>
|
suspend fun importCreatedSession(externalSession: ExternalSession): Result<SessionId>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OIDC part.
|
* OAuth part.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Oidc url to display to the user.
|
* Get the OAuth url to display to the user.
|
||||||
*/
|
*/
|
||||||
suspend fun getOidcUrl(
|
suspend fun getOAuthUrl(
|
||||||
prompt: OidcPrompt,
|
prompt: OAuthPrompt,
|
||||||
loginHint: String?,
|
loginHint: String?,
|
||||||
): Result<OidcDetails>
|
): Result<OAuthDetails>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel Oidc login sequence.
|
* Cancel OAuth login sequence.
|
||||||
*/
|
*/
|
||||||
suspend fun cancelOidcLogin(): Result<Unit>
|
suspend fun cancelOAuthLogin(): Result<Unit>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the existing data about Element Classic session, if any.
|
* Set the existing data about Element Classic session, if any.
|
||||||
|
|
@ -68,9 +68,9 @@ interface MatrixAuthenticationService {
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to login using the [callbackUrl] provided by the Oidc page.
|
* Attempt to log in using the [callbackUrl] provided by the OAuth page.
|
||||||
*/
|
*/
|
||||||
suspend fun loginWithOidc(callbackUrl: String): Result<SessionId>
|
suspend fun loginWithOAuth(callbackUrl: String): Result<SessionId>
|
||||||
|
|
||||||
suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit): Result<SessionId>
|
suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit): Result<SessionId>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ package io.element.android.libraries.matrix.api.auth
|
||||||
data class MatrixHomeServerDetails(
|
data class MatrixHomeServerDetails(
|
||||||
val url: String,
|
val url: String,
|
||||||
val supportsPasswordLogin: Boolean,
|
val supportsPasswordLogin: Boolean,
|
||||||
val supportsOidcLogin: Boolean,
|
val supportsOAuthLogin: Boolean,
|
||||||
) {
|
) {
|
||||||
val isSupported = supportsPasswordLogin || supportsOidcLogin
|
val isSupported = supportsPasswordLogin || supportsOAuthLogin
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.api.auth
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.BuildConfig
|
import io.element.android.libraries.matrix.api.BuildConfig
|
||||||
|
|
||||||
object OidcConfig {
|
object OAuthConfig {
|
||||||
const val CLIENT_URI = BuildConfig.CLIENT_URI
|
const val CLIENT_URI = BuildConfig.CLIENT_URI
|
||||||
|
|
||||||
// Note: host must match with the host of CLIENT_URI
|
// Note: host must match with the host of CLIENT_URI
|
||||||
|
|
@ -12,6 +12,6 @@ import android.os.Parcelable
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class OidcDetails(
|
data class OAuthDetails(
|
||||||
val url: String,
|
val url: String,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.auth
|
package io.element.android.libraries.matrix.api.auth
|
||||||
|
|
||||||
sealed interface OidcPrompt {
|
sealed interface OAuthPrompt {
|
||||||
/**
|
/**
|
||||||
* The Authorization Server should prompt the End-User for
|
* The Authorization Server should prompt the End-User for
|
||||||
* reauthentication.
|
* reauthentication.
|
||||||
*/
|
*/
|
||||||
data object Login : OidcPrompt
|
data object Login : OAuthPrompt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Authorization Server should prompt the End-User to create a user
|
* The Authorization Server should prompt the End-User to create a user
|
||||||
|
|
@ -21,10 +21,10 @@ sealed interface OidcPrompt {
|
||||||
*
|
*
|
||||||
* Defined in [Initiating User Registration via OpenID Connect](https://openid.net/specs/openid-connect-prompt-create-1_0.html).
|
* Defined in [Initiating User Registration via OpenID Connect](https://openid.net/specs/openid-connect-prompt-create-1_0.html).
|
||||||
*/
|
*/
|
||||||
data object Create : OidcPrompt
|
data object Create : OAuthPrompt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unknown value.
|
* An unknown value.
|
||||||
*/
|
*/
|
||||||
data class Unknown(val value: String) : OidcPrompt
|
data class Unknown(val value: String) : OAuthPrompt
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,6 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.auth
|
package io.element.android.libraries.matrix.api.auth
|
||||||
|
|
||||||
interface OidcRedirectUrlProvider {
|
interface OAuthRedirectUrlProvider {
|
||||||
fun provide(): String
|
fun provide(): String
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ sealed class QrLoginException : Exception() {
|
||||||
data object Expired : QrLoginException()
|
data object Expired : QrLoginException()
|
||||||
data object NotFound : QrLoginException()
|
data object NotFound : QrLoginException()
|
||||||
data object LinkingNotSupported : QrLoginException()
|
data object LinkingNotSupported : QrLoginException()
|
||||||
data object OidcMetadataInvalid : QrLoginException()
|
data object OAuthMetadataInvalid : QrLoginException()
|
||||||
data object SlidingSyncNotAvailable : QrLoginException()
|
data object SlidingSyncNotAvailable : QrLoginException()
|
||||||
data object OtherDeviceNotSignedIn : QrLoginException()
|
data object OtherDeviceNotSignedIn : QrLoginException()
|
||||||
data object CheckCodeAlreadySent : QrLoginException()
|
data object CheckCodeAlreadySent : QrLoginException()
|
||||||
|
|
|
||||||
|
|
@ -112,19 +112,19 @@ interface IdentityPasswordResetHandle : IdentityResetHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handle to reset the user's identity with an OIDC login type.
|
* A handle to reset the user's identity with an OAuth login type.
|
||||||
*/
|
*/
|
||||||
interface IdentityOidcResetHandle : IdentityResetHandle {
|
interface IdentityOAuthResetHandle : IdentityResetHandle {
|
||||||
/**
|
/**
|
||||||
* The URL to open in a webview/custom tab to reset the identity.
|
* The URL to open in a webview/custom tab to reset the identity.
|
||||||
*/
|
*/
|
||||||
val url: String
|
val url: String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the identity using the OIDC flow.
|
* Reset the identity using the OAuth flow.
|
||||||
*
|
*
|
||||||
* This method will block the coroutine it's running on and keep polling indefinitely until either the coroutine is cancelled, the [cancel] method is
|
* This method will block the coroutine it's running on and keep polling indefinitely until either the coroutine is cancelled, the [cancel] method is
|
||||||
* called, or the identity is reset.
|
* called, or the identity is reset.
|
||||||
*/
|
*/
|
||||||
suspend fun resetOidc(): Result<Unit>
|
suspend fun resetOAuth(): Result<Unit>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.oidc
|
package io.element.android.libraries.matrix.api.oauth
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ class MatrixHomeServerDetailsTest {
|
||||||
@Test
|
@Test
|
||||||
fun `if homeserver supports oidc, then it is supported`() {
|
fun `if homeserver supports oidc, then it is supported`() {
|
||||||
val sut = aMatrixHomeServerDetails(
|
val sut = aMatrixHomeServerDetails(
|
||||||
supportsOidcLogin = true,
|
supportsOAuthLogin = true,
|
||||||
supportsPasswordLogin = false,
|
supportsPasswordLogin = false,
|
||||||
)
|
)
|
||||||
assertThat(sut.isSupported).isTrue()
|
assertThat(sut.isSupported).isTrue()
|
||||||
|
|
@ -25,7 +25,7 @@ class MatrixHomeServerDetailsTest {
|
||||||
@Test
|
@Test
|
||||||
fun `if homeserver supports password, then it is supported`() {
|
fun `if homeserver supports password, then it is supported`() {
|
||||||
val sut = aMatrixHomeServerDetails(
|
val sut = aMatrixHomeServerDetails(
|
||||||
supportsOidcLogin = false,
|
supportsOAuthLogin = false,
|
||||||
supportsPasswordLogin = true,
|
supportsPasswordLogin = true,
|
||||||
)
|
)
|
||||||
assertThat(sut.isSupported).isTrue()
|
assertThat(sut.isSupported).isTrue()
|
||||||
|
|
@ -34,7 +34,7 @@ class MatrixHomeServerDetailsTest {
|
||||||
@Test
|
@Test
|
||||||
fun `if homeserver supports both, then it is supported`() {
|
fun `if homeserver supports both, then it is supported`() {
|
||||||
val sut = aMatrixHomeServerDetails(
|
val sut = aMatrixHomeServerDetails(
|
||||||
supportsOidcLogin = true,
|
supportsOAuthLogin = true,
|
||||||
supportsPasswordLogin = true,
|
supportsPasswordLogin = true,
|
||||||
)
|
)
|
||||||
assertThat(sut.isSupported).isTrue()
|
assertThat(sut.isSupported).isTrue()
|
||||||
|
|
@ -43,7 +43,7 @@ class MatrixHomeServerDetailsTest {
|
||||||
@Test
|
@Test
|
||||||
fun `if homeserver supports none, then it is not supported`() {
|
fun `if homeserver supports none, then it is not supported`() {
|
||||||
val sut = aMatrixHomeServerDetails(
|
val sut = aMatrixHomeServerDetails(
|
||||||
supportsOidcLogin = false,
|
supportsOAuthLogin = false,
|
||||||
supportsPasswordLogin = false,
|
supportsPasswordLogin = false,
|
||||||
)
|
)
|
||||||
assertThat(sut.isSupported).isFalse()
|
assertThat(sut.isSupported).isFalse()
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||||
import io.element.android.libraries.matrix.api.linknewdevice.LinkDesktopHandler
|
import io.element.android.libraries.matrix.api.linknewdevice.LinkDesktopHandler
|
||||||
import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileHandler
|
import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileHandler
|
||||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
@ -59,7 +59,7 @@ import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
||||||
import io.element.android.libraries.matrix.impl.media.RustMediaPreviewService
|
import io.element.android.libraries.matrix.impl.media.RustMediaPreviewService
|
||||||
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
||||||
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
|
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
|
||||||
import io.element.android.libraries.matrix.impl.oidc.toRustAction
|
import io.element.android.libraries.matrix.impl.oauth.toRustAction
|
||||||
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
||||||
import io.element.android.libraries.matrix.impl.room.GetRoomResult
|
import io.element.android.libraries.matrix.impl.room.GetRoomResult
|
||||||
import io.element.android.libraries.matrix.impl.room.NotJoinedRustRoom
|
import io.element.android.libraries.matrix.impl.room.NotJoinedRustRoom
|
||||||
|
|
|
||||||
|
|
@ -214,5 +214,5 @@ fun SessionData.toSession() = Session(
|
||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
homeserverUrl = homeserverUrl,
|
homeserverUrl = homeserverUrl,
|
||||||
slidingSyncVersion = SlidingSyncVersion.NATIVE,
|
slidingSyncVersion = SlidingSyncVersion.NATIVE,
|
||||||
oauthData = oidcData,
|
oauthData = oAuthData,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,11 @@ fun Throwable.mapAuthenticationException(): AuthenticationException {
|
||||||
is ClientBuildException.EventCache -> AuthenticationException.Generic(message)
|
is ClientBuildException.EventCache -> AuthenticationException.Generic(message)
|
||||||
}
|
}
|
||||||
is OAuthException -> when (this) {
|
is OAuthException -> when (this) {
|
||||||
is OAuthException.Generic -> AuthenticationException.Oidc(message)
|
is OAuthException.Generic -> AuthenticationException.OAuth(message)
|
||||||
is OAuthException.CallbackUrlInvalid -> AuthenticationException.Oidc(message)
|
is OAuthException.CallbackUrlInvalid -> AuthenticationException.OAuth(message)
|
||||||
is OAuthException.Cancelled -> AuthenticationException.Oidc(message)
|
is OAuthException.Cancelled -> AuthenticationException.OAuth(message)
|
||||||
is OAuthException.MetadataInvalid -> AuthenticationException.Oidc(message)
|
is OAuthException.MetadataInvalid -> AuthenticationException.OAuth(message)
|
||||||
is OAuthException.NotSupported -> AuthenticationException.Oidc(message)
|
is OAuthException.NotSupported -> AuthenticationException.OAuth(message)
|
||||||
}
|
}
|
||||||
else -> AuthenticationException.Generic(message)
|
else -> AuthenticationException.Generic(message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,6 @@ fun HomeserverLoginDetails.map(): MatrixHomeServerDetails = use {
|
||||||
MatrixHomeServerDetails(
|
MatrixHomeServerDetails(
|
||||||
url = url(),
|
url = url(),
|
||||||
supportsPasswordLogin = supportsPasswordLogin(),
|
supportsPasswordLogin = supportsPasswordLogin(),
|
||||||
supportsOidcLogin = supportsOauthLogin(),
|
supportsOAuthLogin = supportsOauthLogin(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,22 @@ package io.element.android.libraries.matrix.impl.auth
|
||||||
|
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.Inject
|
||||||
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.OAuthConfig
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider
|
||||||
import org.matrix.rustcomponents.sdk.OAuthConfiguration
|
import org.matrix.rustcomponents.sdk.OAuthConfiguration
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
class OidcConfigurationProvider(
|
class OAuthConfigurationProvider(
|
||||||
private val buildMeta: BuildMeta,
|
private val buildMeta: BuildMeta,
|
||||||
private val oidcRedirectUrlProvider: OidcRedirectUrlProvider,
|
private val oAuthRedirectUrlProvider: OAuthRedirectUrlProvider,
|
||||||
) {
|
) {
|
||||||
fun get(): OAuthConfiguration = OAuthConfiguration(
|
fun get(): OAuthConfiguration = OAuthConfiguration(
|
||||||
clientName = buildMeta.applicationName,
|
clientName = buildMeta.applicationName,
|
||||||
redirectUri = oidcRedirectUrlProvider.provide(),
|
redirectUri = oAuthRedirectUrlProvider.provide(),
|
||||||
clientUri = OidcConfig.CLIENT_URI,
|
clientUri = OAuthConfig.CLIENT_URI,
|
||||||
logoUri = OidcConfig.LOGO_URI,
|
logoUri = OAuthConfig.LOGO_URI,
|
||||||
tosUri = OidcConfig.TOS_URI,
|
tosUri = OAuthConfig.TOS_URI,
|
||||||
policyUri = OidcConfig.POLICY_URI,
|
policyUri = OAuthConfig.POLICY_URI,
|
||||||
staticRegistrations = OidcConfig.STATIC_REGISTRATIONS,
|
staticRegistrations = OAuthConfig.STATIC_REGISTRATIONS,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -8,13 +8,13 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.auth
|
package io.element.android.libraries.matrix.impl.auth
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcPrompt
|
import io.element.android.libraries.matrix.api.auth.OAuthPrompt
|
||||||
import org.matrix.rustcomponents.sdk.OAuthPrompt as RustOidcPrompt
|
import org.matrix.rustcomponents.sdk.OAuthPrompt as RustOAuthPrompt
|
||||||
|
|
||||||
internal fun OidcPrompt.toRustPrompt(): RustOidcPrompt {
|
internal fun OAuthPrompt.toRustPrompt(): RustOAuthPrompt {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
OidcPrompt.Login -> RustOidcPrompt.Unknown("consent")
|
OAuthPrompt.Login -> RustOAuthPrompt.Unknown("consent")
|
||||||
OidcPrompt.Create -> RustOidcPrompt.Create
|
OAuthPrompt.Create -> RustOAuthPrompt.Create
|
||||||
is OidcPrompt.Unknown -> RustOidcPrompt.Unknown(value)
|
is OAuthPrompt.Unknown -> RustOAuthPrompt.Unknown(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class RustHomeServerLoginCompatibilityChecker(
|
||||||
it.homeserverLoginDetails()
|
it.homeserverLoginDetails()
|
||||||
}
|
}
|
||||||
.use {
|
.use {
|
||||||
Timber.d("Homeserver $url | OIDC: ${it.supportsOauthLogin()} | Password: ${it.supportsPasswordLogin()} | SSO: ${it.supportsSsoLogin()}")
|
Timber.d("Homeserver $url | OAuth: ${it.supportsOauthLogin()} | Password: ${it.supportsPasswordLogin()} | SSO: ${it.supportsSsoLogin()}")
|
||||||
it.supportsOauthLogin() || it.supportsPasswordLogin()
|
it.supportsOauthLogin() || it.supportsPasswordLogin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
||||||
import io.element.android.libraries.matrix.api.auth.ElementClassicSession
|
import io.element.android.libraries.matrix.api.auth.ElementClassicSession
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcPrompt
|
import io.element.android.libraries.matrix.api.auth.OAuthPrompt
|
||||||
import io.element.android.libraries.matrix.api.auth.SessionRestorationException
|
import io.element.android.libraries.matrix.api.auth.SessionRestorationException
|
||||||
import io.element.android.libraries.matrix.api.auth.external.ExternalSession
|
import io.element.android.libraries.matrix.api.auth.external.ExternalSession
|
||||||
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
|
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
|
||||||
|
|
@ -65,7 +65,7 @@ class RustMatrixAuthenticationService(
|
||||||
private val sessionStore: SessionStore,
|
private val sessionStore: SessionStore,
|
||||||
private val rustMatrixClientFactory: RustMatrixClientFactory,
|
private val rustMatrixClientFactory: RustMatrixClientFactory,
|
||||||
private val passphraseGenerator: PassphraseGenerator,
|
private val passphraseGenerator: PassphraseGenerator,
|
||||||
private val oidcConfigurationProvider: OidcConfigurationProvider,
|
private val oAuthConfigurationProvider: OAuthConfigurationProvider,
|
||||||
) : MatrixAuthenticationService {
|
) : MatrixAuthenticationService {
|
||||||
// Any existing Element Classic session that we want to try to import secrets from during login.
|
// Any existing Element Classic session that we want to try to import secrets from during login.
|
||||||
private var elementClassicSession: ElementClassicSession? = null
|
private var elementClassicSession: ElementClassicSession? = null
|
||||||
|
|
@ -253,15 +253,15 @@ class RustMatrixAuthenticationService(
|
||||||
|
|
||||||
private var pendingOAuthAuthorizationData: OAuthAuthorizationData? = null
|
private var pendingOAuthAuthorizationData: OAuthAuthorizationData? = null
|
||||||
|
|
||||||
override suspend fun getOidcUrl(
|
override suspend fun getOAuthUrl(
|
||||||
prompt: OidcPrompt,
|
prompt: OAuthPrompt,
|
||||||
loginHint: String?,
|
loginHint: String?,
|
||||||
): Result<OidcDetails> {
|
): Result<OAuthDetails> {
|
||||||
return withContext(coroutineDispatchers.io) {
|
return withContext(coroutineDispatchers.io) {
|
||||||
runCatchingExceptions {
|
runCatchingExceptions {
|
||||||
val client = currentClient ?: error("You need to call `setHomeserver()` first")
|
val client = currentClient ?: error("You need to call `setHomeserver()` first")
|
||||||
val oAuthAuthorizationData = client.urlForOauth(
|
val oAuthAuthorizationData = client.urlForOauth(
|
||||||
oauthConfiguration = oidcConfigurationProvider.get(),
|
oauthConfiguration = oAuthConfigurationProvider.get(),
|
||||||
prompt = prompt.toRustPrompt(),
|
prompt = prompt.toRustPrompt(),
|
||||||
loginHint = loginHint,
|
loginHint = loginHint,
|
||||||
// If we want to restore a previous session for which we have encryption keys, we can pass the deviceId here. At the moment, we don't
|
// If we want to restore a previous session for which we have encryption keys, we can pass the deviceId here. At the moment, we don't
|
||||||
|
|
@ -270,15 +270,15 @@ class RustMatrixAuthenticationService(
|
||||||
)
|
)
|
||||||
val url = oAuthAuthorizationData.loginUrl()
|
val url = oAuthAuthorizationData.loginUrl()
|
||||||
pendingOAuthAuthorizationData = oAuthAuthorizationData
|
pendingOAuthAuthorizationData = oAuthAuthorizationData
|
||||||
OidcDetails(url)
|
OAuthDetails(url)
|
||||||
}.mapFailure { failure ->
|
}.mapFailure { failure ->
|
||||||
Timber.e(failure, "Failed to get OIDC URL")
|
Timber.e(failure, "Failed to get OAuth URL")
|
||||||
failure.mapAuthenticationException()
|
failure.mapAuthenticationException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun cancelOidcLogin(): Result<Unit> {
|
override suspend fun cancelOAuthLogin(): Result<Unit> {
|
||||||
return withContext(coroutineDispatchers.io) {
|
return withContext(coroutineDispatchers.io) {
|
||||||
runCatchingExceptions {
|
runCatchingExceptions {
|
||||||
pendingOAuthAuthorizationData?.use {
|
pendingOAuthAuthorizationData?.use {
|
||||||
|
|
@ -286,7 +286,7 @@ class RustMatrixAuthenticationService(
|
||||||
}
|
}
|
||||||
pendingOAuthAuthorizationData = null
|
pendingOAuthAuthorizationData = null
|
||||||
}.mapFailure { failure ->
|
}.mapFailure { failure ->
|
||||||
Timber.e(failure, "Failed to cancel OIDC login")
|
Timber.e(failure, "Failed to cancel OAuth login")
|
||||||
failure.mapAuthenticationException()
|
failure.mapAuthenticationException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -297,9 +297,9 @@ class RustMatrixAuthenticationService(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* callbackUrl should be the uriRedirect from OidcClientMetadata (with all the parameters).
|
* callbackUrl should be the `url` from `OAuthAction` (with all the parameters).
|
||||||
*/
|
*/
|
||||||
override suspend fun loginWithOidc(callbackUrl: String): Result<SessionId> {
|
override suspend fun loginWithOAuth(callbackUrl: String): Result<SessionId> {
|
||||||
return withContext(coroutineDispatchers.io) {
|
return withContext(coroutineDispatchers.io) {
|
||||||
runCatchingExceptions {
|
runCatchingExceptions {
|
||||||
val client = currentClient ?: error("You need to call `setHomeserver()` first")
|
val client = currentClient ?: error("You need to call `setHomeserver()` first")
|
||||||
|
|
@ -330,7 +330,7 @@ class RustMatrixAuthenticationService(
|
||||||
|
|
||||||
SessionId(sessionData.userId)
|
SessionId(sessionData.userId)
|
||||||
}.mapFailure { failure ->
|
}.mapFailure { failure ->
|
||||||
Timber.e(failure, "Failed to login with OIDC")
|
Timber.e(failure, "Failed to login with OAuth")
|
||||||
failure.mapAuthenticationException()
|
failure.mapAuthenticationException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -355,7 +355,7 @@ class RustMatrixAuthenticationService(
|
||||||
withContext(coroutineDispatchers.io) {
|
withContext(coroutineDispatchers.io) {
|
||||||
val sdkQrCodeLoginData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData
|
val sdkQrCodeLoginData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData
|
||||||
val emptySessionPaths = rotateSessionPath()
|
val emptySessionPaths = rotateSessionPath()
|
||||||
val oidcConfiguration = oidcConfigurationProvider.get()
|
val oAuthConfiguration = oAuthConfigurationProvider.get()
|
||||||
val progressListener = object : QrLoginProgressListener {
|
val progressListener = object : QrLoginProgressListener {
|
||||||
override fun onUpdate(state: QrLoginProgress) {
|
override fun onUpdate(state: QrLoginProgress) {
|
||||||
Timber.d("QR Code login progress: $state")
|
Timber.d("QR Code login progress: $state")
|
||||||
|
|
@ -368,7 +368,7 @@ class RustMatrixAuthenticationService(
|
||||||
qrCodeData = sdkQrCodeLoginData,
|
qrCodeData = sdkQrCodeLoginData,
|
||||||
)
|
)
|
||||||
client.newLoginWithQrCodeHandler(
|
client.newLoginWithQrCodeHandler(
|
||||||
oauthConfiguration = oidcConfiguration,
|
oauthConfiguration = oAuthConfiguration,
|
||||||
).use {
|
).use {
|
||||||
it.scan(
|
it.scan(
|
||||||
qrCodeData = qrCodeData.rustQrCodeData,
|
qrCodeData = qrCodeData.rustQrCodeData,
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ object QrErrorMapper {
|
||||||
is RustHumanQrLoginException.OtherDeviceNotSignedIn -> QrLoginException.OtherDeviceNotSignedIn
|
is RustHumanQrLoginException.OtherDeviceNotSignedIn -> QrLoginException.OtherDeviceNotSignedIn
|
||||||
is RustHumanQrLoginException.LinkingNotSupported -> QrLoginException.LinkingNotSupported
|
is RustHumanQrLoginException.LinkingNotSupported -> QrLoginException.LinkingNotSupported
|
||||||
is RustHumanQrLoginException.Unknown -> QrLoginException.Unknown
|
is RustHumanQrLoginException.Unknown -> QrLoginException.Unknown
|
||||||
is RustHumanQrLoginException.OAuthMetadataInvalid -> QrLoginException.OidcMetadataInvalid
|
is RustHumanQrLoginException.OAuthMetadataInvalid -> QrLoginException.OAuthMetadataInvalid
|
||||||
is RustHumanQrLoginException.SlidingSyncNotAvailable -> QrLoginException.SlidingSyncNotAvailable
|
is RustHumanQrLoginException.SlidingSyncNotAvailable -> QrLoginException.SlidingSyncNotAvailable
|
||||||
is RustHumanQrLoginException.CheckCodeAlreadySent -> QrLoginException.CheckCodeAlreadySent
|
is RustHumanQrLoginException.CheckCodeAlreadySent -> QrLoginException.CheckCodeAlreadySent
|
||||||
is RustHumanQrLoginException.CheckCodeCannotBeSent -> QrLoginException.CheckCodeCannotBeSent
|
is RustHumanQrLoginException.CheckCodeCannotBeSent -> QrLoginException.CheckCodeCannotBeSent
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.impl.encryption
|
||||||
|
|
||||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityOAuthResetHandle
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityResetHandle
|
||||||
import org.matrix.rustcomponents.sdk.AuthData
|
import org.matrix.rustcomponents.sdk.AuthData
|
||||||
|
|
@ -25,7 +25,7 @@ object RustIdentityResetHandleFactory {
|
||||||
return runCatchingExceptions {
|
return runCatchingExceptions {
|
||||||
identityResetHandle?.let {
|
identityResetHandle?.let {
|
||||||
when (val authType = identityResetHandle.authType()) {
|
when (val authType = identityResetHandle.authType()) {
|
||||||
is CrossSigningResetAuthType.OAuth -> RustOidcIdentityResetHandle(identityResetHandle, authType.info.approvalUrl)
|
is CrossSigningResetAuthType.OAuth -> RustIdentityOAuthResetHandle(identityResetHandle, authType.info.approvalUrl)
|
||||||
// User interactive authentication (user + password)
|
// User interactive authentication (user + password)
|
||||||
CrossSigningResetAuthType.Uiaa -> RustPasswordIdentityResetHandle(userId, identityResetHandle)
|
CrossSigningResetAuthType.Uiaa -> RustPasswordIdentityResetHandle(userId, identityResetHandle)
|
||||||
}
|
}
|
||||||
|
|
@ -47,11 +47,11 @@ class RustPasswordIdentityResetHandle(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RustOidcIdentityResetHandle(
|
class RustIdentityOAuthResetHandle(
|
||||||
private val identityResetHandle: org.matrix.rustcomponents.sdk.IdentityResetHandle,
|
private val identityResetHandle: org.matrix.rustcomponents.sdk.IdentityResetHandle,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
) : IdentityOidcResetHandle {
|
) : IdentityOAuthResetHandle {
|
||||||
override suspend fun resetOidc(): Result<Unit> {
|
override suspend fun resetOAuth(): Result<Unit> {
|
||||||
return runCatchingExceptions { identityResetHandle.reset(null) }
|
return runCatchingExceptions { identityResetHandle.reset(null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ internal fun Session.toSessionData(
|
||||||
accessToken = accessToken,
|
accessToken = accessToken,
|
||||||
refreshToken = refreshToken,
|
refreshToken = refreshToken,
|
||||||
homeserverUrl = homeserverUrl ?: this.homeserverUrl,
|
homeserverUrl = homeserverUrl ?: this.homeserverUrl,
|
||||||
oidcData = oauthData,
|
oAuthData = oauthData,
|
||||||
loginTimestamp = Date(),
|
loginTimestamp = Date(),
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = loginType,
|
loginType = loginType,
|
||||||
|
|
@ -52,7 +52,7 @@ internal fun ExternalSession.toSessionData(
|
||||||
accessToken = accessToken,
|
accessToken = accessToken,
|
||||||
refreshToken = refreshToken,
|
refreshToken = refreshToken,
|
||||||
homeserverUrl = homeserverUrl,
|
homeserverUrl = homeserverUrl,
|
||||||
oidcData = null,
|
oAuthData = null,
|
||||||
loginTimestamp = Date(),
|
loginTimestamp = Date(),
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = loginType,
|
loginType = loginType,
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.oidc
|
package io.element.android.libraries.matrix.impl.oauth
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManagementAction
|
import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManagementAction
|
||||||
|
|
||||||
fun AccountManagementAction.toRustAction(): RustAccountManagementAction {
|
fun AccountManagementAction.toRustAction(): RustAccountManagementAction {
|
||||||
|
|
@ -64,17 +64,17 @@ class AuthenticationExceptionMappingTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `mapping Oidc exceptions map to the Oidc Kotlin`() {
|
fun `mapping Oidc exceptions map to the OAuth Kotlin`() {
|
||||||
assertThat(OAuthException.Generic("Generic").mapAuthenticationException())
|
assertThat(OAuthException.Generic("Generic").mapAuthenticationException())
|
||||||
.isException<AuthenticationException.Oidc>("Generic")
|
.isException<AuthenticationException.OAuth>("Generic")
|
||||||
assertThat(OAuthException.CallbackUrlInvalid("CallbackUrlInvalid").mapAuthenticationException())
|
assertThat(OAuthException.CallbackUrlInvalid("CallbackUrlInvalid").mapAuthenticationException())
|
||||||
.isException<AuthenticationException.Oidc>("CallbackUrlInvalid")
|
.isException<AuthenticationException.OAuth>("CallbackUrlInvalid")
|
||||||
assertThat(OAuthException.Cancelled("Cancelled").mapAuthenticationException())
|
assertThat(OAuthException.Cancelled("Cancelled").mapAuthenticationException())
|
||||||
.isException<AuthenticationException.Oidc>("Cancelled")
|
.isException<AuthenticationException.OAuth>("Cancelled")
|
||||||
assertThat(OAuthException.MetadataInvalid("MetadataInvalid").mapAuthenticationException())
|
assertThat(OAuthException.MetadataInvalid("MetadataInvalid").mapAuthenticationException())
|
||||||
.isException<AuthenticationException.Oidc>("MetadataInvalid")
|
.isException<AuthenticationException.OAuth>("MetadataInvalid")
|
||||||
assertThat(OAuthException.NotSupported("NotSupported").mapAuthenticationException())
|
assertThat(OAuthException.NotSupported("NotSupported").mapAuthenticationException())
|
||||||
.isException<AuthenticationException.Oidc>("NotSupported")
|
.isException<AuthenticationException.OAuth>("NotSupported")
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> ThrowableSubject.isException(message: String) {
|
private inline fun <reified T> ThrowableSubject.isException(message: String) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class HomeserverDetailsKtTest {
|
||||||
val homeserverLoginDetails = FakeFfiHomeserverLoginDetails(
|
val homeserverLoginDetails = FakeFfiHomeserverLoginDetails(
|
||||||
url = "https://example.org",
|
url = "https://example.org",
|
||||||
supportsPasswordLogin = true,
|
supportsPasswordLogin = true,
|
||||||
supportsOidcLogin = false
|
supportsOAuthLogin = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -31,7 +31,7 @@ class HomeserverDetailsKtTest {
|
||||||
MatrixHomeServerDetails(
|
MatrixHomeServerDetails(
|
||||||
url = "https://example.org",
|
url = "https://example.org",
|
||||||
supportsPasswordLogin = true,
|
supportsPasswordLogin = true,
|
||||||
supportsOidcLogin = false
|
supportsOAuthLogin = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,18 @@ 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.test.auth.FAKE_REDIRECT_URL
|
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.auth.FakeOAuthRedirectUrlProvider
|
||||||
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
|
||||||
|
|
||||||
class OidcConfigurationProviderTest {
|
class OAuthConfigurationProviderTest {
|
||||||
@Test
|
@Test
|
||||||
fun get() {
|
fun get() {
|
||||||
val result = OidcConfigurationProvider(
|
val result = OAuthConfigurationProvider(
|
||||||
buildMeta = aBuildMeta(
|
buildMeta = aBuildMeta(
|
||||||
applicationName = "myName",
|
applicationName = "myName",
|
||||||
),
|
),
|
||||||
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
|
oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(),
|
||||||
).get()
|
).get()
|
||||||
assertThat(result.clientName).isEqualTo("myName")
|
assertThat(result.clientName).isEqualTo("myName")
|
||||||
assertThat(result.redirectUri).isEqualTo(FAKE_REDIRECT_URL)
|
assertThat(result.redirectUri).isEqualTo(FAKE_REDIRECT_URL)
|
||||||
|
|
@ -18,8 +18,8 @@ import org.junit.Test
|
||||||
|
|
||||||
class RustHomeserverLoginCompatibilityCheckerTest {
|
class RustHomeserverLoginCompatibilityCheckerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `check - is valid if it supports OIDC login`() = runTest {
|
fun `check - is valid if it supports OAuth login`() = runTest {
|
||||||
val sut = createChecker { FakeFfiHomeserverLoginDetails(supportsOidcLogin = true) }
|
val sut = createChecker { FakeFfiHomeserverLoginDetails(supportsOAuthLogin = true) }
|
||||||
assertThat(sut.check("https://matrix.host.org").getOrNull()).isTrue()
|
assertThat(sut.check("https://matrix.host.org").getOrNull()).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiClient
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiClientBuilder
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiClientBuilder
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiHomeserverLoginDetails
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiHomeserverLoginDetails
|
||||||
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.auth.FakeOAuthRedirectUrlProvider
|
||||||
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.test.InMemorySessionStore
|
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||||
|
|
@ -64,9 +64,9 @@ class RustMatrixAuthenticationServiceTest {
|
||||||
sessionStore = sessionStore,
|
sessionStore = sessionStore,
|
||||||
rustMatrixClientFactory = rustMatrixClientFactory,
|
rustMatrixClientFactory = rustMatrixClientFactory,
|
||||||
passphraseGenerator = FakePassphraseGenerator(),
|
passphraseGenerator = FakePassphraseGenerator(),
|
||||||
oidcConfigurationProvider = OidcConfigurationProvider(
|
oAuthConfigurationProvider = OAuthConfigurationProvider(
|
||||||
buildMeta = aBuildMeta(),
|
buildMeta = aBuildMeta(),
|
||||||
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
|
oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class QrErrorMapperTest {
|
||||||
assertThat(QrErrorMapper.map(RustHumanQrLoginException.OtherDeviceNotSignedIn())).isEqualTo(QrLoginException.OtherDeviceNotSignedIn)
|
assertThat(QrErrorMapper.map(RustHumanQrLoginException.OtherDeviceNotSignedIn())).isEqualTo(QrLoginException.OtherDeviceNotSignedIn)
|
||||||
assertThat(QrErrorMapper.map(RustHumanQrLoginException.LinkingNotSupported())).isEqualTo(QrLoginException.LinkingNotSupported)
|
assertThat(QrErrorMapper.map(RustHumanQrLoginException.LinkingNotSupported())).isEqualTo(QrLoginException.LinkingNotSupported)
|
||||||
assertThat(QrErrorMapper.map(RustHumanQrLoginException.Unknown())).isEqualTo(QrLoginException.Unknown)
|
assertThat(QrErrorMapper.map(RustHumanQrLoginException.Unknown())).isEqualTo(QrLoginException.Unknown)
|
||||||
assertThat(QrErrorMapper.map(RustHumanQrLoginException.OAuthMetadataInvalid())).isEqualTo(QrLoginException.OidcMetadataInvalid)
|
assertThat(QrErrorMapper.map(RustHumanQrLoginException.OAuthMetadataInvalid())).isEqualTo(QrLoginException.OAuthMetadataInvalid)
|
||||||
assertThat(QrErrorMapper.map(RustHumanQrLoginException.SlidingSyncNotAvailable())).isEqualTo(QrLoginException.SlidingSyncNotAvailable)
|
assertThat(QrErrorMapper.map(RustHumanQrLoginException.SlidingSyncNotAvailable())).isEqualTo(QrLoginException.SlidingSyncNotAvailable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ import org.matrix.rustcomponents.sdk.NoHandle
|
||||||
class FakeFfiHomeserverLoginDetails(
|
class FakeFfiHomeserverLoginDetails(
|
||||||
private val url: String = "https://example.org",
|
private val url: String = "https://example.org",
|
||||||
private val supportsPasswordLogin: Boolean = false,
|
private val supportsPasswordLogin: Boolean = false,
|
||||||
private val supportsOidcLogin: Boolean = false,
|
private val supportsOAuthLogin: Boolean = false,
|
||||||
private val supportsSsoLogin: Boolean = false,
|
private val supportsSsoLogin: Boolean = false,
|
||||||
) : HomeserverLoginDetails(NoHandle) {
|
) : HomeserverLoginDetails(NoHandle) {
|
||||||
override fun url(): String = url
|
override fun url(): String = url
|
||||||
override fun supportsOauthLogin(): Boolean = supportsOidcLogin
|
override fun supportsOauthLogin(): Boolean = supportsOAuthLogin
|
||||||
override fun supportsPasswordLogin(): Boolean = supportsPasswordLogin
|
override fun supportsPasswordLogin(): Boolean = supportsPasswordLogin
|
||||||
override fun supportsSsoLogin(): Boolean = supportsSsoLogin
|
override fun supportsSsoLogin(): Boolean = supportsSsoLogin
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class SessionKtTest {
|
||||||
assertThat(result.refreshToken).isEqualTo("refreshToken")
|
assertThat(result.refreshToken).isEqualTo("refreshToken")
|
||||||
assertThat(result.homeserverUrl).isEqualTo(A_HOMESERVER_URL)
|
assertThat(result.homeserverUrl).isEqualTo(A_HOMESERVER_URL)
|
||||||
assertThat(result.isTokenValid).isTrue()
|
assertThat(result.isTokenValid).isTrue()
|
||||||
assertThat(result.oidcData).isNull()
|
assertThat(result.oAuthData).isNull()
|
||||||
assertThat(result.loginType).isEqualTo(LoginType.PASSWORD)
|
assertThat(result.loginType).isEqualTo(LoginType.PASSWORD)
|
||||||
assertThat(result.loginTimestamp).isNotNull()
|
assertThat(result.loginTimestamp).isNotNull()
|
||||||
assertThat(result.passphrase).isEqualTo(A_SECRET)
|
assertThat(result.passphrase).isEqualTo(A_SECRET)
|
||||||
|
|
@ -82,7 +82,7 @@ class SessionKtTest {
|
||||||
assertThat(result.refreshToken).isNull()
|
assertThat(result.refreshToken).isNull()
|
||||||
assertThat(result.homeserverUrl).isEqualTo(A_HOMESERVER_URL)
|
assertThat(result.homeserverUrl).isEqualTo(A_HOMESERVER_URL)
|
||||||
assertThat(result.isTokenValid).isTrue()
|
assertThat(result.isTokenValid).isTrue()
|
||||||
assertThat(result.oidcData).isNull()
|
assertThat(result.oAuthData).isNull()
|
||||||
assertThat(result.loginType).isEqualTo(LoginType.PASSWORD)
|
assertThat(result.loginType).isEqualTo(LoginType.PASSWORD)
|
||||||
assertThat(result.loginTimestamp).isNotNull()
|
assertThat(result.loginTimestamp).isNotNull()
|
||||||
assertThat(result.passphrase).isEqualTo(A_SECRET)
|
assertThat(result.passphrase).isEqualTo(A_SECRET)
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.oidc
|
package io.element.android.libraries.matrix.impl.oauth
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.test.A_DEVICE_ID
|
import io.element.android.libraries.matrix.test.A_DEVICE_ID
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManagementAction
|
import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManagementAction
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||||
import io.element.android.libraries.matrix.api.media.MediaPreviewService
|
import io.element.android.libraries.matrix.api.media.MediaPreviewService
|
||||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.auth.ElementClassicSession
|
import io.element.android.libraries.matrix.api.auth.ElementClassicSession
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcPrompt
|
import io.element.android.libraries.matrix.api.auth.OAuthPrompt
|
||||||
import io.element.android.libraries.matrix.api.auth.external.ExternalSession
|
import io.element.android.libraries.matrix.api.auth.external.ExternalSession
|
||||||
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
|
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
|
||||||
import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep
|
import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.simulateLongTask
|
import io.element.android.tests.testutils.simulateLongTask
|
||||||
|
|
||||||
val A_OIDC_DATA = OidcDetails(url = "a-url")
|
val AN_OAUTH_DATA = OAuthDetails(url = "a-url")
|
||||||
|
|
||||||
class FakeMatrixAuthenticationService(
|
class FakeMatrixAuthenticationService(
|
||||||
var matrixClientResult: ((SessionId) -> Result<MatrixClient>)? = null,
|
var matrixClientResult: ((SessionId) -> Result<MatrixClient>)? = null,
|
||||||
|
|
@ -37,8 +37,8 @@ class FakeMatrixAuthenticationService(
|
||||||
private val setElementClassicSessionResult: (ElementClassicSession?) -> Unit = { lambdaError() },
|
private val setElementClassicSessionResult: (ElementClassicSession?) -> Unit = { lambdaError() },
|
||||||
private val doSecretsContainBackupKeyResult: (UserId, String, String) -> Boolean = { _, _, _ -> lambdaError() },
|
private val doSecretsContainBackupKeyResult: (UserId, String, String) -> Boolean = { _, _, _ -> lambdaError() },
|
||||||
) : MatrixAuthenticationService {
|
) : MatrixAuthenticationService {
|
||||||
private var oidcError: Throwable? = null
|
private var oAuthError: Throwable? = null
|
||||||
private var oidcCancelError: Throwable? = null
|
private var oAuthCancelError: Throwable? = null
|
||||||
private var loginError: Throwable? = null
|
private var loginError: Throwable? = null
|
||||||
private var matrixClient: MatrixClient? = null
|
private var matrixClient: MatrixClient? = null
|
||||||
private var onAuthenticationListener: ((MatrixClient) -> Unit)? = null
|
private var onAuthenticationListener: ((MatrixClient) -> Unit)? = null
|
||||||
|
|
@ -70,18 +70,18 @@ class FakeMatrixAuthenticationService(
|
||||||
return importCreatedSessionLambda(externalSession)
|
return importCreatedSessionLambda(externalSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getOidcUrl(
|
override suspend fun getOAuthUrl(
|
||||||
prompt: OidcPrompt,
|
prompt: OAuthPrompt,
|
||||||
loginHint: String?,
|
loginHint: String?,
|
||||||
): Result<OidcDetails> = simulateLongTask {
|
): Result<OAuthDetails> = simulateLongTask {
|
||||||
oidcError?.let { Result.failure(it) } ?: Result.success(A_OIDC_DATA)
|
oAuthError?.let { Result.failure(it) } ?: Result.success(AN_OAUTH_DATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun cancelOidcLogin(): Result<Unit> {
|
override suspend fun cancelOAuthLogin(): Result<Unit> {
|
||||||
return oidcCancelError?.let { Result.failure(it) } ?: Result.success(Unit)
|
return oAuthCancelError?.let { Result.failure(it) } ?: Result.success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun loginWithOidc(callbackUrl: String): Result<SessionId> = simulateLongTask {
|
override suspend fun loginWithOAuth(callbackUrl: String): Result<SessionId> = simulateLongTask {
|
||||||
loginError?.let { Result.failure(it) } ?: run {
|
loginError?.let { Result.failure(it) } ?: run {
|
||||||
onAuthenticationListener?.invoke(matrixClient ?: FakeMatrixClient())
|
onAuthenticationListener?.invoke(matrixClient ?: FakeMatrixClient())
|
||||||
Result.success(A_USER_ID)
|
Result.success(A_USER_ID)
|
||||||
|
|
@ -97,12 +97,12 @@ class FakeMatrixAuthenticationService(
|
||||||
onAuthenticationListener = lambda
|
onAuthenticationListener = lambda
|
||||||
}
|
}
|
||||||
|
|
||||||
fun givenOidcError(throwable: Throwable?) {
|
fun givenOAuthError(throwable: Throwable?) {
|
||||||
oidcError = throwable
|
oAuthError = throwable
|
||||||
}
|
}
|
||||||
|
|
||||||
fun givenOidcCancelError(throwable: Throwable?) {
|
fun givenOAuthCancelError(throwable: Throwable?) {
|
||||||
oidcCancelError = throwable
|
oAuthCancelError = throwable
|
||||||
}
|
}
|
||||||
|
|
||||||
fun givenLoginError(throwable: Throwable?) {
|
fun givenLoginError(throwable: Throwable?) {
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.test.auth
|
package io.element.android.libraries.matrix.test.auth
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider
|
||||||
|
|
||||||
const val FAKE_REDIRECT_URL = "io.element.android:/"
|
const val FAKE_REDIRECT_URL = "io.element.android:/"
|
||||||
|
|
||||||
class FakeOidcRedirectUrlProvider(
|
class FakeOAuthRedirectUrlProvider(
|
||||||
private val provideResult: String = FAKE_REDIRECT_URL,
|
private val provideResult: String = FAKE_REDIRECT_URL,
|
||||||
) : OidcRedirectUrlProvider {
|
) : OAuthRedirectUrlProvider {
|
||||||
override fun provide() = provideResult
|
override fun provide() = provideResult
|
||||||
}
|
}
|
||||||
|
|
@ -14,9 +14,9 @@ import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||||
fun aMatrixHomeServerDetails(
|
fun aMatrixHomeServerDetails(
|
||||||
url: String = A_HOMESERVER_URL,
|
url: String = A_HOMESERVER_URL,
|
||||||
supportsPasswordLogin: Boolean = false,
|
supportsPasswordLogin: Boolean = false,
|
||||||
supportsOidcLogin: Boolean = false,
|
supportsOAuthLogin: Boolean = false,
|
||||||
) = MatrixHomeServerDetails(
|
) = MatrixHomeServerDetails(
|
||||||
url = url,
|
url = url,
|
||||||
supportsPasswordLogin = supportsPasswordLogin,
|
supportsPasswordLogin = supportsPasswordLogin,
|
||||||
supportsOidcLogin = supportsOidcLogin,
|
supportsOAuthLogin = supportsOAuthLogin,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,16 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.test.encryption
|
package io.element.android.libraries.matrix.test.encryption
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityOAuthResetHandle
|
||||||
import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle
|
import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle
|
||||||
|
|
||||||
class FakeIdentityOidcResetHandle(
|
class FakeIdentityOAuthResetHandle(
|
||||||
override val url: String = "",
|
override val url: String = "",
|
||||||
var resetOidcLambda: () -> Result<Unit> = { error("Not implemented") },
|
var resetOAuthLambda: () -> Result<Unit> = { error("Not implemented") },
|
||||||
var cancelLambda: () -> Unit = { error("Not implemented") },
|
var cancelLambda: () -> Unit = { error("Not implemented") },
|
||||||
) : IdentityOidcResetHandle {
|
) : IdentityOAuthResetHandle {
|
||||||
override suspend fun resetOidc(): Result<Unit> {
|
override suspend fun resetOAuth(): Result<Unit> {
|
||||||
return resetOidcLambda()
|
return resetOAuthLambda()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun cancel() {
|
override suspend fun cancel() {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.libraries.oidc.api"
|
namespace = "io.element.android.libraries.oauth.api"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.api
|
package io.element.android.libraries.oauth.api
|
||||||
|
|
||||||
sealed interface OidcAction {
|
sealed interface OAuthAction {
|
||||||
data class GoBack(val toUnblock: Boolean = false) : OidcAction
|
data class GoBack(val toUnblock: Boolean = false) : OAuthAction
|
||||||
data class Success(val url: String) : OidcAction
|
data class Success(val url: String) : OAuthAction
|
||||||
}
|
}
|
||||||
|
|
@ -6,12 +6,12 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.api
|
package io.element.android.libraries.oauth.api
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
import kotlinx.coroutines.flow.FlowCollector
|
||||||
|
|
||||||
interface OidcActionFlow {
|
interface OAuthActionFlow {
|
||||||
fun post(oidcAction: OidcAction)
|
fun post(oAuthAction: OAuthAction)
|
||||||
suspend fun collect(collector: FlowCollector<OidcAction?>)
|
suspend fun collect(collector: FlowCollector<OAuthAction?>)
|
||||||
fun reset()
|
fun reset()
|
||||||
}
|
}
|
||||||
|
|
@ -6,10 +6,10 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.api
|
package io.element.android.libraries.oauth.api
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
|
||||||
interface OidcIntentResolver {
|
interface OAuthIntentResolver {
|
||||||
fun resolve(intent: Intent): OidcAction?
|
fun resolve(intent: Intent): OAuthAction?
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.libraries.oidc.impl"
|
namespace = "io.element.android.libraries.oauth.impl"
|
||||||
|
|
||||||
testOptions {
|
testOptions {
|
||||||
unitTests {
|
unitTests {
|
||||||
|
|
@ -39,7 +39,7 @@ dependencies {
|
||||||
implementation(platform(libs.network.retrofit.bom))
|
implementation(platform(libs.network.retrofit.bom))
|
||||||
implementation(libs.network.retrofit)
|
implementation(libs.network.retrofit)
|
||||||
implementation(libs.serialization.json)
|
implementation(libs.serialization.json)
|
||||||
api(projects.libraries.oidc.api)
|
api(projects.libraries.oauth.api)
|
||||||
|
|
||||||
testCommonDependencies(libs)
|
testCommonDependencies(libs)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
|
@ -6,26 +6,26 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.impl
|
package io.element.android.libraries.oauth.impl
|
||||||
|
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import dev.zacsweers.metro.SingleIn
|
import dev.zacsweers.metro.SingleIn
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
import kotlinx.coroutines.flow.FlowCollector
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
@SingleIn(AppScope::class)
|
@SingleIn(AppScope::class)
|
||||||
class DefaultOidcActionFlow : OidcActionFlow {
|
class DefaultOAuthActionFlow : OAuthActionFlow {
|
||||||
private val mutableStateFlow = MutableStateFlow<OidcAction?>(null)
|
private val mutableStateFlow = MutableStateFlow<OAuthAction?>(null)
|
||||||
|
|
||||||
override fun post(oidcAction: OidcAction) {
|
override fun post(oAuthAction: OAuthAction) {
|
||||||
mutableStateFlow.value = oidcAction
|
mutableStateFlow.value = oAuthAction
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun collect(collector: FlowCollector<OidcAction?>) {
|
override suspend fun collect(collector: FlowCollector<OAuthAction?>) {
|
||||||
mutableStateFlow.collect(collector)
|
mutableStateFlow.collect(collector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,37 +6,37 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.impl
|
package io.element.android.libraries.oauth.impl
|
||||||
|
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
|
|
||||||
fun interface OidcUrlParser {
|
fun interface OAuthUrlParser {
|
||||||
fun parse(url: String): OidcAction?
|
fun parse(url: String): OAuthAction?
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple parser for oidc url interception.
|
* Simple parser for OAuth url interception.
|
||||||
* TODO Find documentation about the format.
|
* TODO Find documentation about the format.
|
||||||
*/
|
*/
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class DefaultOidcUrlParser(
|
class DefaultOAuthUrlParser(
|
||||||
private val oidcRedirectUrlProvider: OidcRedirectUrlProvider,
|
private val oAuthRedirectUrlProvider: OAuthRedirectUrlProvider,
|
||||||
) : OidcUrlParser {
|
) : OAuthUrlParser {
|
||||||
/**
|
/**
|
||||||
* Return a OidcAction, or null if the url is not a OidcUrl.
|
* Return a [OAuthAction], or null if the url is not an OAuth url.
|
||||||
* Note:
|
* Note:
|
||||||
* When user press button "Cancel", we get the url:
|
* When user press button "Cancel", we get the url:
|
||||||
* `io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO`
|
* `io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO`
|
||||||
* On success, we get:
|
* On success, we get:
|
||||||
* `io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB`
|
* `io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB`
|
||||||
*/
|
*/
|
||||||
override fun parse(url: String): OidcAction? {
|
override fun parse(url: String): OAuthAction? {
|
||||||
if (url.startsWith(oidcRedirectUrlProvider.provide()).not()) return null
|
if (url.startsWith(oAuthRedirectUrlProvider.provide()).not()) return null
|
||||||
if (url.contains("error=access_denied")) return OidcAction.GoBack()
|
if (url.contains("error=access_denied")) return OAuthAction.GoBack()
|
||||||
if (url.contains("code=")) return OidcAction.Success(url)
|
if (url.contains("code=")) return OAuthAction.Success(url)
|
||||||
|
|
||||||
// Other case not supported, let's crash the app for now
|
// Other case not supported, let's crash the app for now
|
||||||
error("Not supported: $url")
|
error("Not supported: $url")
|
||||||
|
|
@ -1,34 +1,33 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2025 Element Creations Ltd.
|
* Copyright (c) 2026 Element Creations Ltd.
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.impl
|
package io.element.android.libraries.oauth.impl
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class DefaultOidcActionFlowTest {
|
class DefaultOAuthActionFlowTest {
|
||||||
@Test
|
@Test
|
||||||
fun `collect gets all the posted events`() = runTest {
|
fun `collect gets all the posted events`() = runTest {
|
||||||
val data = mutableListOf<OidcAction?>()
|
val data = mutableListOf<OAuthAction?>()
|
||||||
val sut = DefaultOidcActionFlow()
|
val sut = DefaultOAuthActionFlow()
|
||||||
backgroundScope.launch {
|
backgroundScope.launch {
|
||||||
sut.collect { action ->
|
sut.collect { action ->
|
||||||
data.add(action)
|
data.add(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sut.post(OidcAction.GoBack())
|
sut.post(OAuthAction.GoBack())
|
||||||
delay(1)
|
delay(1)
|
||||||
sut.reset()
|
sut.reset()
|
||||||
delay(1)
|
delay(1)
|
||||||
assertThat(data).containsExactly(OidcAction.GoBack(), null)
|
assertThat(data).containsExactly(OAuthAction.GoBack(), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2025 Element Creations Ltd.
|
* Copyright (c) 2026 Element Creations Ltd.
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.impl
|
package io.element.android.libraries.oauth.impl
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import org.junit.Assert.assertThrows
|
import org.junit.Assert.assertThrows
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
@ -21,36 +20,36 @@ import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.RuntimeEnvironment
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
class DefaultOidcIntentResolverTest {
|
class DefaultOAuthIntentResolverTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test resolve oidc go back`() {
|
fun `test resolve OAuth go back`() {
|
||||||
val sut = createDefaultOidcIntentResolver()
|
val sut = createDefaultOAuthIntentResolver()
|
||||||
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.android:/?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(OidcAction.GoBack())
|
assertThat(result).isEqualTo(OAuthAction.GoBack())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test resolve oidc success`() {
|
fun `test resolve OAuth success`() {
|
||||||
val sut = createDefaultOidcIntentResolver()
|
val sut = createDefaultOAuthIntentResolver()
|
||||||
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.android:/?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(
|
||||||
OidcAction.Success(
|
OAuthAction.Success(
|
||||||
url = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
|
url = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test resolve oidc invalid`() {
|
fun `test resolve OAuth invalid`() {
|
||||||
val sut = createDefaultOidcIntentResolver()
|
val sut = createDefaultOAuthIntentResolver()
|
||||||
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.android:/invalid".toUri()
|
data = "io.element.android:/invalid".toUri()
|
||||||
|
|
@ -60,10 +59,10 @@ class DefaultOidcIntentResolverTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDefaultOidcIntentResolver(): DefaultOidcIntentResolver {
|
private fun createDefaultOAuthIntentResolver(): DefaultOAuthIntentResolver {
|
||||||
return DefaultOidcIntentResolver(
|
return DefaultOAuthIntentResolver(
|
||||||
oidcUrlParser = DefaultOidcUrlParser(
|
oAuthUrlParser = DefaultOAuthUrlParser(
|
||||||
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
|
oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,59 +1,58 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2025 Element Creations Ltd.
|
* Copyright (c) 2026 Element Creations Ltd.
|
||||||
* Copyright 2023-2025 New Vector Ltd.
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.impl
|
package io.element.android.libraries.oauth.impl
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
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.FAKE_REDIRECT_URL
|
||||||
import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class DefaultOidcUrlParserTest {
|
class DefaultOAuthUrlParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test empty url`() {
|
fun `test empty url`() {
|
||||||
val sut = createDefaultOidcUrlParser()
|
val sut = createDefaultOAuthUrlParser()
|
||||||
assertThat(sut.parse("")).isNull()
|
assertThat(sut.parse("")).isNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test regular url`() {
|
fun `test regular url`() {
|
||||||
val sut = createDefaultOidcUrlParser()
|
val sut = createDefaultOAuthUrlParser()
|
||||||
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 = createDefaultOidcUrlParser()
|
val sut = createDefaultOAuthUrlParser()
|
||||||
val aCancelUrl = "$FAKE_REDIRECT_URL?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(OAuthAction.GoBack())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test success url`() {
|
fun `test success url`() {
|
||||||
val sut = createDefaultOidcUrlParser()
|
val sut = createDefaultOAuthUrlParser()
|
||||||
val aSuccessUrl = "$FAKE_REDIRECT_URL?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(OAuthAction.Success(aSuccessUrl))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test unknown url`() {
|
fun `test unknown url`() {
|
||||||
val sut = createDefaultOidcUrlParser()
|
val sut = createDefaultOAuthUrlParser()
|
||||||
val anUnknownUrl = "$FAKE_REDIRECT_URL?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 {
|
private fun createDefaultOAuthUrlParser(): DefaultOAuthUrlParser {
|
||||||
return DefaultOidcUrlParser(
|
return DefaultOAuthUrlParser(
|
||||||
oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(),
|
oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,11 +11,11 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.libraries.oidc.test"
|
namespace = "io.element.android.libraries.oauth.test"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.coroutines.core)
|
implementation(libs.coroutines.core)
|
||||||
api(projects.libraries.oidc.api)
|
api(projects.libraries.oauth.api)
|
||||||
implementation(projects.tests.testutils)
|
implementation(projects.tests.testutils)
|
||||||
}
|
}
|
||||||
|
|
@ -6,17 +6,17 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.oidc.test
|
package io.element.android.libraries.oauth.test
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcIntentResolver
|
import io.element.android.libraries.oauth.api.OAuthIntentResolver
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
|
||||||
class FakeOidcIntentResolver(
|
class FakeOAuthIntentResolver(
|
||||||
private val resolveResult: (Intent) -> OidcAction? = { lambdaError() }
|
private val resolveResult: (Intent) -> OAuthAction? = { lambdaError() }
|
||||||
) : OidcIntentResolver {
|
) : OAuthIntentResolver {
|
||||||
override fun resolve(intent: Intent): OidcAction? {
|
override fun resolve(intent: Intent): OAuthAction? {
|
||||||
return resolveResult(intent)
|
return resolveResult(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* 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.oauth.test.customtab
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is actually a copy of DefaultOAuthActionFlow.
|
||||||
|
*/
|
||||||
|
class FakeOAuthActionFlow : 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.oidc.impl
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import dev.zacsweers.metro.AppScope
|
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
|
||||||
import io.element.android.libraries.oidc.api.OidcIntentResolver
|
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
|
||||||
class DefaultOidcIntentResolver(
|
|
||||||
private val oidcUrlParser: OidcUrlParser,
|
|
||||||
) : OidcIntentResolver {
|
|
||||||
override fun resolve(intent: Intent): OidcAction? {
|
|
||||||
return oidcUrlParser.parse(intent.dataString.orEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2025 Element Creations Ltd.
|
|
||||||
* 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.oidc.test.customtab
|
|
||||||
|
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is actually a copy of DefaultOidcActionFlow.
|
|
||||||
*/
|
|
||||||
class FakeOidcActionFlow : OidcActionFlow {
|
|
||||||
private val mutableStateFlow = MutableStateFlow<OidcAction?>(null)
|
|
||||||
|
|
||||||
override fun post(oidcAction: OidcAction) {
|
|
||||||
mutableStateFlow.value = oidcAction
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun collect(collector: FlowCollector<OidcAction?>) {
|
|
||||||
mutableStateFlow.collect(collector)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
mutableStateFlow.value = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -24,8 +24,8 @@ data class SessionData(
|
||||||
val refreshToken: String?,
|
val refreshToken: String?,
|
||||||
/** The homeserver URL of the session. */
|
/** The homeserver URL of the session. */
|
||||||
val homeserverUrl: String,
|
val homeserverUrl: String,
|
||||||
/** The Open ID Connect info for this session, if any. */
|
/** The Open Authorization info for this session, if any. */
|
||||||
val oidcData: String?,
|
val oAuthData: String?,
|
||||||
/** The timestamp of the last login. May be `null` in very old sessions. */
|
/** The timestamp of the last login. May be `null` in very old sessions. */
|
||||||
val loginTimestamp: Date?,
|
val loginTimestamp: Date?,
|
||||||
/** Whether the [accessToken] is valid or not. */
|
/** Whether the [accessToken] is valid or not. */
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ internal fun SessionData.toDbModel(): DbSessionData {
|
||||||
accessToken = accessToken,
|
accessToken = accessToken,
|
||||||
refreshToken = refreshToken,
|
refreshToken = refreshToken,
|
||||||
homeserverUrl = homeserverUrl,
|
homeserverUrl = homeserverUrl,
|
||||||
oidcData = oidcData,
|
oidcData = oAuthData,
|
||||||
loginTimestamp = loginTimestamp?.time,
|
loginTimestamp = loginTimestamp?.time,
|
||||||
isTokenValid = if (isTokenValid) 1L else 0L,
|
isTokenValid = if (isTokenValid) 1L else 0L,
|
||||||
loginType = loginType.name,
|
loginType = loginType.name,
|
||||||
|
|
@ -41,7 +41,7 @@ internal fun DbSessionData.toApiModel(): SessionData {
|
||||||
accessToken = accessToken,
|
accessToken = accessToken,
|
||||||
refreshToken = refreshToken,
|
refreshToken = refreshToken,
|
||||||
homeserverUrl = homeserverUrl,
|
homeserverUrl = homeserverUrl,
|
||||||
oidcData = oidcData,
|
oAuthData = oidcData,
|
||||||
loginTimestamp = loginTimestamp?.let { Date(it) },
|
loginTimestamp = loginTimestamp?.let { Date(it) },
|
||||||
isTokenValid = isTokenValid == 1L,
|
isTokenValid = isTokenValid == 1L,
|
||||||
loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name),
|
loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name),
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ fun aSessionData(
|
||||||
accessToken = accessToken,
|
accessToken = accessToken,
|
||||||
refreshToken = refreshToken,
|
refreshToken = refreshToken,
|
||||||
homeserverUrl = "aHomeserverUrl",
|
homeserverUrl = "aHomeserverUrl",
|
||||||
oidcData = null,
|
oAuthData = null,
|
||||||
loginTimestamp = null,
|
loginTimestamp = null,
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = LoginType.UNKNOWN,
|
loginType = LoginType.UNKNOWN,
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ fun DependencyHandlerScope.allLibrariesImpl() {
|
||||||
implementation(project(":libraries:troubleshoot:impl"))
|
implementation(project(":libraries:troubleshoot:impl"))
|
||||||
implementation(project(":libraries:fullscreenintent:impl"))
|
implementation(project(":libraries:fullscreenintent:impl"))
|
||||||
implementation(project(":libraries:wellknown:impl"))
|
implementation(project(":libraries:wellknown:impl"))
|
||||||
implementation(project(":libraries:oidc:impl"))
|
implementation(project(":libraries:oauth:impl"))
|
||||||
implementation(project(":libraries:workmanager:impl"))
|
implementation(project(":libraries:workmanager:impl"))
|
||||||
implementation(project(":libraries:recentemojis:impl"))
|
implementation(project(":libraries:recentemojis:impl"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue