Merge pull request #1128 from vector-im/feature/bma/cleanupOidc
Cleanup OIDC
This commit is contained in:
commit
011fa6af67
5 changed files with 40 additions and 10 deletions
|
|
@ -22,7 +22,9 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.bumble.appyx.core.composable.Children
|
import com.bumble.appyx.core.composable.Children
|
||||||
|
import com.bumble.appyx.core.lifecycle.subscribe
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.plugin.Plugin
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
|
@ -33,6 +35,8 @@ import com.bumble.appyx.navmodel.backstack.operation.singleTop
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.features.login.api.oidc.OidcAction
|
||||||
|
import io.element.android.features.login.api.oidc.OidcActionFlow
|
||||||
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.oidc.CustomTabAvailabilityChecker
|
import io.element.android.features.login.impl.oidc.CustomTabAvailabilityChecker
|
||||||
import io.element.android.features.login.impl.oidc.customtab.CustomTabHandler
|
import io.element.android.features.login.impl.oidc.customtab.CustomTabHandler
|
||||||
|
|
@ -51,6 +55,8 @@ import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
import io.element.android.libraries.matrix.api.auth.OidcDetails
|
||||||
import io.element.android.libraries.theme.ElementTheme
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
|
|
@ -61,6 +67,7 @@ class LoginFlowNode @AssistedInject constructor(
|
||||||
private val customTabHandler: CustomTabHandler,
|
private val customTabHandler: CustomTabHandler,
|
||||||
private val accountProviderDataSource: AccountProviderDataSource,
|
private val accountProviderDataSource: AccountProviderDataSource,
|
||||||
private val defaultLoginUserStory: DefaultLoginUserStory,
|
private val defaultLoginUserStory: DefaultLoginUserStory,
|
||||||
|
private val oidcActionFlow: OidcActionFlow,
|
||||||
) : BackstackNode<LoginFlowNode.NavTarget>(
|
) : BackstackNode<LoginFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.ConfirmAccountProvider,
|
initialElement = NavTarget.ConfirmAccountProvider,
|
||||||
|
|
@ -78,9 +85,26 @@ class LoginFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
private val inputs: Inputs = inputs()
|
private val inputs: Inputs = inputs()
|
||||||
|
|
||||||
|
private var customChromeTabStarted = false
|
||||||
|
|
||||||
override fun onBuilt() {
|
override fun onBuilt() {
|
||||||
super.onBuilt()
|
super.onBuilt()
|
||||||
defaultLoginUserStory.setLoginFlowIsDone(false)
|
defaultLoginUserStory.setLoginFlowIsDone(false)
|
||||||
|
lifecycle.subscribe(
|
||||||
|
onResume = {
|
||||||
|
if (customChromeTabStarted) {
|
||||||
|
customChromeTabStarted = false
|
||||||
|
// Workaround to detect that the Custom Chrome Tab has been closed
|
||||||
|
// If there is no coming OidcAction (that would end this Node),
|
||||||
|
// consider that the user has cancelled the login
|
||||||
|
// by pressing back or by closing the Custom Chrome Tab.
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(5000)
|
||||||
|
oidcActionFlow.post(OidcAction.GoBack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface NavTarget : Parcelable {
|
sealed interface NavTarget : Parcelable {
|
||||||
|
|
@ -113,7 +137,10 @@ class LoginFlowNode @AssistedInject constructor(
|
||||||
override fun onOidcDetails(oidcDetails: OidcDetails) {
|
override fun onOidcDetails(oidcDetails: OidcDetails) {
|
||||||
if (customTabAvailabilityChecker.supportCustomTab()) {
|
if (customTabAvailabilityChecker.supportCustomTab()) {
|
||||||
// In this case open a Chrome Custom tab
|
// In this case open a Chrome Custom tab
|
||||||
activity?.let { customTabHandler.open(it, darkTheme, oidcDetails.url) }
|
activity?.let {
|
||||||
|
customChromeTabStarted = true
|
||||||
|
customTabHandler.open(it, darkTheme, oidcDetails.url)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fallback to WebView mode
|
// Fallback to WebView mode
|
||||||
backstack.push(NavTarget.OidcView(oidcDetails))
|
backstack.push(NavTarget.OidcView(oidcDetails))
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,9 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
launch {
|
defaultOidcActionFlow.collect { oidcAction ->
|
||||||
defaultOidcActionFlow.collect {
|
if (oidcAction != null) {
|
||||||
onOidcAction(it, loginFlowAction)
|
onOidcAction(oidcAction, loginFlowAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,10 +113,9 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onOidcAction(
|
private suspend fun onOidcAction(
|
||||||
oidcAction: OidcAction?,
|
oidcAction: OidcAction,
|
||||||
loginFlowAction: MutableState<Async<LoginFlow>>,
|
loginFlowAction: MutableState<Async<LoginFlow>>,
|
||||||
) {
|
) {
|
||||||
oidcAction ?: return
|
|
||||||
loginFlowAction.value = Async.Loading()
|
loginFlowAction.value = Async.Loading()
|
||||||
when (oidcAction) {
|
when (oidcAction) {
|
||||||
OidcAction.GoBack -> {
|
OidcAction.GoBack -> {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
@Composable
|
@Composable
|
||||||
fun LogoutPreferenceView(
|
fun LogoutPreferenceView(
|
||||||
state: LogoutPreferenceState,
|
state: LogoutPreferenceState,
|
||||||
onSuccessLogout: (String?) -> Unit = {}
|
onSuccessLogout: (logoutUrlResult: String?) -> Unit
|
||||||
) {
|
) {
|
||||||
val eventSink = state.eventSink
|
val eventSink = state.eventSink
|
||||||
if (state.logoutAction is Async.Success) {
|
if (state.logoutAction is Async.Success) {
|
||||||
|
|
@ -96,5 +96,8 @@ internal fun LogoutPreferenceViewDarkPreview() = ElementPreviewDark { ContentToP
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ContentToPreview() {
|
private fun ContentToPreview() {
|
||||||
LogoutPreferenceView(aLogoutPreferenceState())
|
LogoutPreferenceView(
|
||||||
|
aLogoutPreferenceState(),
|
||||||
|
onSuccessLogout = {}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ fun PreferencesRootView(
|
||||||
onOpenRageShake: () -> Unit,
|
onOpenRageShake: () -> Unit,
|
||||||
onOpenAbout: () -> Unit,
|
onOpenAbout: () -> Unit,
|
||||||
onOpenDeveloperSettings: () -> Unit,
|
onOpenDeveloperSettings: () -> Unit,
|
||||||
onSuccessLogout: (String?) -> Unit,
|
onSuccessLogout: (logoutUrlResult: String?) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
|
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ interface MatrixClient : Closeable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout the user.
|
* Logout the user.
|
||||||
* Returns an optional URL. When the URL is there, it should be presented to the user after logout for RP initiated logout on their account page.
|
* Returns an optional URL. When the URL is there, it should be presented to the user after logout for
|
||||||
|
* Relying Party (RP) initiated logout on their account page.
|
||||||
*/
|
*/
|
||||||
suspend fun logout(): String?
|
suspend fun logout(): String?
|
||||||
suspend fun loadUserDisplayName(): Result<String>
|
suspend fun loadUserDisplayName(): Result<String>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue