Merge pull request #1945 from vector-im/feature/update_element_config_file_parsing

Feature/update element config file parsing
This commit is contained in:
Benoit Marty 2020-08-18 18:31:39 +02:00 committed by GitHub
commit 72f5f8b64b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 27 deletions

View File

@ -9,6 +9,7 @@ Improvements 🙌:
- Give user the possibility to prevent accidental call (#1869) - Give user the possibility to prevent accidental call (#1869)
- Display device information (name, id and key) in Cryptography setting screen (#1784) - Display device information (name, id and key) in Cryptography setting screen (#1784)
- Ensure users do not accidentally ignore other users (#1890) - Ensure users do not accidentally ignore other users (#1890)
- Support new config.json format and config.domain.json files (#1682)
- Increase Font size on Calling screen (#1643) - Increase Font size on Calling screen (#1643)
Bugfix 🐛: Bugfix 🐛:

View File

@ -42,6 +42,11 @@ import retrofit2.http.Url
* The login REST API. * The login REST API.
*/ */
internal interface AuthAPI { internal interface AuthAPI {
/**
* Get a Riot config file, using the name including the domain
*/
@GET("config.{domain}.json")
fun getRiotConfigDomain(@Path("domain") domain: String): Call<RiotConfig>
/** /**
* Get a Riot config file * Get a Riot config file

View File

@ -19,6 +19,9 @@ package org.matrix.android.sdk.internal.auth
import android.net.Uri import android.net.Uri
import dagger.Lazy import dagger.Lazy
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.Credentials
@ -50,12 +53,8 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.task.launchToCallback
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.util.exhaustive
import org.matrix.android.sdk.internal.util.toCancelable import org.matrix.android.sdk.internal.util.toCancelable
import org.matrix.android.sdk.internal.wellknown.GetWellknownTask import org.matrix.android.sdk.internal.wellknown.GetWellknownTask
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import javax.inject.Inject import javax.inject.Inject
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
@ -157,7 +156,7 @@ internal class DefaultAuthenticationService @Inject constructor(
if (it is Failure.OtherServerError if (it is Failure.OtherServerError
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) { && it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
// It's maybe a Riot url? // It's maybe a Riot url?
getRiotLoginFlowInternal(homeServerConnectionConfig) getRiotDomainLoginFlowInternal(homeServerConnectionConfig)
} else { } else {
throw it throw it
} }
@ -166,6 +165,37 @@ internal class DefaultAuthenticationService @Inject constructor(
} }
} }
private suspend fun getRiotDomainLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
val authAPI = buildAuthAPI(homeServerConnectionConfig)
val domain = homeServerConnectionConfig.homeServerUri.host
?: return getRiotLoginFlowInternal(homeServerConnectionConfig)
// Ok, try to get the config.domain.json file of a RiotWeb client
return runCatching {
executeRequest<RiotConfig>(null) {
apiCall = authAPI.getRiotConfigDomain(domain)
}
}
.map { riotConfig ->
onRiotConfigRetrieved(homeServerConnectionConfig, riotConfig)
}
.fold(
{
it
},
{
if (it is Failure.OtherServerError
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
// Try with config.json
getRiotLoginFlowInternal(homeServerConnectionConfig)
} else {
throw it
}
}
)
}
private suspend fun getRiotLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { private suspend fun getRiotLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
val authAPI = buildAuthAPI(homeServerConnectionConfig) val authAPI = buildAuthAPI(homeServerConnectionConfig)
@ -176,23 +206,7 @@ internal class DefaultAuthenticationService @Inject constructor(
} }
} }
.map { riotConfig -> .map { riotConfig ->
if (riotConfig.defaultHomeServerUrl?.isNotBlank() == true) { onRiotConfigRetrieved(homeServerConnectionConfig, riotConfig)
// Ok, good sign, we got a default hs url
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
homeServerUri = Uri.parse(riotConfig.defaultHomeServerUrl)
)
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
val versions = executeRequest<Versions>(null) {
apiCall = newAuthAPI.versions()
}
getLoginFlowResult(newAuthAPI, versions, riotConfig.defaultHomeServerUrl)
} else {
// Config exists, but there is no default homeserver url (ex: https://riot.im/app)
throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
}
} }
.fold( .fold(
{ {
@ -210,6 +224,27 @@ internal class DefaultAuthenticationService @Inject constructor(
) )
} }
private suspend fun onRiotConfigRetrieved(homeServerConnectionConfig: HomeServerConnectionConfig, riotConfig: RiotConfig): LoginFlowResult {
val defaultHomeServerUrl = riotConfig.getPreferredHomeServerUrl()
if (defaultHomeServerUrl?.isNotEmpty() == true) {
// Ok, good sign, we got a default hs url
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
homeServerUri = Uri.parse(defaultHomeServerUrl)
)
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
val versions = executeRequest<Versions>(null) {
apiCall = newAuthAPI.versions()
}
return getLoginFlowResult(newAuthAPI, versions, defaultHomeServerUrl)
} else {
// Config exists, but there is no default homeserver url (ex: https://riot.im/app)
throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
}
}
private suspend fun getWellknownLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { private suspend fun getWellknownLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
val domain = homeServerConnectionConfig.homeServerUri.host val domain = homeServerConnectionConfig.homeServerUri.host
?: throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) ?: throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
@ -234,7 +269,7 @@ internal class DefaultAuthenticationService @Inject constructor(
getLoginFlowResult(newAuthAPI, versions, wellknownResult.homeServerUrl) getLoginFlowResult(newAuthAPI, versions, wellknownResult.homeServerUrl)
} }
else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
}.exhaustive }
} }
private suspend fun getLoginFlowResult(authAPI: AuthAPI, versions: Versions, homeServerUrl: String): LoginFlowResult { private suspend fun getLoginFlowResult(authAPI: AuthAPI, versions: Versions, homeServerUrl: String): LoginFlowResult {

View File

@ -21,9 +21,31 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class RiotConfig( internal data class RiotConfig(
// There are plenty of other elements in the file config.json of a RiotWeb client, but for the moment only one is interesting /**
// Ex: "brand", "branding", etc. * This is now deprecated, but still used first, rather than value from "default_server_config"
*/
@Json(name = "default_hs_url") @Json(name = "default_hs_url")
val defaultHomeServerUrl: String? val defaultHomeServerUrl: String?,
@Json(name = "default_server_config")
val defaultServerConfig: RiotConfigDefaultServerConfig?
) {
fun getPreferredHomeServerUrl(): String? {
return defaultHomeServerUrl
?.takeIf { it.isNotEmpty() }
?: defaultServerConfig?.homeServer?.baseURL
}
}
@JsonClass(generateAdapter = true)
internal data class RiotConfigDefaultServerConfig(
@Json(name = "m.homeserver")
val homeServer: RiotConfigBaseConfig? = null
)
@JsonClass(generateAdapter = true)
internal data class RiotConfigBaseConfig(
@Json(name = "base_url")
val baseURL: String? = null
) )