Benoit Marty
1 year ago
committed by
Benoit Marty
26 changed files with 789 additions and 44 deletions
@ -0,0 +1,45 @@ |
|||||||
|
[ios implementation](https://github.com/vector-im/element-x-ios/compare/develop...doug/oidc-temp) |
||||||
|
|
||||||
|
Rust sdk branch: https://github.com/matrix-org/matrix-rust-sdk/tree/oidc-ffi |
||||||
|
|
||||||
|
Figma https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?node-id=133-5426&t=yQXKeANatk6keoZF-0 |
||||||
|
|
||||||
|
Server list: https://github.com/vector-im/oidc-playground |
||||||
|
|
||||||
|
Metadata iOS: (from https://github.com/vector-im/element-x-ios/blob/5f9d07377cebc4f21d9668b1a25f6e3bb22f64a1/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift#L28) |
||||||
|
|
||||||
|
clientName: InfoPlistReader.main.bundleDisplayName, |
||||||
|
redirectUri: "io.element:/callback", |
||||||
|
clientUri: "https://element.io", |
||||||
|
tosUri: "https://element.io/user-terms-of-service", |
||||||
|
policyUri: "https://element.io/privacy" |
||||||
|
|
||||||
|
|
||||||
|
Android: |
||||||
|
clientName = "Element", |
||||||
|
redirectUri = "io.element:/callback", |
||||||
|
clientUri = "https://element.io", |
||||||
|
tosUri = "https://element.io/user-terms-of-service", |
||||||
|
policyUri = "https://element.io/privacy" |
||||||
|
|
||||||
|
|
||||||
|
Example of OidcData (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 |
||||||
|
|
||||||
|
Formatted 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 |
||||||
|
|
||||||
|
state: ex6mNJVFZ5jn9wL8 |
||||||
|
|
||||||
|
|
||||||
|
Oidc 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 |
@ -0,0 +1,23 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
sealed interface OidcEvents { |
||||||
|
object Cancel : OidcEvents |
||||||
|
data class OidcActionEvent(val oidcAction: OidcAction): OidcEvents |
||||||
|
object ClearError : OidcEvents |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import com.bumble.appyx.core.modality.BuildContext |
||||||
|
import com.bumble.appyx.core.node.Node |
||||||
|
import com.bumble.appyx.core.plugin.Plugin |
||||||
|
import dagger.assisted.Assisted |
||||||
|
import dagger.assisted.AssistedInject |
||||||
|
import io.element.android.anvilannotations.ContributesNode |
||||||
|
import io.element.android.libraries.architecture.NodeInputs |
||||||
|
import io.element.android.libraries.architecture.inputs |
||||||
|
import io.element.android.libraries.di.AppScope |
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcDetails |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO Transmit back press to the webview |
||||||
|
*/ |
||||||
|
@ContributesNode(AppScope::class) |
||||||
|
class OidcNode @AssistedInject constructor( |
||||||
|
@Assisted buildContext: BuildContext, |
||||||
|
@Assisted plugins: List<Plugin>, |
||||||
|
presenterFactory: OidcPresenter.Factory, |
||||||
|
) : Node(buildContext, plugins = plugins) { |
||||||
|
|
||||||
|
data class Inputs( |
||||||
|
val oidcDetails: OidcDetails, |
||||||
|
) : NodeInputs |
||||||
|
|
||||||
|
private val inputs: Inputs = inputs() |
||||||
|
private val presenter = presenterFactory.create(inputs.oidcDetails) |
||||||
|
|
||||||
|
@Composable |
||||||
|
override fun View(modifier: Modifier) { |
||||||
|
val state = presenter.present() |
||||||
|
OidcView( |
||||||
|
state = state, |
||||||
|
modifier = modifier, |
||||||
|
onNavigateBack = ::navigateUp, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.runtime.getValue |
||||||
|
import androidx.compose.runtime.mutableStateOf |
||||||
|
import androidx.compose.runtime.remember |
||||||
|
import androidx.compose.runtime.rememberCoroutineScope |
||||||
|
import androidx.compose.runtime.setValue |
||||||
|
import dagger.assisted.Assisted |
||||||
|
import dagger.assisted.AssistedFactory |
||||||
|
import dagger.assisted.AssistedInject |
||||||
|
import io.element.android.libraries.architecture.Async |
||||||
|
import io.element.android.libraries.architecture.Presenter |
||||||
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService |
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcDetails |
||||||
|
import kotlinx.coroutines.launch |
||||||
|
|
||||||
|
class OidcPresenter @AssistedInject constructor( |
||||||
|
@Assisted private val oidcDetails: OidcDetails, |
||||||
|
private val authenticationService: MatrixAuthenticationService, |
||||||
|
) : Presenter<OidcState> { |
||||||
|
|
||||||
|
@AssistedFactory |
||||||
|
interface Factory { |
||||||
|
fun create(oidcDetails: OidcDetails): OidcPresenter |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
override fun present(): OidcState { |
||||||
|
var requestState: Async<Unit> by remember { |
||||||
|
mutableStateOf(Async.Uninitialized) |
||||||
|
} |
||||||
|
val localCoroutineScope = rememberCoroutineScope() |
||||||
|
|
||||||
|
fun handleCancel() { |
||||||
|
requestState = Async.Loading() |
||||||
|
localCoroutineScope.launch { |
||||||
|
requestState = try { |
||||||
|
authenticationService.cancelOidcLogin() |
||||||
|
// Then go back |
||||||
|
Async.Success(Unit) |
||||||
|
} catch (throwable: Throwable) { |
||||||
|
Async.Failure(throwable) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun handleSuccess(url: String) { |
||||||
|
requestState = Async.Loading() |
||||||
|
localCoroutineScope.launch { |
||||||
|
try { |
||||||
|
authenticationService.loginWithOidc(url) |
||||||
|
// Then the node tree will be updated, there is nothing to do |
||||||
|
} catch (throwable: Throwable) { |
||||||
|
requestState = Async.Failure(throwable) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun handleAction(action: OidcAction) { |
||||||
|
when (action) { |
||||||
|
OidcAction.GoBack -> handleCancel() |
||||||
|
is OidcAction.Success -> handleSuccess(action.url) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun handleEvents(event: OidcEvents) { |
||||||
|
when (event) { |
||||||
|
OidcEvents.Cancel -> handleCancel() |
||||||
|
is OidcEvents.OidcActionEvent -> handleAction(event.oidcAction) |
||||||
|
OidcEvents.ClearError -> requestState = Async.Uninitialized |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return OidcState( |
||||||
|
oidcDetails = oidcDetails, |
||||||
|
requestState = requestState, |
||||||
|
eventSink = ::handleEvents |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import io.element.android.libraries.architecture.Async |
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcDetails |
||||||
|
|
||||||
|
data class OidcState( |
||||||
|
val oidcDetails: OidcDetails, |
||||||
|
val requestState: Async<Unit>, |
||||||
|
val eventSink: (OidcEvents) -> Unit |
||||||
|
) |
@ -0,0 +1,39 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider |
||||||
|
import io.element.android.libraries.architecture.Async |
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcDetails |
||||||
|
|
||||||
|
open class OidcStateProvider : PreviewParameterProvider<OidcState> { |
||||||
|
override val values: Sequence<OidcState> |
||||||
|
get() = sequenceOf( |
||||||
|
aOidcState(), |
||||||
|
aOidcState().copy(requestState = Async.Loading()), |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
fun aOidcState() = OidcState( |
||||||
|
oidcDetails = aOidcDetails(), |
||||||
|
requestState = Async.Uninitialized, |
||||||
|
eventSink = {} |
||||||
|
) |
||||||
|
|
||||||
|
fun aOidcDetails() = OidcDetails( |
||||||
|
url = "aUrl", |
||||||
|
) |
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcConfig |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple parser for oidc url interception. |
||||||
|
* TODO Find documentation about the format. |
||||||
|
*/ |
||||||
|
class OidcUrlParser { |
||||||
|
|
||||||
|
// When user press button "Cancel", we get the url: |
||||||
|
// `io.element:/callback?error=access_denied&state=IFF1UETGye2ZA8pO` |
||||||
|
// On success, we get: |
||||||
|
// `io.element:/callback?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB` |
||||||
|
/** |
||||||
|
* Return a OidcAction, or null if the url is not a OidcUrl |
||||||
|
*/ |
||||||
|
fun parse(url: String): OidcAction? { |
||||||
|
if (!url.startsWith(OidcConfig.redirectUri)) return null |
||||||
|
if (url.contains("error=access_denied")) return OidcAction.GoBack |
||||||
|
if (url.contains("code=")) return OidcAction.Success(url) |
||||||
|
|
||||||
|
// Other case not supported, let's crash the app for now |
||||||
|
error("Not supported: $url") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed interface OidcAction { |
||||||
|
object GoBack : OidcAction |
||||||
|
data class Success(val url: String) : OidcAction |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import android.webkit.WebView |
||||||
|
import androidx.activity.compose.BackHandler |
||||||
|
import androidx.compose.foundation.layout.Box |
||||||
|
import androidx.compose.foundation.layout.statusBarsPadding |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.runtime.remember |
||||||
|
import androidx.compose.ui.Alignment |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.tooling.preview.Preview |
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter |
||||||
|
import androidx.compose.ui.viewinterop.AndroidView |
||||||
|
import io.element.android.libraries.architecture.Async |
||||||
|
import io.element.android.libraries.core.bool.orFalse |
||||||
|
import io.element.android.libraries.core.bool.orTrue |
||||||
|
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog |
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark |
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight |
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun OidcView( |
||||||
|
state: OidcState, |
||||||
|
onNavigateBack: () -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
) { |
||||||
|
val oidcUrlParser = remember { OidcUrlParser() } |
||||||
|
var webView: WebView? = null |
||||||
|
fun shouldOverrideUrl(url: String): Boolean { |
||||||
|
val action = oidcUrlParser.parse(url) |
||||||
|
if (action != null) { |
||||||
|
state.eventSink.invoke(OidcEvents.OidcActionEvent(action)) |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
val oidcWebViewClient = remember { |
||||||
|
OidcWebViewClient(eventListener = object : WebViewEventListener { |
||||||
|
override fun shouldOverrideUrlLoading(url: String): Boolean { |
||||||
|
return shouldOverrideUrl(url) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
BackHandler { |
||||||
|
if (webView?.canGoBack().orFalse()) { |
||||||
|
webView?.goBack() |
||||||
|
} else { |
||||||
|
// To properly cancel Oidc login |
||||||
|
state.eventSink.invoke(OidcEvents.Cancel) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Box(modifier = modifier.statusBarsPadding()) { |
||||||
|
AndroidView( |
||||||
|
modifier = modifier |
||||||
|
.statusBarsPadding(), |
||||||
|
factory = { context -> |
||||||
|
WebView(context).apply { |
||||||
|
webViewClient = oidcWebViewClient |
||||||
|
loadUrl(state.oidcDetails.url) |
||||||
|
}.also { |
||||||
|
webView = it |
||||||
|
} |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
when (state.requestState) { |
||||||
|
Async.Uninitialized -> Unit |
||||||
|
is Async.Failure -> { |
||||||
|
ErrorDialog( |
||||||
|
content = state.requestState.error.toString(), |
||||||
|
onDismiss = { state.eventSink(OidcEvents.ClearError) } |
||||||
|
) |
||||||
|
} |
||||||
|
is Async.Loading -> { |
||||||
|
// Indeterminate indicator, to avoid the freeze effect if the connection takes time to initialize. |
||||||
|
CircularProgressIndicator( |
||||||
|
modifier = Modifier.align(Alignment.Center) |
||||||
|
) |
||||||
|
} |
||||||
|
is Async.Success -> onNavigateBack() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Preview |
||||||
|
@Composable |
||||||
|
fun OidcViewLightPreview(@PreviewParameter(OidcStateProvider::class) state: OidcState) = |
||||||
|
ElementPreviewLight { ContentToPreview(state) } |
||||||
|
|
||||||
|
@Preview |
||||||
|
@Composable |
||||||
|
fun OidcViewDarkPreview(@PreviewParameter(OidcStateProvider::class) state: OidcState) = |
||||||
|
ElementPreviewDark { ContentToPreview(state) } |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun ContentToPreview(state: OidcState) { |
||||||
|
OidcView( |
||||||
|
state = state, |
||||||
|
onNavigateBack = { }, |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
import android.annotation.TargetApi |
||||||
|
import android.os.Build |
||||||
|
import android.webkit.WebResourceRequest |
||||||
|
import android.webkit.WebView |
||||||
|
import android.webkit.WebViewClient |
||||||
|
import timber.log.Timber |
||||||
|
|
||||||
|
// TODO Move to a dedicated module |
||||||
|
class OidcWebViewClient(private val eventListener: WebViewEventListener) : WebViewClient() { |
||||||
|
@TargetApi(Build.VERSION_CODES.N) |
||||||
|
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { |
||||||
|
return shouldOverrideUrl(request.url.toString()) |
||||||
|
} |
||||||
|
|
||||||
|
@Deprecated("Deprecated in Java") |
||||||
|
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { |
||||||
|
return shouldOverrideUrl(url) |
||||||
|
} |
||||||
|
|
||||||
|
private fun shouldOverrideUrl(url: String): Boolean { |
||||||
|
Timber.d("shouldOverrideUrl: $url") |
||||||
|
return eventListener.shouldOverrideUrlLoading(url) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.login.impl.oidc |
||||||
|
|
||||||
|
interface WebViewEventListener { |
||||||
|
/** |
||||||
|
* Triggered when a Webview loads an url. |
||||||
|
* |
||||||
|
* @param url The url about to be rendered. |
||||||
|
* @return true if the method needs to manage some custom handling |
||||||
|
*/ |
||||||
|
fun shouldOverrideUrlLoading(url: String): Boolean { |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.api.auth |
||||||
|
|
||||||
|
object OidcConfig { |
||||||
|
const val redirectUri = "io.element:/callback" |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.api.auth |
||||||
|
|
||||||
|
import android.os.Parcelable |
||||||
|
import kotlinx.parcelize.Parcelize |
||||||
|
|
||||||
|
@Parcelize |
||||||
|
data class OidcDetails( |
||||||
|
val url: String, |
||||||
|
) : Parcelable |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.auth |
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcConfig |
||||||
|
import org.matrix.rustcomponents.sdk.OidcClientMetadata |
||||||
|
|
||||||
|
val oidcClientMetadata: OidcClientMetadata = OidcClientMetadata( |
||||||
|
clientName = "Element", |
||||||
|
redirectUri = OidcConfig.redirectUri, |
||||||
|
clientUri = "https://element.io", |
||||||
|
tosUri = "https://element.io/user-terms-of-service", |
||||||
|
policyUri = "https://element.io/privacy" |
||||||
|
) |
||||||
|
|
Loading…
Reference in new issue