Identity: ping API V2 and cleanup
This commit is contained in:
parent
38fb7185b6
commit
ed2f62cbe7
@ -31,6 +31,13 @@ interface IdentityService {
|
|||||||
|
|
||||||
fun getCurrentIdentityServer(): String?
|
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.
|
* Update the identity server url.
|
||||||
* @param url the new url. Set to null to disconnect from the identity server
|
* @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
|
package im.vector.matrix.android.api.session.identity
|
||||||
|
|
||||||
sealed class IdentityServiceError(cause: Throwable? = null) : Throwable(cause = cause) {
|
sealed class IdentityServiceError(cause: Throwable? = null) : Throwable(cause = cause) {
|
||||||
|
object OutdatedIdentityServer : IdentityServiceError(null)
|
||||||
object NoIdentityServerConfigured : IdentityServiceError(null)
|
object NoIdentityServerConfigured : IdentityServiceError(null)
|
||||||
object TermsNotSignedException : IdentityServiceError(null)
|
object TermsNotSignedException : IdentityServiceError(null)
|
||||||
object BulkLookupSha256NotSupported : IdentityServiceError(null)
|
object BulkLookupSha256NotSupported : IdentityServiceError(null)
|
||||||
|
@ -29,7 +29,9 @@ internal object NetworkConstants {
|
|||||||
|
|
||||||
// Identity server
|
// Identity server
|
||||||
const val URI_IDENTITY_PATH = "_matrix/identity/api/v1/"
|
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"
|
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 getOpenIdTokenTask: GetOpenIdTokenTask,
|
||||||
private val bulkLookupTask: BulkLookupTask,
|
private val bulkLookupTask: BulkLookupTask,
|
||||||
private val identityRegisterTask: IdentityRegisterTask,
|
private val identityRegisterTask: IdentityRegisterTask,
|
||||||
|
private val identityPingTask: IdentityPingTask,
|
||||||
private val identityDisconnectTask: IdentityDisconnectTask,
|
private val identityDisconnectTask: IdentityDisconnectTask,
|
||||||
private val identityRequestTokenForBindingTask: IdentityRequestTokenForBindingTask,
|
private val identityRequestTokenForBindingTask: IdentityRequestTokenForBindingTask,
|
||||||
@Unauthenticated
|
@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 {
|
override fun setNewIdentityServer(url: String?, callback: MatrixCallback<String?>): Cancelable {
|
||||||
val urlCandidate = url?.let { param ->
|
val urlCandidate = url?.let { param ->
|
||||||
buildString {
|
buildString {
|
||||||
|
@ -32,14 +32,21 @@ internal interface IdentityAuthAPI {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
* 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
|
* 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
|
* @return 200 in case of success
|
||||||
*/
|
*/
|
||||||
@GET(NetworkConstants.URI_API_PREFIX_IDENTITY)
|
@GET(NetworkConstants.URI_IDENTITY_PREFIX_PATH)
|
||||||
fun ping(): Call<Void>
|
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.
|
* 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
|
@Binds
|
||||||
abstract fun bindIdentityServiceStore(store: RealmIdentityServiceStore): IdentityServiceStore
|
abstract fun bindIdentityServiceStore(store: RealmIdentityServiceStore): IdentityServiceStore
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindIdentityPingTask(task: DefaultIdentityPingTask): IdentityPingTask
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindIdentityRegisterTask(task: DefaultIdentityRegisterTask): IdentityRegisterTask
|
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 ->
|
is Loading ->
|
||||||
settingsProgressItem {
|
settingsProgressItem {
|
||||||
id("progress${pidInfo.threePid.value}")
|
id("progress${pidInfo.threePid.value}")
|
||||||
|
|
||||||
}
|
}
|
||||||
is Success -> Unit /* Cannot happen */
|
is Success -> Unit /* Cannot happen */
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,6 @@ package im.vector.riotx.features.discovery.change
|
|||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
sealed class SetIdentityServerAction : VectorViewModelAction {
|
sealed class SetIdentityServerAction : VectorViewModelAction {
|
||||||
data class UpdateServerName(val url: String) : SetIdentityServerAction()
|
data class UpdateIdentityServerUrl(val url: String) : SetIdentityServerAction()
|
||||||
object DoChangeServerName : SetIdentityServerAction()
|
object DoChangeIdentityServerUrl : SetIdentityServerAction()
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
mKeyTextEdit.isEnabled = true
|
mKeyTextEdit.isEnabled = true
|
||||||
mProgressBar.isVisible = false
|
mProgressBar.isVisible = false
|
||||||
}
|
}
|
||||||
val newText = state.newIdentityServer ?: ""
|
val newText = state.newIdentityServerUrl ?: ""
|
||||||
if (newText != mKeyTextEdit.text.toString()) {
|
if (newText != mKeyTextEdit.text.toString()) {
|
||||||
mKeyTextEdit.setText(newText)
|
mKeyTextEdit.setText(newText)
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
R.id.action_submit -> {
|
R.id.action_submit -> {
|
||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
if (!state.isVerifyingServer) {
|
if (!state.isVerifyingServer) {
|
||||||
viewModel.handle(SetIdentityServerAction.DoChangeServerName)
|
viewModel.handle(SetIdentityServerAction.DoChangeIdentityServerUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@ -98,7 +98,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
if (!state.isVerifyingServer) {
|
if (!state.isVerifyingServer) {
|
||||||
viewModel.handle(SetIdentityServerAction.DoChangeServerName)
|
viewModel.handle(SetIdentityServerAction.DoChangeIdentityServerUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@setOnEditorActionListener true
|
return@setOnEditorActionListener true
|
||||||
@ -147,8 +147,8 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
|
|
||||||
private fun processIdentityServerChange() {
|
private fun processIdentityServerChange() {
|
||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
if (state.newIdentityServer != null) {
|
if (state.newIdentityServerUrl != null) {
|
||||||
sharedViewModel.requestChangeToIdentityServer(state.newIdentityServer)
|
sharedViewModel.requestChangeToIdentityServer(state.newIdentityServerUrl)
|
||||||
parentFragmentManager.popBackStack()
|
parentFragmentManager.popBackStack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
|
|
||||||
@OnTextChanged(R.id.discovery_identity_server_enter_edittext)
|
@OnTextChanged(R.id.discovery_identity_server_enter_edittext)
|
||||||
fun onTextEditChange(s: Editable?) {
|
fun onTextEditChange(s: Editable?) {
|
||||||
s?.toString()?.let { viewModel.handle(SetIdentityServerAction.UpdateServerName(it)) }
|
s?.toString()?.let { viewModel.handle(SetIdentityServerAction.UpdateIdentityServerUrl(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -20,8 +20,7 @@ import androidx.annotation.StringRes
|
|||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
|
||||||
data class SetIdentityServerState(
|
data class SetIdentityServerState(
|
||||||
val existingIdentityServer: String? = null,
|
val newIdentityServerUrl: String? = null,
|
||||||
val newIdentityServer: String? = null,
|
|
||||||
@StringRes val errorMessageId: Int? = null,
|
@StringRes val errorMessageId: Int? = null,
|
||||||
val isVerifyingServer: Boolean = false
|
val isVerifyingServer: Boolean = false
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
@ -23,6 +23,7 @@ import com.squareup.inject.assisted.AssistedInject
|
|||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.api.session.Session
|
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.GetTermsResponse
|
||||||
import im.vector.matrix.android.api.session.terms.TermsService
|
import im.vector.matrix.android.api.session.terms.TermsService
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
@ -62,22 +63,22 @@ class SetIdentityServerViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
override fun handle(action: SetIdentityServerAction) {
|
override fun handle(action: SetIdentityServerAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is SetIdentityServerAction.UpdateServerName -> updateServerName(action)
|
is SetIdentityServerAction.UpdateIdentityServerUrl -> updateIdentityServerUrl(action)
|
||||||
SetIdentityServerAction.DoChangeServerName -> doChangeServerName()
|
SetIdentityServerAction.DoChangeIdentityServerUrl -> doChangeIdentityServerUrl()
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateServerName(action: SetIdentityServerAction.UpdateServerName) {
|
private fun updateIdentityServerUrl(action: SetIdentityServerAction.UpdateIdentityServerUrl) {
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
newIdentityServer = action.url,
|
newIdentityServerUrl = action.url,
|
||||||
errorMessageId = null
|
errorMessageId = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doChangeServerName() = withState {
|
private fun doChangeIdentityServerUrl() = withState {
|
||||||
var baseUrl: String? = it.newIdentityServer
|
var baseUrl: String? = it.newIdentityServerUrl
|
||||||
if (baseUrl.isNullOrBlank()) {
|
if (baseUrl.isNullOrBlank()) {
|
||||||
setState {
|
setState {
|
||||||
copy(errorMessageId = R.string.settings_discovery_please_enter_server)
|
copy(errorMessageId = R.string.settings_discovery_please_enter_server)
|
||||||
@ -89,6 +90,29 @@ class SetIdentityServerViewModel @AssistedInject constructor(
|
|||||||
copy(isVerifyingServer = true)
|
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,
|
mxSession.getTerms(TermsService.ServiceType.IdentityService,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
object : MatrixCallback<GetTermsResponse> {
|
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_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_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_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_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>
|
<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…
x
Reference in New Issue
Block a user