Merge pull request #2111 from vector-im/feature/bma_raw_service

Raw service
This commit is contained in:
Benoit Marty 2020-09-16 17:55:42 +02:00 committed by GitHub
commit 4c6234796d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 780 additions and 89 deletions

View file

@ -21,7 +21,7 @@ Translations 🗣:
- -
SDK API changes ⚠️: SDK API changes ⚠️:
- - Create a new RawService to get plain data from the server.
Build 🧱: Build 🧱:
- -

View file

@ -24,6 +24,7 @@ import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.legacy.LegacySessionImporter import org.matrix.android.sdk.api.legacy.LegacySessionImporter
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.common.DaggerTestMatrixComponent import org.matrix.android.sdk.common.DaggerTestMatrixComponent
import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.network.UserAgentHolder import org.matrix.android.sdk.internal.network.UserAgentHolder
@ -41,6 +42,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
@Inject internal lateinit var legacySessionImporter: LegacySessionImporter @Inject internal lateinit var legacySessionImporter: LegacySessionImporter
@Inject internal lateinit var authenticationService: AuthenticationService @Inject internal lateinit var authenticationService: AuthenticationService
@Inject internal lateinit var rawService: RawService
@Inject internal lateinit var userAgentHolder: UserAgentHolder @Inject internal lateinit var userAgentHolder: UserAgentHolder
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
@Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var olmManager: OlmManager
@ -61,6 +63,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
return authenticationService return authenticationService
} }
fun rawService() = rawService
fun legacySessionImporter(): LegacySessionImporter { fun legacySessionImporter(): LegacySessionImporter {
return legacySessionImporter return legacySessionImporter
} }

View file

@ -25,6 +25,7 @@ import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.legacy.LegacySessionImporter import org.matrix.android.sdk.api.legacy.LegacySessionImporter
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.di.DaggerMatrixComponent import org.matrix.android.sdk.internal.di.DaggerMatrixComponent
import org.matrix.android.sdk.internal.network.UserAgentHolder import org.matrix.android.sdk.internal.network.UserAgentHolder
@ -42,6 +43,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
@Inject internal lateinit var legacySessionImporter: LegacySessionImporter @Inject internal lateinit var legacySessionImporter: LegacySessionImporter
@Inject internal lateinit var authenticationService: AuthenticationService @Inject internal lateinit var authenticationService: AuthenticationService
@Inject internal lateinit var rawService: RawService
@Inject internal lateinit var userAgentHolder: UserAgentHolder @Inject internal lateinit var userAgentHolder: UserAgentHolder
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
@Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var olmManager: OlmManager
@ -62,6 +64,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
return authenticationService return authenticationService
} }
fun rawService() = rawService
fun legacySessionImporter(): LegacySessionImporter { fun legacySessionImporter(): LegacySessionImporter {
return legacySessionImporter return legacySessionImporter
} }

View file

@ -42,9 +42,6 @@ import org.matrix.android.sdk.api.util.JsonDict
* } * }
* ] * ]
* } * }
* "im.vector.riot.jitsi": {
* "preferredDomain": "https://jitsi.riot.im/"
* }
* } * }
* </pre> * </pre>
*/ */
@ -57,24 +54,5 @@ data class WellKnown(
val identityServer: WellKnownBaseConfig? = null, val identityServer: WellKnownBaseConfig? = null,
@Json(name = "m.integrations") @Json(name = "m.integrations")
val integrations: JsonDict? = null, val integrations: JsonDict? = null
@Json(name = "im.vector.riot.e2ee")
val e2eAdminSetting: E2EWellKnownConfig? = null,
@Json(name = "im.vector.riot.jitsi")
val jitsiServer: WellKnownPreferredConfig? = null
)
@JsonClass(generateAdapter = true)
data class E2EWellKnownConfig(
@Json(name = "default")
val e2eDefault: Boolean = true
)
@JsonClass(generateAdapter = true)
data class WellKnownPreferredConfig(
@Json(name = "preferredDomain")
val preferredDomain: String? = null
) )

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.api.raw
sealed class RawCacheStrategy {
// Data is always fetched from the server
object NoCache: RawCacheStrategy()
// Once data is retrieved, it is stored for the provided amount of time.
// In case of error, and if strict is set to false, the cache can be returned if available
data class TtlCache(val validityDurationInMillis: Long, val strict: Boolean): RawCacheStrategy()
// Once retrieved, the data is stored in cache and will be always get from the cache
object InfiniteCache: RawCacheStrategy()
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2020 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.api.raw
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* Useful methods to fetch raw data from the server. The access token will not be used to fetched the data
*/
interface RawService {
/**
* Get a URL, either from cache or from the remote server, depending on the cache strategy
*/
fun getUrl(url: String,
rawCacheStrategy: RawCacheStrategy,
matrixCallback: MatrixCallback<String>): Cancelable
/**
* Specific case for the well-known file. Cache validity is 8 hours
*/
fun getWellknown(userId: String, matrixCallback: MatrixCallback<String>): Cancelable
/**
* Clear all the cache data
*/
fun clearCache(matrixCallback: MatrixCallback<Unit>): Cancelable
}

View file

@ -33,16 +33,7 @@ data class HomeServerCapabilities(
/** /**
* Default identity server url, provided in Wellknown * Default identity server url, provided in Wellknown
*/ */
val defaultIdentityServerUrl: String? = null, val defaultIdentityServerUrl: String? = null
/**
* Option to allow homeserver admins to set the default E2EE behaviour back to disabled for DMs / private rooms
* (as it was before) for various environments where this is desired.
*/
val adminE2EByDefault: Boolean = true,
/**
* Preferred Jitsi domain, provided in Wellknown
*/
val preferredJitsiDomain: String? = null
) { ) {
companion object { companion object {
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L

View file

@ -28,7 +28,7 @@ import javax.inject.Inject
class RealmSessionStoreMigration @Inject constructor() : RealmMigration { class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
companion object { companion object {
const val SESSION_STORE_SCHEMA_VERSION = 4L const val SESSION_STORE_SCHEMA_VERSION = 5L
} }
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
@ -38,6 +38,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
if (oldVersion <= 1) migrateTo2(realm) if (oldVersion <= 1) migrateTo2(realm)
if (oldVersion <= 2) migrateTo3(realm) if (oldVersion <= 2) migrateTo3(realm)
if (oldVersion <= 3) migrateTo4(realm) if (oldVersion <= 3) migrateTo4(realm)
if (oldVersion <= 4) migrateTo5(realm)
} }
private fun migrateTo1(realm: DynamicRealm) { private fun migrateTo1(realm: DynamicRealm) {
@ -54,16 +55,16 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
private fun migrateTo2(realm: DynamicRealm) { private fun migrateTo2(realm: DynamicRealm) {
Timber.d("Step 1 -> 2") Timber.d("Step 1 -> 2")
realm.schema.get("HomeServerCapabilitiesEntity") realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.ADMIN_E2_E_BY_DEFAULT, Boolean::class.java) ?.addField("adminE2EByDefault", Boolean::class.java)
?.transform { obj -> ?.transform { obj ->
obj.setBoolean(HomeServerCapabilitiesEntityFields.ADMIN_E2_E_BY_DEFAULT, true) obj.setBoolean("adminE2EByDefault", true)
} }
} }
private fun migrateTo3(realm: DynamicRealm) { private fun migrateTo3(realm: DynamicRealm) {
Timber.d("Step 2 -> 3") Timber.d("Step 2 -> 3")
realm.schema.get("HomeServerCapabilitiesEntity") realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.PREFERRED_JITSI_DOMAIN, String::class.java) ?.addField("preferredJitsiDomain", String::class.java)
?.transform { obj -> ?.transform { obj ->
// Schedule a refresh of the capabilities // Schedule a refresh of the capabilities
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0) obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
@ -82,4 +83,11 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
.setRequired(PendingThreePidEntityFields.SID, true) .setRequired(PendingThreePidEntityFields.SID, true)
.addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java) .addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java)
} }
private fun migrateTo5(realm: DynamicRealm) {
Timber.d("Step 4 -> 5")
realm.schema.get("HomeServerCapabilitiesEntity")
?.removeField("adminE2EByDefault")
?.removeField("preferredJitsiDomain")
}
} }

View file

@ -30,9 +30,7 @@ internal object HomeServerCapabilitiesMapper {
canChangePassword = entity.canChangePassword, canChangePassword = entity.canChangePassword,
maxUploadFileSize = entity.maxUploadFileSize, maxUploadFileSize = entity.maxUploadFileSize,
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported, lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
defaultIdentityServerUrl = entity.defaultIdentityServerUrl, defaultIdentityServerUrl = entity.defaultIdentityServerUrl
adminE2EByDefault = entity.adminE2EByDefault,
preferredJitsiDomain = entity.preferredJitsiDomain
) )
} }
} }

View file

