Legals: Trick to get the homeserver policy

This commit is contained in:
Benoit Marty 2021-12-08 19:58:50 +01:00 committed by Benoit Marty
parent d49a0dde6e
commit 411fd31d4c
5 changed files with 66 additions and 7 deletions

View file

@ -19,7 +19,12 @@ package org.matrix.android.sdk.api.session.terms
interface TermsService { interface TermsService {
enum class ServiceType { enum class ServiceType {
IntegrationManager, IntegrationManager,
IdentityService IdentityService,
/**
* It's only possible to use this value for [getTerms]
*/
Homeserver
} }
suspend fun getTerms(serviceType: ServiceType, baseUrl: String): GetTermsResponse suspend fun getTerms(serviceType: ServiceType, baseUrl: String): GetTermsResponse

View file

@ -18,10 +18,13 @@ package org.matrix.android.sdk.internal.session.terms
import dagger.Lazy import dagger.Lazy
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.terms.GetTermsResponse import org.matrix.android.sdk.api.session.terms.GetTermsResponse
import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
import org.matrix.android.sdk.internal.network.NetworkConstants import org.matrix.android.sdk.internal.network.NetworkConstants
import org.matrix.android.sdk.internal.network.RetrofitFactory import org.matrix.android.sdk.internal.network.RetrofitFactory
@ -48,11 +51,49 @@ internal class DefaultTermsService @Inject constructor(
override suspend fun getTerms(serviceType: TermsService.ServiceType, override suspend fun getTerms(serviceType: TermsService.ServiceType,
baseUrl: String): GetTermsResponse { baseUrl: String): GetTermsResponse {
val url = buildUrl(baseUrl, serviceType) return if (serviceType == TermsService.ServiceType.Homeserver) {
val termsResponse = executeRequest(null) { getHomeserverTerms(baseUrl)
termsAPI.getTerms("${url}terms") } else {
val url = buildUrl(baseUrl, serviceType)
val termsResponse = executeRequest(null) {
termsAPI.getTerms("${url}terms")
}
GetTermsResponse(termsResponse, getAlreadyAcceptedTermUrlsFromAccountData())
} }
return GetTermsResponse(termsResponse, getAlreadyAcceptedTermUrlsFromAccountData()) }
/**
* We use a trick here to get the homeserver T&C, we use the register API
*/
private suspend fun getHomeserverTerms(baseUrl: String): GetTermsResponse {
return try {
executeRequest(null) {
termsAPI.register(baseUrl + NetworkConstants.URI_API_PREFIX_PATH_R0 + "register")
}
// Return empty result if it succeed, but it should never happen
buildEmptyGetTermsResponse()
} catch (throwable: Throwable) {
@Suppress("UNCHECKED_CAST")
((throwable.toRegistrationFlowResponse()
?.params?.get(LoginFlowTypes.TERMS) as? JsonDict)
?.get("policies") as? JsonDict)
?.let { dict ->
GetTermsResponse(
serverResponse = TermsResponse(
policies = dict
),
alreadyAcceptedTermUrls = emptySet()
)
}
?: buildEmptyGetTermsResponse()
}
}
private fun buildEmptyGetTermsResponse(): GetTermsResponse {
return GetTermsResponse(
serverResponse = TermsResponse(),
alreadyAcceptedTermUrls = emptySet()
)
} }
override suspend fun agreeToTerms(serviceType: TermsService.ServiceType, override suspend fun agreeToTerms(serviceType: TermsService.ServiceType,
@ -91,7 +132,9 @@ internal class DefaultTermsService @Inject constructor(
private fun buildUrl(baseUrl: String, serviceType: TermsService.ServiceType): String { private fun buildUrl(baseUrl: String, serviceType: TermsService.ServiceType): String {
val servicePath = when (serviceType) { val servicePath = when (serviceType) {
TermsService.ServiceType.IntegrationManager -> NetworkConstants.URI_INTEGRATION_MANAGER_PATH TermsService.ServiceType.IntegrationManager -> NetworkConstants.URI_INTEGRATION_MANAGER_PATH
TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2 TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2
TermsService.ServiceType.Homeserver ->
error("You cannot use this API with parameter TermsService.ServiceType.Homeserver")
} }
return "${baseUrl.ensureTrailingSlash()}$servicePath" return "${baseUrl.ensureTrailingSlash()}$servicePath"
} }

View file

@ -16,6 +16,8 @@
package org.matrix.android.sdk.internal.session.terms package org.matrix.android.sdk.internal.session.terms
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.api.util.emptyJsonDict
import org.matrix.android.sdk.internal.network.HttpHeaders import org.matrix.android.sdk.internal.network.HttpHeaders
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
@ -37,4 +39,12 @@ internal interface TermsAPI {
suspend fun agreeToTerms(@Url url: String, suspend fun agreeToTerms(@Url url: String,
@Body params: AcceptTermsBody, @Body params: AcceptTermsBody,
@Header(HttpHeaders.Authorization) token: String) @Header(HttpHeaders.Authorization) token: String)
/**
* API to retrieve the terms for a homeserver. The API /terms does not exist yet, so retrieve the terms from the login flow.
* We do not care about the result (Credentials)
*/
@POST
suspend fun register(@Url url: String,
@Body body: JsonDict = emptyJsonDict)
} }

View file

@ -29,7 +29,7 @@ suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): Identity
suspend fun Session.fetchHomeserverWithTerms(userLanguage: String): IdentityServerWithTerms { suspend fun Session.fetchHomeserverWithTerms(userLanguage: String): IdentityServerWithTerms {
val homeserverUrl = sessionParams.homeServerUrl val homeserverUrl = sessionParams.homeServerUrl
return fetchTerms(homeserverUrl, TermsService.ServiceType.IdentityService, userLanguage) return fetchTerms(homeserverUrl, TermsService.ServiceType.Homeserver, userLanguage)
} }
private suspend fun Session.fetchTerms(serviceUrl: String, private suspend fun Session.fetchTerms(serviceUrl: String,

View file

@ -53,6 +53,7 @@ class ReviewTermsFragment @Inject constructor(
termsController.description = when (reviewTermsViewModel.termsArgs.type) { termsController.description = when (reviewTermsViewModel.termsArgs.type) {
TermsService.ServiceType.IdentityService -> getString(R.string.terms_description_for_identity_server) TermsService.ServiceType.IdentityService -> getString(R.string.terms_description_for_identity_server)
TermsService.ServiceType.IntegrationManager -> getString(R.string.terms_description_for_integration_manager) TermsService.ServiceType.IntegrationManager -> getString(R.string.terms_description_for_integration_manager)
TermsService.ServiceType.Homeserver -> error("Homeserver is not supported here")
} }
termsController.listener = this termsController.listener = this