Identity: ping API V2 and cleanup
This commit is contained in:
parent
38fb7185b6
commit
ed2f62cbe7
|
@ -31,6 +31,13 @@ interface IdentityService {
|
|||
|
||||
fun getCurrentIdentityServer(): String?
|
||||
|
||||
/**
|
||||
* Check if the identity server is valid
|
||||
* See https://matrix.org/docs/spec/identity_service/latest#status-check
|
||||
* RiotX SDK only supports identity server API v2
|
||||
*/
|
||||
fun isValidIdentityServer(url: String, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
/**
|
||||
* Update the identity server url.
|
||||
* @param url the new url. Set to null to disconnect from the identity server
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.matrix.android.api.session.identity
|
||||
|
||||
sealed class IdentityServiceError(cause: Throwable? = null) : Throwable(cause = cause) {
|
||||
object OutdatedIdentityServer : IdentityServiceError(null)
|
||||
object NoIdentityServerConfigured : IdentityServiceError(null)
|
||||
object TermsNotSignedException : IdentityServiceError(null)
|
||||
object BulkLookupSha256NotSupported : IdentityServiceError(null)
|
||||
|
|
|
@ -29,7 +29,9 @@ internal object NetworkConstants {
|
|||
|
||||
// Identity server
|
||||
const val URI_IDENTITY_PATH = "_matrix/identity/api/v1/"
|
||||
const val URI_IDENTITY_PATH_V2 = "_matrix/identity/v2/"
|
||||
|
||||
const val URI_IDENTITY_PREFIX_PATH = "_matrix/identity/v2"
|
||||
const val URI_IDENTITY_PATH_V2 = "$URI_IDENTITY_PREFIX_PATH/"
|
||||
|
||||
const val URI_API_PREFIX_IDENTITY = "_matrix/identity/api/v1"
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ internal class DefaultIdentityService @Inject constructor(
|
|||
private val getOpenIdTokenTask: GetOpenIdTokenTask,
|
||||
private val bulkLookupTask: BulkLookupTask,
|
||||
private val identityRegisterTask: IdentityRegisterTask,
|
||||
private val identityPingTask: IdentityPingTask,
|
||||
private val identityDisconnectTask: IdentityDisconnectTask,
|
||||
private val identityRequestTokenForBindingTask: IdentityRequestTokenForBindingTask,
|
||||
@Unauthenticated
|
||||
|
@ -157,6 +158,14 @@ internal class DefaultIdentityService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun isValidIdentityServer(url: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
return GlobalScope.launchToCallback(coroutineDispatchers.main, callback) {
|
||||
val api = retrofitFactory.create(unauthenticatedOkHttpClient, url).create(IdentityAuthAPI::class.java)
|
||||
|
||||
identityPingTask.execute(IdentityPingTask.Params(api))
|
||||
}
|
||||
}
|
||||
|
||||
override fun setNewIdentityServer(url: String?, callback: MatrixCallback<String?>): Cancelable {
|
||||
val urlCandidate = url?.let { param ->
|
||||
buildString {
|
||||
|
|
|
@ -32,14 +32,21 @@ internal interface IdentityAuthAPI {
|
|||
|
||||
/**
|
||||
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
||||
* Simple ping call to check if server alive
|
||||
* Simple ping call to check if server exists and is alive
|
||||
*
|
||||
* Ref: https://matrix.org/docs/spec/identity_service/unstable#status-check
|
||||
* https://matrix.org/docs/spec/identity_service/latest#get-matrix-identity-v2
|
||||
*
|
||||
* @return 200 in case of success
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_IDENTITY)
|
||||
fun ping(): Call<Void>
|
||||
@GET(NetworkConstants.URI_IDENTITY_PREFIX_PATH)
|
||||
fun ping(): Call<Unit>
|
||||
|
||||
/**
|
||||
* Ping v1 will be used to check outdated Identity server
|
||||
*/
|
||||
@GET("_matrix/identity/api/v1")
|
||||
fun pingV1(): Call<Unit>
|
||||
|
||||
/**
|
||||
* Exchanges an OpenID token from the homeserver for an access token to access the identity server.
|
||||
|
|
|
@ -92,6 +92,9 @@ internal abstract class IdentityModule {
|
|||
@Binds
|
||||
abstract fun bindIdentityServiceStore(store: RealmIdentityServiceStore): IdentityServiceStore
|
||||
|
||||
@Binds
|
||||
abstract fun bindIdentityPingTask(task: DefaultIdentityPingTask): IdentityPingTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindIdentityRegisterTask(task: DefaultIdentityRegisterTask): IdentityRegisterTask
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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 im.vector.matrix.android.internal.session.identity
|
||||
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.identity.IdentityServiceError
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
internal interface IdentityPingTask : Task<IdentityPingTask.Params, Unit> {
|
||||
data class Params(
|
||||
val identityAuthAPI: IdentityAuthAPI
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultIdentityPingTask @Inject constructor() : IdentityPingTask {
|
||||
|
||||
override suspend fun execute(params: IdentityPingTask.Params) {
|
||||
try {
|
||||
executeRequest<Unit>(null) {
|
||||
apiCall = params.identityAuthAPI.ping()
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
if (throwable is Failure.ServerError && throwable.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
||||
// Check if API v1 is available
|
||||
executeRequest<Unit>(null) {
|
||||
apiCall = params.identityAuthAPI.pingV1()
|
||||
}
|
||||
// API V1 is responding, but not V2 -> Outdated
|
||||
throw IdentityServiceError.OutdatedIdentityServer
|
||||
} else {
|
||||
throw throwable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -198,7 +198,6 @@ class DiscoverySettingsController @Inject constructor(
|
|||
is Loading ->
|
||||
settingsProgressItem {
|
||||
id("progress${pidInfo.threePid.value}")
|
||||
|
||||
}
|
||||
is Success -> Unit /* Cannot happen */
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@ package im.vector.riotx.features.discovery.change
|
|||
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class SetIdentityServerAction : VectorViewModelAction {
|
||||
data class UpdateServerName(val url: String) : SetIdentityServerAction()
|
||||
object DoChangeServerName : SetIdentityServerAction()
|
||||
data class UpdateIdentityServerUrl(val url: String) : SetIdentityServerAction()
|
||||
object DoChangeIdentityServerUrl : SetIdentityServerAction()
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
mKeyTextEdit.isEnabled = true
|
||||
mProgressBar.isVisible = false
|
||||
}
|
||||
val newText = state.newIdentityServer ?: ""
|
||||
val newText = state.newIdentityServerUrl ?: ""
|
||||
if (newText != mKeyTextEdit.text.toString()) {
|
||||
mKeyTextEdit.setText(newText)
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
R.id.action_submit -> {
|
||||
withState(viewModel) { state ->
|
||||
if (!state.isVerifyingServer) {
|
||||
viewModel.handle(SetIdentityServerAction.DoChangeServerName)
|
||||
viewModel.handle(SetIdentityServerAction.DoChangeIdentityServerUrl)
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -98,7 +98,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
withState(viewModel) { state ->
|
||||
if (!state.isVerifyingServer) {
|
||||
viewModel.handle(SetIdentityServerAction.DoChangeServerName)
|
||||
viewModel.handle(SetIdentityServerAction.DoChangeIdentityServerUrl)
|
||||
}
|
||||
}
|
||||
return@setOnEditorActionListener true
|
||||
|
@ -147,8 +147,8 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
|
||||
private fun processIdentityServerChange() {
|
||||
withState(viewModel) { state ->
|
||||
if (state.newIdentityServer != null) {
|
||||
sharedViewModel.requestChangeToIdentityServer(state.newIdentityServer)
|
||||
if (state.newIdentityServerUrl != null) {
|
||||
sharedViewModel.requestChangeToIdentityServer(state.newIdentityServerUrl)
|
||||
parentFragmentManager.popBackStack()
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
|
||||
@OnTextChanged(R.id.discovery_identity_server_enter_edittext)
|
||||
fun onTextEditChange(s: Editable?) {
|
||||
s?.toString()?.let { viewModel.handle(SetIdentityServerAction.UpdateServerName(it)) }
|
||||
s?.toString()?.let { viewModel.handle(SetIdentityServerAction.UpdateIdentityServerUrl(it)) }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -20,8 +20,7 @@ import androidx.annotation.StringRes
|
|||
import com.airbnb.mvrx.MvRxState
|
||||
|
||||
data class SetIdentityServerState(
|
||||
val existingIdentityServer: String? = null,
|
||||
val newIdentityServer: String? = null,
|
||||
val newIdentityServerUrl: String? = null,
|
||||
@StringRes val errorMessageId: Int? = null,
|
||||
val isVerifyingServer: Boolean = false
|
||||
) : MvRxState
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.squareup.inject.assisted.AssistedInject
|
|||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.identity.IdentityServiceError
|
||||
import im.vector.matrix.android.api.session.terms.GetTermsResponse
|
||||
import im.vector.matrix.android.api.session.terms.TermsService
|
||||
import im.vector.riotx.R
|
||||
|
@ -62,22 +63,22 @@ class SetIdentityServerViewModel @AssistedInject constructor(
|
|||
|
||||
override fun handle(action: SetIdentityServerAction) {
|
||||
when (action) {
|
||||
is SetIdentityServerAction.UpdateServerName -> updateServerName(action)
|
||||
SetIdentityServerAction.DoChangeServerName -> doChangeServerName()
|
||||
is SetIdentityServerAction.UpdateIdentityServerUrl -> updateIdentityServerUrl(action)
|
||||
SetIdentityServerAction.DoChangeIdentityServerUrl -> doChangeIdentityServerUrl()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun updateServerName(action: SetIdentityServerAction.UpdateServerName) {
|
||||
private fun updateIdentityServerUrl(action: SetIdentityServerAction.UpdateIdentityServerUrl) {
|
||||
setState {
|
||||
copy(
|
||||
newIdentityServer = action.url,
|
||||
newIdentityServerUrl = action.url,
|
||||
errorMessageId = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doChangeServerName() = withState {
|
||||
var baseUrl: String? = it.newIdentityServer
|
||||
private fun doChangeIdentityServerUrl() = withState {
|
||||
var baseUrl: String? = it.newIdentityServerUrl
|
||||
if (baseUrl.isNullOrBlank()) {
|
||||
setState {
|
||||
copy(errorMessageId = R.string.settings_discovery_please_enter_server)
|
||||
|
@ -89,6 +90,29 @@ class SetIdentityServerViewModel @AssistedInject constructor(
|
|||
copy(isVerifyingServer = true)
|
||||
}
|
||||
|
||||
// First ping the identity server v2 API
|
||||
mxSession.identityService().isValidIdentityServer(baseUrl, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
// Ok, next step
|
||||
checkTerms(baseUrl)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
setState {
|
||||
copy(
|
||||
isVerifyingServer = false,
|
||||
errorMessageId = if (failure is IdentityServiceError.OutdatedIdentityServer) {
|
||||
R.string.settings_discovery_outdated_identity_server
|
||||
} else {
|
||||
R.string.settings_discovery_bad_identity_server
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun checkTerms(baseUrl: String) {
|
||||
mxSession.getTerms(TermsService.ServiceType.IdentityService,
|
||||
baseUrl,
|
||||
object : MatrixCallback<GetTermsResponse> {
|
||||
|
|
|
@ -1738,6 +1738,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
|
|||
|
||||
<string name="settings_discovery_enter_identity_server">Enter a new identity server</string>
|
||||
<string name="settings_discovery_bad_identity_server">Could not connect to identity server</string>
|
||||
<string name="settings_discovery_outdated_identity_server">This identity server does not support API V2</string>
|
||||
<string name="settings_discovery_please_enter_server">Please enter the identity server url</string>
|
||||
<string name="settings_discovery_no_terms_title">Identity server has no terms of services</string>
|
||||
<string name="settings_discovery_no_terms">The identity server you have chosen does not have any terms of services. Only continue if you trust the owner of the service</string>
|
||||
|
|
Loading…
Reference in New Issue