@ -17,17 +17,15 @@
package org.matrix.android.sdk.internal.database.model package org.matrix.android.sdk.internal.database.model
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import io.realm.RealmObject import io.realm.RealmObject
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
internal open class HomeServerCapabilitiesEntity( internal open class HomeServerCapabilitiesEntity(
var canChangePassword: Boolean = true, var canChangePassword: Boolean = true,
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN, var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
var lastVersionIdentityServerSupported: Boolean = false, var lastVersionIdentityServerSupported: Boolean = false,
var defaultIdentityServerUrl: String? = null, var defaultIdentityServerUrl: String? = null,
var adminE2EByDefault: Boolean = true, var lastUpdatedTimestamp: Long = 0L
var lastUpdatedTimestamp: Long = 0L,
var preferredJitsiDomain: String? = null
) : RealmObject() { ) : RealmObject() {
companion object companion object

View file

@ -0,0 +1,31 @@
/*
* Copyright 2019 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
internal open class RawCacheEntity(
@PrimaryKey
var url: String = "",
var data: String = "",
var lastUpdatedTimestamp: Long = 0L
) : RealmObject() {
companion object
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2019 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.database.query
import io.realm.Realm
import io.realm.kotlin.createObject
import io.realm.kotlin.where
import org.matrix.android.sdk.internal.database.model.RawCacheEntity
import org.matrix.android.sdk.internal.database.model.RawCacheEntityFields
/**
* Get the current RawCacheEntity, return null if it does not exist
*/
internal fun RawCacheEntity.Companion.get(realm: Realm, url: String): RawCacheEntity? {
return realm.where<RawCacheEntity>()
.equalTo(RawCacheEntityFields.URL, url)
.findFirst()
}
/**
* Get the current RawCacheEntity, create one if it does not exist
*/
internal fun RawCacheEntity.Companion.getOrCreate(realm: Realm, url: String): RawCacheEntity {
return get(realm, url) ?: realm.createObject(url)
}

View file

@ -23,6 +23,10 @@ import javax.inject.Qualifier
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
internal annotation class AuthDatabase internal annotation class AuthDatabase
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class GlobalDatabase
@Qualifier @Qualifier
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
internal annotation class SessionDatabase internal annotation class SessionDatabase

View file

@ -22,22 +22,30 @@ import android.content.res.Resources
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import dagger.BindsInstance import dagger.BindsInstance
import dagger.Component import dagger.Component
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.auth.AuthModule import org.matrix.android.sdk.internal.auth.AuthModule
import org.matrix.android.sdk.internal.auth.SessionParamsStore import org.matrix.android.sdk.internal.auth.SessionParamsStore
import org.matrix.android.sdk.internal.raw.RawModule
import org.matrix.android.sdk.internal.session.MockHttpInterceptor import org.matrix.android.sdk.internal.session.MockHttpInterceptor
import org.matrix.android.sdk.internal.session.TestInterceptor import org.matrix.android.sdk.internal.session.TestInterceptor
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import okhttp3.OkHttpClient
import org.matrix.olm.OlmManager import org.matrix.olm.OlmManager
import java.io.File import java.io.File
@Component(modules = [MatrixModule::class, NetworkModule::class, AuthModule::class, NoOpTestModule::class]) @Component(modules = [
MatrixModule::class,
NetworkModule::class,
AuthModule::class,
RawModule::class,
NoOpTestModule::class
])
@MatrixScope @MatrixScope
internal interface MatrixComponent { internal interface MatrixComponent {
@ -53,6 +61,8 @@ internal interface MatrixComponent {
fun authenticationService(): AuthenticationService fun authenticationService(): AuthenticationService
fun rawService(): RawService
fun context(): Context fun context(): Context
fun matrixConfiguration(): MatrixConfiguration fun matrixConfiguration(): MatrixConfiguration

View file

@ -0,0 +1,41 @@
/*
* Copyright 2019 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.raw
import com.zhuinden.monarchy.Monarchy
import io.realm.kotlin.where
import org.matrix.android.sdk.internal.database.model.RawCacheEntity
import org.matrix.android.sdk.internal.di.GlobalDatabase
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import javax.inject.Inject
internal interface CleanRawCacheTask : Task<Unit, Unit>
internal class DefaultCleanRawCacheTask @Inject constructor(
@GlobalDatabase private val monarchy: Monarchy
) : CleanRawCacheTask {
override suspend fun execute(params: Unit) {
monarchy.awaitTransaction { realm ->
realm.where<RawCacheEntity>()
.findAll()
.deleteAllFromRealm()
}
}
}

View file

@ -0,0 +1,101 @@
/*
* Copyright 2019 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.raw
import com.zhuinden.monarchy.Monarchy
import okhttp3.ResponseBody
import org.matrix.android.sdk.api.raw.RawCacheStrategy
import org.matrix.android.sdk.internal.database.model.RawCacheEntity
import org.matrix.android.sdk.internal.database.query.get
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.di.GlobalDatabase
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import java.util.Date
import javax.inject.Inject
internal interface GetUrlTask : Task<GetUrlTask.Params, String> {
data class Params(
val url: String,
val rawCacheStrategy: RawCacheStrategy
)
}
internal class DefaultGetUrlTask @Inject constructor(
private val rawAPI: RawAPI,
@GlobalDatabase private val monarchy: Monarchy
) : GetUrlTask {
override suspend fun execute(params: GetUrlTask.Params): String {
return when (params.rawCacheStrategy) {
RawCacheStrategy.NoCache -> doRequest(params.url)
is RawCacheStrategy.TtlCache -> doRequestWithCache(
params.url,
params.rawCacheStrategy.validityDurationInMillis,
params.rawCacheStrategy.strict
)
RawCacheStrategy.InfiniteCache -> doRequestWithCache(
params.url,
Long.MAX_VALUE,
true
)
}
}
private suspend fun doRequest(url: String): String {
return executeRequest<ResponseBody>(null) {
apiCall = rawAPI.getUrl(url)
}
.string()
}
private suspend fun doRequestWithCache(url: String, validityDurationInMillis: Long, strict: Boolean): String {
// Get data from cache
var dataFromCache: String? = null
var isCacheValid = false
monarchy.doWithRealm { realm ->
val entity = RawCacheEntity.get(realm, url)
dataFromCache = entity?.data
isCacheValid = entity != null && Date().time < entity.lastUpdatedTimestamp + validityDurationInMillis
}
if (dataFromCache != null && isCacheValid) {
return dataFromCache as String
}
// No cache or outdated cache
val data = try {
doRequest(url)
} catch (throwable: Throwable) {
// In case of error, we can return value from cache even if outdated
return dataFromCache
?.takeIf { !strict }
?: throw throwable
}
// Store cache
monarchy.awaitTransaction { realm ->
val rawCacheEntity = RawCacheEntity.getOrCreate(realm, url)
rawCacheEntity.data = data
rawCacheEntity.lastUpdatedTimestamp = Date().time
}
return data
}
}

View file

@ -0,0 +1,60 @@
/*
* 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 org.matrix.android.sdk.internal.raw
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.raw.RawCacheStrategy
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class DefaultRawService @Inject constructor(
private val taskExecutor: TaskExecutor,
private val getUrlTask: GetUrlTask,
private val cleanRawCacheTask: CleanRawCacheTask
) : RawService {
override fun getUrl(url: String,
rawCacheStrategy: RawCacheStrategy,
matrixCallback: MatrixCallback<String>): Cancelable {
return getUrlTask
.configureWith(GetUrlTask.Params(url, rawCacheStrategy)) {
callback = matrixCallback
}
.executeBy(taskExecutor)
}
override fun getWellknown(userId: String,
matrixCallback: MatrixCallback<String>): Cancelable {
val homeServerDomain = userId.substringAfter(":")
return getUrl(
"https://$homeServerDomain/.well-known/matrix/client",
RawCacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false),
matrixCallback
)
}
override fun clearCache(matrixCallback: MatrixCallback<Unit>): Cancelable {
return cleanRawCacheTask
.configureWith(Unit) {
callback = matrixCallback
}
.executeBy(taskExecutor)
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2019 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.raw
import io.realm.annotations.RealmModule
import org.matrix.android.sdk.internal.database.model.RawCacheEntity
/**
* Realm module for global classes
*/
@RealmModule(library = true,
classes = [
RawCacheEntity::class
])
internal class GlobalRealmModule

View file

@ -0,0 +1,29 @@
/*
* Copyright 2020 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.raw
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Url
internal interface RawAPI {
@GET
fun getUrl(@Url url: String): Call<ResponseBody>
}

View file

@ -0,0 +1,81 @@
/*
* Copyright 2020 New Vector Ltd
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.raw
import com.zhuinden.monarchy.Monarchy
import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.Provides
import io.realm.RealmConfiguration
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.internal.database.RealmKeysUtils
import org.matrix.android.sdk.internal.di.GlobalDatabase
import org.matrix.android.sdk.internal.di.MatrixScope
import org.matrix.android.sdk.internal.di.Unauthenticated
import org.matrix.android.sdk.internal.network.RetrofitFactory
@Module
internal abstract class RawModule {
@Module
companion object {
private const val DB_ALIAS = "matrix-sdk-global"
@JvmStatic
@Provides
@GlobalDatabase
fun providesMonarchy(@GlobalDatabase realmConfiguration: RealmConfiguration): Monarchy {
return Monarchy.Builder()
.setRealmConfiguration(realmConfiguration)
.build()
}
@JvmStatic
@Provides
@GlobalDatabase
@MatrixScope
fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils): RealmConfiguration {
return RealmConfiguration.Builder()
.apply {
realmKeysUtils.configureEncryption(this, DB_ALIAS)
}
.name("matrix-sdk-global.realm")
.modules(GlobalRealmModule())
.build()
}
@Provides
@JvmStatic
fun providesRawAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
retrofitFactory: RetrofitFactory): RawAPI {
return retrofitFactory.create(okHttpClient, "https://example.org").create(RawAPI::class.java)
}
}
@Binds
abstract fun bindRawService(service: DefaultRawService): RawService
@Binds
abstract fun bindGetUrlTask(task: DefaultGetUrlTask): GetUrlTask
@Binds
abstract fun bindCleanRawCacheTask(task: DefaultCleanRawCacheTask): CleanRawCacheTask
}

View file

@ -18,6 +18,7 @@
package org.matrix.android.sdk.internal.session.homeserver package org.matrix.android.sdk.internal.session.homeserver
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import org.greenrobot.eventbus.EventBus
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
@ -32,7 +33,6 @@ import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationMan
import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction import org.matrix.android.sdk.internal.util.awaitTransaction
import org.matrix.android.sdk.internal.wellknown.GetWellknownTask import org.matrix.android.sdk.internal.wellknown.GetWellknownTask
import org.greenrobot.eventbus.EventBus
import timber.log.Timber import timber.log.Timber
import java.util.Date import java.util.Date
import javax.inject.Inject import javax.inject.Inject
@ -109,16 +109,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {
homeServerCapabilitiesEntity.defaultIdentityServerUrl = getWellknownResult.identityServerUrl homeServerCapabilitiesEntity.defaultIdentityServerUrl = getWellknownResult.identityServerUrl
homeServerCapabilitiesEntity.adminE2EByDefault = getWellknownResult.wellKnown.e2eAdminSetting?.e2eDefault ?: true
homeServerCapabilitiesEntity.preferredJitsiDomain = getWellknownResult.wellKnown.jitsiServer?.preferredDomain
// We are also checking for integration manager configurations // We are also checking for integration manager configurations
val config = configExtractor.extract(getWellknownResult.wellKnown) val config = configExtractor.extract(getWellknownResult.wellKnown)
if (config != null) { if (config != null) {
Timber.v("Extracted integration config : $config") Timber.v("Extracted integration config : $config")
realm.insertOrUpdate(config) realm.insertOrUpdate(config)
} }
} else {
homeServerCapabilitiesEntity.adminE2EByDefault = true
} }
homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time
} }

View file

@ -57,6 +57,7 @@ import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.ui.UiStateRepository import im.vector.app.features.ui.UiStateRepository
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import javax.inject.Singleton import javax.inject.Singleton
@ -118,6 +119,8 @@ interface VectorComponent {
fun authenticationService(): AuthenticationService fun authenticationService(): AuthenticationService
fun rawService(): RawService
fun bugReporter(): BugReporter fun bugReporter(): BugReporter
fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler

View file

@ -34,6 +34,7 @@ import im.vector.app.features.ui.UiStateRepository
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.legacy.LegacySessionImporter import org.matrix.android.sdk.api.legacy.LegacySessionImporter
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@Module @Module
@ -78,6 +79,12 @@ abstract class VectorModule {
fun providesAuthenticationService(matrix: Matrix): AuthenticationService { fun providesAuthenticationService(matrix: Matrix): AuthenticationService {
return matrix.authenticationService() return matrix.authenticationService()
} }
@Provides
@JvmStatic
fun providesRawService(matrix: Matrix): RawService {
return matrix.rawService()
}
} }
@Binds @Binds

View file

@ -16,6 +16,7 @@
package im.vector.app.features.createdirect package im.vector.app.features.createdirect
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
@ -23,13 +24,19 @@ import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault
import im.vector.app.features.userdirectory.PendingInvitee import im.vector.app.features.userdirectory.PendingInvitee
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
initialState: CreateDirectRoomViewState, initialState: CreateDirectRoomViewState,
private val rawService: RawService,
private val session: Session) private val session: Session)
: VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction, CreateDirectRoomViewEvents>(initialState) { : VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction, CreateDirectRoomViewEvents>(initialState) {
@ -54,22 +61,28 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
} }
private fun createRoomAndInviteSelectedUsers(invitees: Set<PendingInvitee>) { private fun createRoomAndInviteSelectedUsers(invitees: Set<PendingInvitee>) {
val roomParams = CreateRoomParams() viewModelScope.launch(Dispatchers.IO) {
.apply { val adminE2EByDefault = rawService.getElementWellknown(session.myUserId)
invitees.forEach { ?.isE2EByDefault()
when (it) { ?: true
is PendingInvitee.UserPendingInvitee -> invitedUserIds.add(it.user.userId)
is PendingInvitee.ThreePidPendingInvitee -> invite3pids.add(it.threePid)
}.exhaustive
}
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = session.getHomeServerCapabilities().adminE2EByDefault
}
session.rx() val roomParams = CreateRoomParams()
.createRoom(roomParams) .apply {
.execute { invitees.forEach {
copy(createAndInviteState = it) when (it) {
} is PendingInvitee.UserPendingInvitee -> invitedUserIds.add(it.user.userId)
is PendingInvitee.ThreePidPendingInvitee -> invite3pids.add(it.threePid)
}.exhaustive
}
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
}
session.rx()
.createRoom(roomParams)
.execute {
copy(createAndInviteState = it)
}
}
} }
} }

View file

@ -42,6 +42,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder
import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory
import im.vector.app.features.home.room.typing.TypingHelper import im.vector.app.features.home.room.typing.TypingHelper
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorLocale
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable import io.reactivex.Observable
@ -58,6 +59,7 @@ import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.extensions.tryThis
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
@ -107,6 +109,7 @@ class RoomDetailViewModel @AssistedInject constructor(
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val rainbowGenerator: RainbowGenerator, private val rainbowGenerator: RainbowGenerator,
private val session: Session, private val session: Session,
private val rawService: RawService,
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider, private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
private val stickerPickerActionHandler: StickerPickerActionHandler, private val stickerPickerActionHandler: StickerPickerActionHandler,
private val roomSummaryHolder: RoomSummaryHolder, private val roomSummaryHolder: RoomSummaryHolder,
@ -331,7 +334,12 @@ class RoomDetailViewModel @AssistedInject constructor(
val roomId: String = room.roomId val roomId: String = room.roomId
val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.toLowerCase(VectorLocale.applicationLocale) val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.toLowerCase(VectorLocale.applicationLocale)
val jitsiDomain = session.getHomeServerCapabilities().preferredJitsiDomain ?: stringProvider.getString(R.string.preferred_jitsi_domain) val preferredJitsiDomain = tryThis {
rawService.getElementWellknown(session.myUserId)
?.jitsiServer
?.preferredDomain
}
val jitsiDomain = preferredJitsiDomain ?: stringProvider.getString(R.string.preferred_jitsi_domain)
// We use the default element wrapper for this widget // We use the default element wrapper for this widget
// https://github.com/vector-im/element-web/blob/develop/docs/jitsi-dev.md // https://github.com/vector-im/element-web/blob/develop/docs/jitsi-dev.md

View file

@ -16,18 +16,43 @@
package im.vector.app.features.homeserver package im.vector.app.features.homeserver
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.app.core.di.HasScreenInjector import im.vector.app.core.di.HasScreenInjector
import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault
import im.vector.app.features.userdirectory.KnownUsersFragment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryThis
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
class HomeServerCapabilitiesViewModel(initialState: HomeServerCapabilitiesViewState) class HomeServerCapabilitiesViewModel @AssistedInject constructor(
: VectorViewModel<HomeServerCapabilitiesViewState, EmptyAction, EmptyViewEvents>(initialState) { @Assisted initialState: HomeServerCapabilitiesViewState,
private val session: Session,
private val rawService: RawService
) : VectorViewModel<HomeServerCapabilitiesViewState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel
}
companion object : MvRxViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> { companion object : MvRxViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel? {
val fragment: KnownUsersFragment = (viewModelContext as FragmentViewModelContext).fragment()
return fragment.homeServerCapabilitiesViewModelFactory.create(state)
}
override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState? { override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState? {
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getSafeActiveSession() val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getSafeActiveSession()
@ -37,5 +62,25 @@ class HomeServerCapabilitiesViewModel(initialState: HomeServerCapabilitiesViewSt
} }
} }
init {
initAdminE2eByDefault()
}
private fun initAdminE2eByDefault() {
viewModelScope.launch(Dispatchers.IO) {
val adminE2EByDefault = tryThis {
rawService.getElementWellknown(session.myUserId)
?.isE2EByDefault()
?: true
} ?: true
setState {
copy(
isE2EByDefault = adminE2EByDefault
)
}
}
}
override fun handle(action: EmptyAction) {} override fun handle(action: EmptyAction) {}
} }

View file

@ -20,5 +20,6 @@ import com.airbnb.mvrx.MvRxState
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
data class HomeServerCapabilitiesViewState( data class HomeServerCapabilitiesViewState(
val capabilities: HomeServerCapabilities = HomeServerCapabilities() val capabilities: HomeServerCapabilities = HomeServerCapabilities(),
val isE2EByDefault: Boolean = true
) : MvRxState ) : MvRxState

View file

@ -0,0 +1,55 @@
/*
* 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.app.features.raw.wellknown
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ElementWellKnown(
/**
* Preferred Jitsi domain
*/
@Json(name = "im.vector.riot.jitsi")
val jitsiServer: WellKnownPreferredConfig? = null,
/**
* The settings above were first proposed under a im.vector.riot.e2ee key, which is now deprecated.
* Element will check for either key, preferring io.element.e2ee if both exist.
*/
@Json(name = "io.element.e2ee")
val elementE2E: E2EWellKnownConfig? = null,
@Json(name = "im.vector.riot.e2ee")
val riotE2E: E2EWellKnownConfig? = null
)
@JsonClass(generateAdapter = true)
data class E2EWellKnownConfig(
/**
* Option to allow homeserver admins to set the default E2EE behaviour back to disabled for DMs / private rooms
* (as it was before) for various environments where this is desired.
*/
@Json(name = "default")
val e2eDefault: Boolean? = null
)
@JsonClass(generateAdapter = true)
data class WellKnownPreferredConfig(
@Json(name = "preferredDomain")
val preferredDomain: String? = null
)

View file

@ -0,0 +1,27 @@
/*
* 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.app.features.raw.wellknown
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.internal.util.awaitCallback
suspend fun RawService.getElementWellknown(userId: String): ElementWellKnown? {
return awaitCallback<String> { getWellknown(userId, it) }
.let { ElementWellKnownMapper.from(it) }
}
fun ElementWellKnown.isE2EByDefault() = elementE2E?.e2eDefault ?: riotE2E?.e2eDefault ?: true

View file

@ -0,0 +1,29 @@
/*
* 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.app.features.raw.wellknown
import com.squareup.moshi.JsonAdapter
import org.matrix.android.sdk.internal.di.MoshiProvider
object ElementWellKnownMapper {
val adapter: JsonAdapter<ElementWellKnown> = MoshiProvider.providesMoshi().adapter(ElementWellKnown::class.java)
fun from(value: String): ElementWellKnown? {
return adapter.fromJson(value)
}
}

View file

@ -17,6 +17,7 @@
package im.vector.app.features.roomdirectory.createroom package im.vector.app.features.roomdirectory.createroom
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Loading
@ -27,15 +28,22 @@ import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault
import im.vector.app.features.roomdirectory.RoomDirectoryActivity import im.vector.app.features.roomdirectory.RoomDirectoryActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.extensions.tryThis
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateRoomViewState, class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateRoomViewState,
private val session: Session private val session: Session,
private val rawService: RawService
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, EmptyViewEvents>(initialState) { ) : VectorViewModel<CreateRoomViewState, CreateRoomAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory @AssistedInject.Factory
@ -44,11 +52,25 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
} }
init { init {
setState { initAdminE2eByDefault()
copy( }
isEncrypted = !this.isPublic && session.getHomeServerCapabilities().adminE2EByDefault,
hsAdminHasDisabledE2E = !session.getHomeServerCapabilities().adminE2EByDefault private var adminE2EByDefault = true
)
private fun initAdminE2eByDefault() {
viewModelScope.launch(Dispatchers.IO) {
adminE2EByDefault = tryThis {
rawService.getElementWellknown(session.myUserId)
?.isE2EByDefault()
?: true
} ?: true
setState {
copy(
isEncrypted = !isPublic && adminE2EByDefault,
hsAdminHasDisabledE2E = !adminE2EByDefault
)
}
} }
} }
@ -81,7 +103,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
private fun setIsPublic(action: CreateRoomAction.SetIsPublic) = setState { private fun setIsPublic(action: CreateRoomAction.SetIsPublic) = setState {
copy( copy(
isPublic = action.isPublic, isPublic = action.isPublic,
isEncrypted = !action.isPublic && session.getHomeServerCapabilities().adminE2EByDefault isEncrypted = !action.isPublic && adminE2EByDefault
) )
} }

View file

@ -80,9 +80,6 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
override var titleRes = R.string.settings_general_title override var titleRes = R.string.settings_general_title
override val preferenceXmlRes = R.xml.vector_settings_general override val preferenceXmlRes = R.xml.vector_settings_general
private var mDisplayedEmails = ArrayList<String>()
private var mDisplayedPhoneNumber = ArrayList<String>()
private var avatarCameraUri: Uri? = null private var avatarCameraUri: Uri? = null
private val mUserSettingsCategory by lazy { private val mUserSettingsCategory by lazy {

View file

@ -56,6 +56,8 @@ import im.vector.app.features.pin.PinActivity
import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.PinCodeStore
import im.vector.app.features.pin.PinLocker import im.vector.app.features.pin.PinLocker
import im.vector.app.features.pin.PinMode import im.vector.app.features.pin.PinMode
import im.vector.app.features.raw.wellknown.ElementWellKnownMapper
import im.vector.app.features.raw.wellknown.isE2EByDefault
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
@ -151,8 +153,14 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
disposables.add(it) disposables.add(it)
} }
val e2eByDefault = session.getHomeServerCapabilities().adminE2EByDefault vectorActivity.getVectorComponent()
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible = !e2eByDefault .rawService()
.getWellknown(session.myUserId, object : MatrixCallback<String> {
override fun onSuccess(data: String) {
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible =
ElementWellKnownMapper.from(data)?.isE2EByDefault() == false
}
})
} }
private val secureBackupCategory by lazy { private val secureBackupCategory by lazy {
@ -273,8 +281,6 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
text = getString(R.string.settings_hs_admin_e2e_disabled) text = getString(R.string.settings_hs_admin_e2e_disabled)
textColor = ContextCompat.getColor(requireContext(), R.color.riotx_destructive_accent) textColor = ContextCompat.getColor(requireContext(), R.color.riotx_destructive_accent)
} }
it.isVisible = session.getHomeServerCapabilities().adminE2EByDefault
} }
} }

View file

@ -29,7 +29,6 @@ import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.jakewharton.rxbinding3.widget.textChanges import com.jakewharton.rxbinding3.widget.textChanges
import org.matrix.android.sdk.api.session.user.model.User
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.configureWith
@ -39,12 +38,14 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
import kotlinx.android.synthetic.main.fragment_known_users.* import kotlinx.android.synthetic.main.fragment_known_users.*
import org.matrix.android.sdk.api.session.user.model.User
import javax.inject.Inject import javax.inject.Inject
class KnownUsersFragment @Inject constructor( class KnownUsersFragment @Inject constructor(
val userDirectoryViewModelFactory: UserDirectoryViewModel.Factory, val userDirectoryViewModelFactory: UserDirectoryViewModel.Factory,
private val knownUsersController: KnownUsersController, private val knownUsersController: KnownUsersController,
private val dimensionConverter: DimensionConverter private val dimensionConverter: DimensionConverter,
val homeServerCapabilitiesViewModelFactory: HomeServerCapabilitiesViewModel.Factory
) : VectorBaseFragment(), KnownUsersController.Callback { ) : VectorBaseFragment(), KnownUsersController.Callback {
private val args: KnownUsersFragmentArgs by args() private val args: KnownUsersFragmentArgs by args()
@ -71,7 +72,7 @@ class KnownUsersFragment @Inject constructor(
setupCloseView() setupCloseView()
homeServerCapabilitiesViewModel.subscribe { homeServerCapabilitiesViewModel.subscribe {
knownUsersE2EbyDefaultDisabled.isVisible = !it.capabilities.adminE2EByDefault knownUsersE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault
} }
viewModel.selectSubscribe(this, UserDirectoryViewState::pendingInvitees) { viewModel.selectSubscribe(this, UserDirectoryViewState::pendingInvitees) {