Wire compute room shields with rust

This commit is contained in:
Valere 2021-10-29 15:24:18 +02:00
parent ae635e2b0a
commit f209ae26bc
30 changed files with 1867 additions and 1573 deletions

2
.gitignore vendored
View file

@ -20,3 +20,5 @@ Cargo.lock
/fastlane/report.xml /fastlane/report.xml
/library/build /library/build
matrix-sdk-android/src/main/jniLibs/

View file

@ -35,13 +35,11 @@ import org.matrix.android.sdk.internal.crypto.OutgoingRoomKeyRequest
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.internal.crypto.model.MXDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.MXEncryptEventContentResult import org.matrix.android.sdk.internal.crypto.model.MXEncryptEventContentResult
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse
import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody
interface CryptoService { interface CryptoService {
@ -153,4 +151,11 @@ interface CryptoService {
* send, in order to speed up sending of the message. * send, in order to speed up sending of the message.
*/ */
fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>) fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>)
/**
* When LL all room members might not be loaded when setting up encryption.
* This is called after room members have been loaded
* ... not sure if shoud be API
*/
fun onE2ERoomMemberLoadedFromServer(roomId: String)
} }

View file

@ -19,6 +19,7 @@ package org.matrix.android.sdk.api.session.crypto.crosssigning
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustResult import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustResult
import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult
@ -104,6 +105,8 @@ interface CrossSigningService {
fun trustDevice(deviceId: String, fun trustDevice(deviceId: String,
callback: MatrixCallback<Unit>) callback: MatrixCallback<Unit>)
suspend fun shieldForGroup(userIds: List<String>) : RoomEncryptionTrustLevel
/** /**
* Check if a device is trusted * Check if a device is trusted
* *

View file

@ -27,7 +27,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningServic
import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.api.CryptoApi
import org.matrix.android.sdk.internal.crypto.crosssigning.ComputeTrustTask import org.matrix.android.sdk.internal.crypto.crosssigning.ComputeTrustTask
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultComputeTrustTask import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultComputeTrustTask
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DefaultCreateKeysBackupVersionTask import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DefaultCreateKeysBackupVersionTask
@ -96,6 +95,11 @@ import org.matrix.android.sdk.internal.di.UserMd5
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.session.cache.ClearCacheTask import org.matrix.android.sdk.internal.session.cache.ClearCacheTask
import org.matrix.android.sdk.internal.session.cache.RealmClearCacheTask import org.matrix.android.sdk.internal.session.cache.RealmClearCacheTask
import io.realm.RealmConfiguration
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.internal.crypto.verification.RustVerificationService
import retrofit2.Retrofit import retrofit2.Retrofit
import java.io.File import java.io.File
@ -238,7 +242,10 @@ internal abstract class CryptoModule {
abstract fun bindClaimOneTimeKeysForUsersDeviceTask(task: DefaultClaimOneTimeKeysForUsersDevice): ClaimOneTimeKeysForUsersDeviceTask abstract fun bindClaimOneTimeKeysForUsersDeviceTask(task: DefaultClaimOneTimeKeysForUsersDevice): ClaimOneTimeKeysForUsersDeviceTask
@Binds @Binds
abstract fun bindCrossSigningService(service: DefaultCrossSigningService): CrossSigningService abstract fun bindCrossSigningService(service: RustCrossSigningService): CrossSigningService
@Binds
abstract fun bindVerificationService(service: RustVerificationService): VerificationService
@Binds @Binds
abstract fun bindCryptoStore(store: RealmCryptoStore): IMXCryptoStore abstract fun bindCryptoStore(store: RealmCryptoStore): IMXCryptoStore

View file

@ -17,13 +17,21 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventEntityFields import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.database.query.whereType import org.matrix.android.sdk.internal.database.query.whereType
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
import org.matrix.android.sdk.internal.util.fetchCopied import org.matrix.android.sdk.internal.util.fetchCopied
import org.matrix.android.sdk.internal.util.logLimit
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -31,7 +39,8 @@ import javax.inject.Inject
* in the session DB, this class encapsulate this functionality * in the session DB, this class encapsulate this functionality
*/ */
internal class CryptoSessionInfoProvider @Inject constructor( internal class CryptoSessionInfoProvider @Inject constructor(
@SessionDatabase private val monarchy: Monarchy @SessionDatabase private val monarchy: Monarchy,
@UserId private val myUserId: String
) { ) {
fun isRoomEncrypted(roomId: String): Boolean { fun isRoomEncrypted(roomId: String): Boolean {
@ -47,7 +56,7 @@ internal class CryptoSessionInfoProvider @Inject constructor(
/** /**
* @param allActive if true return joined as well as invited, if false, only joined * @param allActive if true return joined as well as invited, if false, only joined
*/ */
fun getRoomUserIds(roomId: String, allActive: Boolean): List<String> { fun getRoomUserIds(roomId: String, allActive: Boolean): List<String> {
var userIds: List<String> = emptyList() var userIds: List<String> = emptyList()
monarchy.doWithRealm { realm -> monarchy.doWithRealm { realm ->
userIds = if (allActive) { userIds = if (allActive) {
@ -58,4 +67,41 @@ internal class CryptoSessionInfoProvider @Inject constructor(
} }
return userIds return userIds
} }
fun getUserListForShieldComputation(roomId: String): List<String> {
var userIds: List<String> = emptyList()
monarchy.doWithRealm { realm ->
userIds = RoomMemberHelper(realm, roomId).getActiveRoomMemberIds()
}
var isDirect = false
monarchy.doWithRealm { realm ->
isDirect = RoomSummaryEntity.where(realm, roomId = roomId).findFirst()?.isDirect == true
}
return if (isDirect || userIds.size <= 2) {
userIds.filter { it != myUserId }
} else {
userIds
}
}
fun getRoomsWhereUsersAreParticipating(userList: List<String>): List<String> {
var roomIds: List<String>? = null
monarchy.doWithRealm { sessionRealm ->
roomIds = sessionRealm.where(RoomMemberSummaryEntity::class.java)
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
.distinct(RoomMemberSummaryEntityFields.ROOM_ID)
.findAll()
.map { it.roomId }
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
}
return roomIds.orEmpty()
}
fun updateShieldForRoom(roomId: String, shield: RoomEncryptionTrustLevel) {
monarchy.writeAsync { realm ->
val summary = RoomSummaryEntity.where(realm, roomId = roomId).findFirst()
summary?.roomEncryptionTrustLevel = shield
}
}
} }

View file

@ -88,31 +88,17 @@ import org.matrix.android.sdk.internal.crypto.model.event.SecretSendEventContent
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse
import org.matrix.android.sdk.internal.crypto.model.rest.ForwardedRoomKeyContent import org.matrix.android.sdk.internal.crypto.model.rest.ForwardedRoomKeyContent
import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSigningKeysTask
import org.matrix.android.sdk.internal.crypto.verification.RustVerificationService import org.matrix.android.sdk.internal.crypto.verification.RustVerificationService
import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.SessionFilesDirectory
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.foldToCallback import org.matrix.android.sdk.internal.extensions.foldToCallback
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskExecutor
@ -120,235 +106,13 @@ import org.matrix.android.sdk.internal.task.TaskThread
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 timber.log.Timber import timber.log.Timber
import uniffi.olm.OutgoingVerificationRequest
import uniffi.olm.Request import uniffi.olm.Request
import uniffi.olm.RequestType import uniffi.olm.RequestType
import uniffi.olm.SignatureUploadRequest
import uniffi.olm.UploadSigningKeysRequest
import java.io.File
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
internal class RequestSender @Inject constructor(
private val sendToDeviceTask: SendToDeviceTask,
private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask,
private val uploadKeysTask: UploadKeysTask,
private val downloadKeysForUsersTask: DownloadKeysForUsersTask,
private val signaturesUploadTask: UploadSignaturesTask,
private val sendVerificationMessageTask: Lazy<DefaultSendVerificationMessageTask>,
private val uploadSigningKeysTask: UploadSigningKeysTask,
private val getKeysBackupLastVersionTask: GetKeysBackupLastVersionTask,
private val getKeysBackupVersionTask: GetKeysBackupVersionTask,
private val deleteBackupTask: DeleteBackupTask,
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
private val backupRoomKeysTask: StoreSessionsDataTask,
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
private val getSessionsDataTask: GetSessionsDataTask,
private val getRoomSessionsDataTask: GetRoomSessionsDataTask,
private val getRoomSessionDataTask: GetRoomSessionDataTask,
) {
companion object {
const val REQUEST_RETRY_COUNT = 3
}
suspend fun claimKeys(request: Request.KeysClaim): String {
val claimParams = ClaimOneTimeKeysForUsersDeviceTask.Params(request.oneTimeKeys)
val response = oneTimeKeysForUsersDeviceTask.executeRetry(claimParams, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider
.providesMoshi()
.adapter(KeysClaimResponse::class.java)
return adapter.toJson(response)!!
}
suspend fun queryKeys(request: Request.KeysQuery): String {
val params = DownloadKeysForUsersTask.Params(request.users, null)
val response = downloadKeysForUsersTask.executeRetry(params, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider.providesMoshi().adapter(KeysQueryResponse::class.java)
return adapter.toJson(response)!!
}
suspend fun uploadKeys(request: Request.KeysUpload): String {
val body = MoshiProvider.providesMoshi().adapter<JsonDict>(Map::class.java).fromJson(request.body)!!
val params = UploadKeysTask.Params(body)
val response = uploadKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider.providesMoshi().adapter(KeysUploadResponse::class.java)
return adapter.toJson(response)!!
}
suspend fun sendVerificationRequest(request: OutgoingVerificationRequest) {
when (request) {
is OutgoingVerificationRequest.InRoom -> sendRoomMessage(request)
is OutgoingVerificationRequest.ToDevice -> sendToDevice(request)
}
}
suspend fun sendRoomMessage(request: OutgoingVerificationRequest.InRoom): String {
return sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
}
suspend fun sendRoomMessage(request: Request.RoomMessage): String {
return sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
}
suspend fun sendRoomMessage(eventType: String, roomId: String, content: String, transactionId: String): String {
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java)
val jsonContent = adapter.fromJson(content)
val event = Event(eventType, transactionId, jsonContent, roomId = roomId)
val params = SendVerificationMessageTask.Params(event)
return this.sendVerificationMessageTask.get().executeRetry(params, REQUEST_RETRY_COUNT)
}
suspend fun sendSignatureUpload(request: Request.SignatureUpload) {
sendSignatureUpload(request.body)
}
suspend fun sendSignatureUpload(request: SignatureUploadRequest) {
sendSignatureUpload(request.body)
}
private suspend fun sendSignatureUpload(body: String) {
val adapter = MoshiProvider.providesMoshi().adapter<Map<String, Map<String, Any>>>(Map::class.java)
val signatures = adapter.fromJson(body)!!
val params = UploadSignaturesTask.Params(signatures)
this.signaturesUploadTask.executeRetry(params, REQUEST_RETRY_COUNT)
}
suspend fun uploadCrossSigningKeys(
request: UploadSigningKeysRequest,
interactiveAuthInterceptor: UserInteractiveAuthInterceptor?
) {
val adapter = MoshiProvider.providesMoshi().adapter(RestKeyInfo::class.java)
val masterKey = adapter.fromJson(request.masterKey)!!.toCryptoModel()
val selfSigningKey = adapter.fromJson(request.selfSigningKey)!!.toCryptoModel()
val userSigningKey = adapter.fromJson(request.userSigningKey)!!.toCryptoModel()
val uploadSigningKeysParams = UploadSigningKeysTask.Params(
masterKey,
userSigningKey,
selfSigningKey,
null
)
try {
uploadSigningKeysTask.execute(uploadSigningKeysParams)
} catch (failure: Throwable) {
if (interactiveAuthInterceptor == null
|| !handleUIA(
failure = failure,
interceptor = interactiveAuthInterceptor,
retryBlock = { authUpdate ->
uploadSigningKeysTask.executeRetry(
uploadSigningKeysParams.copy(userAuthParam = authUpdate),
REQUEST_RETRY_COUNT
)
}
)
) {
Timber.d("## UIA: propagate failure")
throw failure
}
}
}
suspend fun sendToDevice(request: Request.ToDevice) {
sendToDevice(request.eventType, request.body, request.requestId)
}
suspend fun sendToDevice(request: OutgoingVerificationRequest.ToDevice) {
sendToDevice(request.eventType, request.body, request.requestId)
}
suspend fun sendToDevice(eventType: String, body: String, transactionId: String) {
val adapter = MoshiProvider
.providesMoshi()
.newBuilder()
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
.build()
.adapter<Map<String, HashMap<String, Any>>>(Map::class.java)
val jsonBody = adapter.fromJson(body)!!
val userMap = MXUsersDevicesMap<Any>()
userMap.join(jsonBody)
val sendToDeviceParams = SendToDeviceTask.Params(eventType, userMap, transactionId)
sendToDeviceTask.executeRetry(sendToDeviceParams, REQUEST_RETRY_COUNT)
}
suspend fun getKeyBackupVersion(version: String? = null): KeysVersionResult? {
return try {
if (version != null) {
getKeysBackupVersionTask.execute(version)
} else {
getKeysBackupLastVersionTask.execute(Unit)
}
} catch (failure: Throwable) {
if (failure is Failure.ServerError
&& failure.error.code == MatrixError.M_NOT_FOUND) {
null
} else {
throw failure
}
}
}
suspend fun createKeyBackup(body: CreateKeysBackupVersionBody): KeysVersion {
return createKeysBackupVersionTask.execute(body)
}
suspend fun deleteKeyBackup(version: String) {
val params = DeleteBackupTask.Params(version)
deleteBackupTask.execute(params)
}
suspend fun backupRoomKeys(request: Request.KeysBackup): String {
val adapter = MoshiProvider
.providesMoshi()
.newBuilder()
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
.build()
.adapter<MutableMap<String, RoomKeysBackupData>>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
RoomKeysBackupData::class.java
))
val keys = adapter.fromJson(request.rooms)!!
val params = StoreSessionsDataTask.Params(request.version, KeysBackupData(keys))
val response = backupRoomKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
val responseAdapter = MoshiProvider.providesMoshi().adapter(BackupKeysResult::class.java)
return responseAdapter.toJson(response)!!
}
suspend fun updateBackup(keysBackupVersion: KeysVersionResult, body: UpdateKeysBackupVersionBody) {
val params = UpdateKeysBackupVersionTask.Params(keysBackupVersion.version, body)
updateKeysBackupVersionTask.executeRetry(params, REQUEST_RETRY_COUNT)
}
suspend fun downloadBackedUpKeys(version: String, roomId: String, sessionId: String): KeysBackupData {
val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version))
return KeysBackupData(mutableMapOf(
roomId to RoomKeysBackupData(mutableMapOf(
sessionId to data
))
))
}
suspend fun downloadBackedUpKeys(version: String, roomId: String): KeysBackupData {
val data = getRoomSessionsDataTask.execute(GetRoomSessionsDataTask.Params(roomId, version))
// Convert to KeysBackupData
return KeysBackupData(mutableMapOf(roomId to data))
}
suspend fun downloadBackedUpKeys(version: String): KeysBackupData {
return getSessionsDataTask.execute(GetSessionsDataTask.Params(version))
}
}
/** /**
* A `CryptoService` class instance manages the end-to-end crypto for a session. * A `CryptoService` class instance manages the end-to-end crypto for a session.
* *
@ -365,8 +129,10 @@ internal class DefaultCryptoService @Inject constructor(
private val userId: String, private val userId: String,
@DeviceId @DeviceId
private val deviceId: String?, private val deviceId: String?,
@SessionFilesDirectory // @SessionId
private val dataDir: File, // private val sessionId: String,
// @SessionFilesDirectory
// private val dataDir: File,
// the crypto store // the crypto store
private val cryptoStore: IMXCryptoStore, private val cryptoStore: IMXCryptoStore,
// Set of parameters used to configure/customize the end-to-end crypto. // Set of parameters used to configure/customize the end-to-end crypto.
@ -384,18 +150,20 @@ internal class DefaultCryptoService @Inject constructor(
private val taskExecutor: TaskExecutor, private val taskExecutor: TaskExecutor,
private val cryptoCoroutineScope: CoroutineScope, private val cryptoCoroutineScope: CoroutineScope,
private val sender: RequestSender, private val sender: RequestSender,
private val crossSigningService: CrossSigningService,
private val verificationService: RustVerificationService,
private val olmMachineProvider: OlmMachineProvider
) : CryptoService { ) : CryptoService {
private val isStarting = AtomicBoolean(false) private val isStarting = AtomicBoolean(false)
private val isStarted = AtomicBoolean(false) private val isStarted = AtomicBoolean(false)
private var olmMachine: OlmMachine? = null private val olmMachine by lazy { olmMachineProvider.olmMachine }
// The verification service. // The verification service.
private var verificationService: RustVerificationService? = null // private var verificationService: RustVerificationService? = null
// The cross signing service. // private val deviceObserver: DeviceUpdateObserver = DeviceUpdateObserver()
private var crossSigningService: RustCrossSigningService? = null
// The key backup service. // The key backup service.
private var keysBackupService: RustKeyBackupService? = null private var keysBackupService: RustKeyBackupService? = null
@ -410,7 +178,7 @@ internal class DefaultCryptoService @Inject constructor(
// TODO does this need to be concurrent? // TODO does this need to be concurrent?
private val newSessionListeners = ArrayList<NewSessionListener>() private val newSessionListeners = ArrayList<NewSessionListener>()
suspend fun onStateEvent(roomId: String, event: Event) { fun onStateEvent(roomId: String, event: Event) {
when (event.getClearType()) { when (event.getClearType()) {
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
@ -418,12 +186,14 @@ internal class DefaultCryptoService @Inject constructor(
} }
} }
suspend fun onLiveEvent(roomId: String, event: Event) { fun onLiveEvent(roomId: String, event: Event) {
when (event.getClearType()) { when (event.getClearType()) {
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
else -> this.verificationService?.onEvent(event) else -> cryptoCoroutineScope.launch {
this@DefaultCryptoService.verificationService?.onEvent(event)
}
} }
} }
@ -463,7 +233,7 @@ internal class DefaultCryptoService @Inject constructor(
} }
override fun getMyDevice(): CryptoDeviceInfo { override fun getMyDevice(): CryptoDeviceInfo {
return runBlocking { olmMachine!!.ownDevice() } return runBlocking { olmMachine.ownDevice() }
} }
override fun fetchDevicesList(callback: MatrixCallback<DevicesListResponse>) { override fun fetchDevicesList(callback: MatrixCallback<DevicesListResponse>) {
@ -565,14 +335,10 @@ internal class DefaultCryptoService @Inject constructor(
try { try {
setRustLogger() setRustLogger()
val machine = OlmMachine(userId, deviceId!!, dataDir, deviceObserver, sender)
olmMachine = machine
verificationService = RustVerificationService(machine)
crossSigningService = RustCrossSigningService(machine)
keysBackupService = RustKeyBackupService(machine, sender, coroutineDispatchers, cryptoCoroutineScope) keysBackupService = RustKeyBackupService(machine, sender, coroutineDispatchers, cryptoCoroutineScope)
Timber.v( Timber.v(
"## CRYPTO | Successfully started up an Olm machine for " + "## CRYPTO | Successfully started up an Olm machine for " +
"${userId}, ${deviceId}, identity keys: ${this.olmMachine?.identityKeys()}") "${userId}, ${deviceId}, identity keys: ${this.olmMachine.identityKeys()}")
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
Timber.v("Failed create an Olm machine: $throwable") Timber.v("Failed create an Olm machine: $throwable")
} }
@ -614,38 +380,9 @@ internal class DefaultCryptoService @Inject constructor(
/** /**
* @return the VerificationService * @return the VerificationService
*/ */
override fun verificationService(): VerificationService { override fun verificationService() = verificationService
// TODO yet another problem because the CryptoService is started in the
// sync loop
//
// The `KeyRequestHandler` and `IncomingVerificationHandler` want to add
// listeners to the verification service, they are initialized in the
// `ActiveSessionHolder` class in the `setActiveSession()` method. In
// the `setActiveSession()` method we call the `start()` method of the
// handlers without first calling the `start()` method of the
// `DefaultCryptoService`.
//
// The start method of the crypto service isn't part of the
// `CryptoService` interface so it currently can't be called there. I'm
// inclined to believe that it should be, and that it should be
// initialized before anything else tries to do something with it.
//
// Let's initialize here as a workaround until we figure out if the
// above conclusion is correct.
if (verificationService == null) {
internalStart()
}
return verificationService!! override fun crossSigningService() = crossSigningService
}
override fun crossSigningService(): CrossSigningService {
if (crossSigningService == null) {
internalStart()
}
return crossSigningService!!
}
/** /**
* A sync response has been received * A sync response has been received
@ -685,7 +422,7 @@ internal class DefaultCryptoService @Inject constructor(
override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? {
return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) { return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) {
runBlocking { runBlocking {
this@DefaultCryptoService.olmMachine?.getCryptoDeviceInfo(userId, deviceId) this@DefaultCryptoService.olmMachine.getCryptoDeviceInfo(userId, deviceId)
} }
} else { } else {
null null
@ -694,7 +431,7 @@ internal class DefaultCryptoService @Inject constructor(
override fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> { override fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> {
return runBlocking { return runBlocking {
this@DefaultCryptoService.olmMachine?.getCryptoDeviceInfo(userId) ?: listOf() this@DefaultCryptoService.olmMachine.getCryptoDeviceInfo(userId) ?: listOf()
} }
} }
@ -704,7 +441,7 @@ internal class DefaultCryptoService @Inject constructor(
override fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>> { override fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>> {
return runBlocking { return runBlocking {
this@DefaultCryptoService.olmMachine?.getLiveDevices(userIds) ?: LiveDevice(userIds, deviceObserver) this@DefaultCryptoService.olmMachine.getLiveDevices(userIds) //?: LiveDevice(userIds, deviceObserver)
} }
} }
@ -755,7 +492,7 @@ internal class DefaultCryptoService @Inject constructor(
Timber.v("Enabling encryption in $roomId for the first time; invalidating device lists for all users therein") Timber.v("Enabling encryption in $roomId for the first time; invalidating device lists for all users therein")
val userIds = ArrayList(membersId) val userIds = ArrayList(membersId)
olmMachine!!.updateTrackedUsers(userIds) olmMachine.updateTrackedUsers(userIds)
} }
return true return true
@ -833,7 +570,7 @@ internal class DefaultCryptoService @Inject constructor(
} }
override fun discardOutboundSession(roomId: String) { override fun discardOutboundSession(roomId: String) {
olmMachine?.discardRoomKey(roomId) olmMachine.discardRoomKey(roomId)
} }
/** /**
@ -846,7 +583,7 @@ internal class DefaultCryptoService @Inject constructor(
@Throws(MXCryptoError::class) @Throws(MXCryptoError::class)
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult { override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
return runBlocking { return runBlocking {
olmMachine!!.decryptRoomEvent(event) olmMachine.decryptRoomEvent(event)
} }
} }
@ -873,20 +610,29 @@ internal class DefaultCryptoService @Inject constructor(
Timber.w("Invalid encryption event") Timber.w("Invalid encryption event")
return return
} }
// Do not load members here, would defeat lazy loading
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val params = LoadRoomMembersTask.Params(roomId) // val params = LoadRoomMembersTask.Params(roomId)
try { // try {
loadRoomMembersTask.execute(params) // loadRoomMembersTask.execute(params)
} catch (throwable: Throwable) { // } catch (throwable: Throwable) {
Timber.e(throwable, "## CRYPTO | onRoomEncryptionEvent ERROR FAILED TO SETUP CRYPTO ") // Timber.e(throwable, "## CRYPTO | onRoomEncryptionEvent ERROR FAILED TO SETUP CRYPTO ")
} finally { // } finally {
val userIds = getRoomUserIds(roomId) val userIds = getRoomUserIds(roomId)
olmMachine!!.updateTrackedUsers(userIds) olmMachine.updateTrackedUsers(userIds)
setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), userIds) setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), userIds)
} // }
} }
} }
override fun onE2ERoomMemberLoadedFromServer(roomId: String) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val userIds = getRoomUserIds(roomId)
// Because of LL we might want to update tracked users
olmMachine.updateTrackedUsers(userIds)
}
}
private fun getRoomUserIds(roomId: String): List<String> { private fun getRoomUserIds(roomId: String): List<String> {
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser() && val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser() &&
shouldEncryptForInvitedMembers(roomId) shouldEncryptForInvitedMembers(roomId)
@ -898,7 +644,7 @@ internal class DefaultCryptoService @Inject constructor(
* *
* @param event the membership event causing the change * @param event the membership event causing the change
*/ */
private suspend fun onRoomMembershipEvent(roomId: String, event: Event) { private fun onRoomMembershipEvent(roomId: String, event: Event) {
// We only care about the memberships if this room is encrypted // We only care about the memberships if this room is encrypted
if (isRoomEncrypted(roomId)) { if (isRoomEncrypted(roomId)) {
return return
@ -909,7 +655,9 @@ internal class DefaultCryptoService @Inject constructor(
val membership = roomMember?.membership val membership = roomMember?.membership
if (membership == Membership.JOIN) { if (membership == Membership.JOIN) {
// make sure we are tracking the deviceList for this user. // make sure we are tracking the deviceList for this user.
olmMachine!!.updateTrackedUsers(listOf(userId)) cryptoCoroutineScope.launch {
olmMachine.updateTrackedUsers(listOf(userId))
}
} else if (membership == Membership.INVITE } else if (membership == Membership.INVITE
&& shouldEncryptForInvitedMembers(roomId) && shouldEncryptForInvitedMembers(roomId)
&& isEncryptionEnabledForInvitedUser()) { && isEncryptionEnabledForInvitedUser()) {
@ -918,7 +666,11 @@ internal class DefaultCryptoService @Inject constructor(
// know what other servers are in the room at the time they've been invited. // know what other servers are in the room at the time they've been invited.
// They therefore will not send device updates if a user logs in whilst // They therefore will not send device updates if a user logs in whilst
// their state is invite. // their state is invite.
olmMachine!!.updateTrackedUsers(listOf(userId)) cryptoCoroutineScope.launch {
olmMachine.updateTrackedUsers(listOf(userId))
}
} else {
// nop
} }
} }
} }
@ -952,7 +704,7 @@ internal class DefaultCryptoService @Inject constructor(
deviceChanges: DeviceListResponse?, deviceChanges: DeviceListResponse?,
keyCounts: DeviceOneTimeKeysCountSyncResponse?) { keyCounts: DeviceOneTimeKeysCountSyncResponse?) {
// Decrypt and handle our to-device events // Decrypt and handle our to-device events
val toDeviceEvents = this.olmMachine!!.receiveSyncChanges(toDevice, deviceChanges, keyCounts) val toDeviceEvents = this.olmMachine.receiveSyncChanges(toDevice, deviceChanges, keyCounts)
// Notify the our listeners about room keys so decryption is retried. // Notify the our listeners about room keys so decryption is retried.
if (toDeviceEvents.events != null) { if (toDeviceEvents.events != null) {
@ -981,7 +733,7 @@ internal class DefaultCryptoService @Inject constructor(
this.keysBackupService?.onSecretKeyGossip(secretContent.secretValue) this.keysBackupService?.onSecretKeyGossip(secretContent.secretValue)
} }
else -> { else -> {
this.verificationService?.onEvent(event) this.verificationService.onEvent(event)
} }
} }
} }
@ -990,7 +742,7 @@ internal class DefaultCryptoService @Inject constructor(
private suspend fun preshareRoomKey(roomId: String, roomMembers: List<String>) { private suspend fun preshareRoomKey(roomId: String, roomMembers: List<String>) {
keyClaimLock.withLock { keyClaimLock.withLock {
val request = this.olmMachine!!.getMissingSessions(roomMembers) val request = this.olmMachine.getMissingSessions(roomMembers)
// This request can only be a keys claim request. // This request can only be a keys claim request.
if (request != null) { if (request != null) {
when (request) { when (request) {
@ -1008,7 +760,7 @@ internal class DefaultCryptoService @Inject constructor(
keyShareLock.withLock { keyShareLock.withLock {
coroutineScope { coroutineScope {
this@DefaultCryptoService.olmMachine!!.shareRoomKey(roomId, roomMembers).map { this@DefaultCryptoService.olmMachine.shareRoomKey(roomId, roomMembers).map {
when (it) { when (it) {
is Request.ToDevice -> { is Request.ToDevice -> {
sharedKey = true sharedKey = true
@ -1035,18 +787,28 @@ internal class DefaultCryptoService @Inject constructor(
} }
private suspend fun encrypt(roomId: String, eventType: String, content: Content): Content { private suspend fun encrypt(roomId: String, eventType: String, content: Content): Content {
return olmMachine!!.encrypt(roomId, eventType, content) return olmMachine.encrypt(roomId, eventType, content)
} }
private suspend fun uploadKeys(request: Request.KeysUpload) { private suspend fun uploadKeys(request: Request.KeysUpload) {
val response = this.sender.uploadKeys(request) val response = this.sender.uploadKeys(request)
this.olmMachine!!.markRequestAsSent(request.requestId, RequestType.KEYS_UPLOAD, response) this.olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_UPLOAD, response)
} }
private suspend fun queryKeys(request: Request.KeysQuery) { private suspend fun queryKeys(request: Request.KeysQuery) {
try { try {
val response = this.sender.queryKeys(request) val response = this.sender.queryKeys(request)
this.olmMachine!!.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response) this.olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response)
// Update the shields!
cryptoCoroutineScope.launch {
cryptoSessionInfoProvider.getRoomsWhereUsersAreParticipating(request.users).forEach { roomId ->
val userGroup = cryptoSessionInfoProvider.getUserListForShieldComputation(roomId)
val shield = crossSigningService.shieldForGroup(userGroup)
cryptoSessionInfoProvider.updateShieldForRoom(roomId, shield)
}
}
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error") Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
} }
@ -1054,23 +816,23 @@ internal class DefaultCryptoService @Inject constructor(
private suspend fun sendToDevice(request: Request.ToDevice) { private suspend fun sendToDevice(request: Request.ToDevice) {
this.sender.sendToDevice(request) this.sender.sendToDevice(request)
olmMachine!!.markRequestAsSent(request.requestId, RequestType.TO_DEVICE, "{}") olmMachine.markRequestAsSent(request.requestId, RequestType.TO_DEVICE, "{}")
} }
private suspend fun claimKeys(request: Request.KeysClaim) { private suspend fun claimKeys(request: Request.KeysClaim) {
val response = this.sender.claimKeys(request) val response = this.sender.claimKeys(request)
olmMachine!!.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response) olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response)
} }
private suspend fun signatureUpload(request: Request.SignatureUpload) { private suspend fun signatureUpload(request: Request.SignatureUpload) {
this.sender.sendSignatureUpload(request) this.sender.sendSignatureUpload(request)
olmMachine!!.markRequestAsSent(request.requestId, RequestType.SIGNATURE_UPLOAD, "{}") olmMachine.markRequestAsSent(request.requestId, RequestType.SIGNATURE_UPLOAD, "{}")
} }
private suspend fun sendOutgoingRequests() { private suspend fun sendOutgoingRequests() {
outgoingRequestsLock.withLock { outgoingRequestsLock.withLock {
coroutineScope { coroutineScope {
olmMachine!!.outgoingRequests().map { olmMachine.outgoingRequests().map {
when (it) { when (it) {
is Request.KeysUpload -> { is Request.KeysUpload -> {
async { async {
@ -1122,7 +884,7 @@ internal class DefaultCryptoService @Inject constructor(
*/ */
override suspend fun exportRoomKeys(password: String): ByteArray { override suspend fun exportRoomKeys(password: String): ByteArray {
val iterationCount = max(10000, MXMegolmExportEncryption.DEFAULT_ITERATION_COUNT) val iterationCount = max(10000, MXMegolmExportEncryption.DEFAULT_ITERATION_COUNT)
return olmMachine!!.exportKeys(password, iterationCount) return olmMachine.exportKeys(password, iterationCount)
} }
/** /**
@ -1234,7 +996,7 @@ internal class DefaultCryptoService @Inject constructor(
*/ */
override fun reRequestRoomKeyForEvent(event: Event) { override fun reRequestRoomKeyForEvent(event: Event) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val requestPair = olmMachine!!.requestRoomKey(event) val requestPair = olmMachine.requestRoomKey(event)
val cancellation = requestPair.cancellation val cancellation = requestPair.cancellation
val request = requestPair.keyRequest val request = requestPair.keyRequest
@ -1279,9 +1041,9 @@ internal class DefaultCryptoService @Inject constructor(
if (forceDownload) { if (forceDownload) {
// TODO replicate the logic from the device list manager // TODO replicate the logic from the device list manager
// where we would download the fresh info from the server. // where we would download the fresh info from the server.
this@DefaultCryptoService.olmMachine?.getUserDevicesMap(userIds) ?: MXUsersDevicesMap() this@DefaultCryptoService.olmMachine.getUserDevicesMap(userIds) // ?: MXUsersDevicesMap()
} else { } else {
this@DefaultCryptoService.olmMachine?.getUserDevicesMap(userIds) ?: MXUsersDevicesMap() this@DefaultCryptoService.olmMachine.getUserDevicesMap(userIds) //?: MXUsersDevicesMap()
} }
}.foldToCallback(callback) }.foldToCallback(callback)
} }

View file

@ -39,7 +39,7 @@ internal class Device(
private val machine: OlmMachine, private val machine: OlmMachine,
private var inner: InnerDevice, private var inner: InnerDevice,
private val sender: RequestSender, private val sender: RequestSender,
private val listeners: ArrayList<VerificationService.Listener>, private val listeners: ArrayList<VerificationService.Listener>
) { ) {
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
private suspend fun refreshData() { private suspend fun refreshData() {

View file

@ -35,6 +35,7 @@ import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
// Legacy name: MXDeviceList // Legacy name: MXDeviceList
@Deprecated("In favor of rust olmMachine")
@SessionScope @SessionScope
internal class DeviceListManager @Inject constructor(private val cryptoStore: IMXCryptoStore, internal class DeviceListManager @Inject constructor(private val cryptoStore: IMXCryptoStore,
private val olmDevice: MXOlmDevice, private val olmDevice: MXOlmDevice,

View file

@ -22,6 +22,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.listeners.ProgressListener
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.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
@ -99,7 +100,7 @@ internal class LiveDevice(
internal class LiveUserIdentity( internal class LiveUserIdentity(
internal var userId: String, internal var userId: String,
private var observer: UserIdentityUpdateObserver, private var observer: UserIdentityUpdateObserver
) : MutableLiveData<Optional<MXCrossSigningInfo>>() { ) : MutableLiveData<Optional<MXCrossSigningInfo>>() {
override fun onActive() { override fun onActive() {
observer.addUserIdentityUpdateListener(this) observer.addUserIdentityUpdateListener(this)
@ -529,8 +530,13 @@ internal class OlmMachine(
return when (identity) { return when (identity) {
is RustUserIdentity.Other -> { is RustUserIdentity.Other -> {
val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel() val verified = this.inner().isIdentityVerified(userId)
val selfSigningKey = adapter.fromJson(identity.selfSigningKey)!!.toCryptoModel() val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply {
trustLevel = DeviceTrustLevel(verified, verified)
}
val selfSigningKey = adapter.fromJson(identity.selfSigningKey)!!.toCryptoModel().apply {
trustLevel = DeviceTrustLevel(verified, verified)
}
UserIdentity(identity.userId, masterKey, selfSigningKey, this, this.requestSender) UserIdentity(identity.userId, masterKey, selfSigningKey, this, this.requestSender)
} }

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2021 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.crypto
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.SessionScope
import java.io.File
import javax.inject.Inject
@SessionScope
internal class OlmMachineProvider @Inject constructor(
@UserId private val userId: String,
@DeviceId private val deviceId: String?,
@SessionFilesDirectory private val dataDir: File,
requestSender: RequestSender
) {
private val deviceObserver: DeviceUpdateObserver = DeviceUpdateObserver()
var olmMachine: OlmMachine = OlmMachine(userId, deviceId!!, dataDir, deviceObserver, requestSender)
}

View file

@ -37,7 +37,7 @@ internal class QrCodeVerification(
private var request: VerificationRequest, private var request: VerificationRequest,
private var inner: QrCode?, private var inner: QrCode?,
private val sender: RequestSender, private val sender: RequestSender,
listeners: ArrayList<VerificationService.Listener>, listeners: ArrayList<VerificationService.Listener>
) : QrCodeVerificationTransaction { ) : QrCodeVerificationTransaction {
private val dispatcher = UpdateDispatcher(listeners) private val dispatcher = UpdateDispatcher(listeners)

View file

@ -0,0 +1,282 @@
/*
* Copyright (c) 2021 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.crypto
import com.squareup.moshi.Types
import dagger.Lazy
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.auth.registration.handleUIA
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteBackupTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupLastVersionTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupVersionTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionDataTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionsDataTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetSessionsDataTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSigningKeysTask
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
import timber.log.Timber
import uniffi.olm.OutgoingVerificationRequest
import uniffi.olm.Request
import uniffi.olm.SignatureUploadRequest
import uniffi.olm.UploadSigningKeysRequest
import javax.inject.Inject
internal class RequestSender @Inject constructor(
private val sendToDeviceTask: SendToDeviceTask,
private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask,
private val uploadKeysTask: UploadKeysTask,
private val downloadKeysForUsersTask: DownloadKeysForUsersTask,
private val signaturesUploadTask: UploadSignaturesTask,
private val sendVerificationMessageTask: Lazy<DefaultSendVerificationMessageTask>,
private val uploadSigningKeysTask: UploadSigningKeysTask,
private val getKeysBackupLastVersionTask: GetKeysBackupLastVersionTask,
private val getKeysBackupVersionTask: GetKeysBackupVersionTask,
private val deleteBackupTask: DeleteBackupTask,
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
private val backupRoomKeysTask: StoreSessionsDataTask,
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
private val getSessionsDataTask: GetSessionsDataTask,
private val getRoomSessionsDataTask: GetRoomSessionsDataTask,
private val getRoomSessionDataTask: GetRoomSessionDataTask,
) {
companion object {
const val REQUEST_RETRY_COUNT = 3
}
suspend fun claimKeys(request: Request.KeysClaim): String {
val claimParams = ClaimOneTimeKeysForUsersDeviceTask.Params(request.oneTimeKeys)
val response = oneTimeKeysForUsersDeviceTask.executeRetry(claimParams, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider
.providesMoshi()
.adapter(KeysClaimResponse::class.java)
return adapter.toJson(response)!!
}
suspend fun queryKeys(request: Request.KeysQuery): String {
val params = DownloadKeysForUsersTask.Params(request.users, null)
val response = downloadKeysForUsersTask.executeRetry(params, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider.providesMoshi().adapter(KeysQueryResponse::class.java)
return adapter.toJson(response)!!
}
suspend fun uploadKeys(request: Request.KeysUpload): String {
val body = MoshiProvider.providesMoshi().adapter<JsonDict>(Map::class.java).fromJson(request.body)!!
val params = UploadKeysTask.Params(body)
val response = uploadKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider.providesMoshi().adapter(KeysUploadResponse::class.java)
return adapter.toJson(response)!!
}
suspend fun sendVerificationRequest(request: OutgoingVerificationRequest) {
when (request) {
is OutgoingVerificationRequest.InRoom -> sendRoomMessage(request)
is OutgoingVerificationRequest.ToDevice -> sendToDevice(request)
}
}
suspend fun sendRoomMessage(request: OutgoingVerificationRequest.InRoom): String {
return sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
}
suspend fun sendRoomMessage(request: Request.RoomMessage): String {
return sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
}
suspend fun sendRoomMessage(eventType: String, roomId: String, content: String, transactionId: String): String {
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java)
val jsonContent = adapter.fromJson(content)
val event = Event(eventType, transactionId, jsonContent, roomId = roomId)
val params = SendVerificationMessageTask.Params(event)
return this.sendVerificationMessageTask.get().executeRetry(params, REQUEST_RETRY_COUNT)
}
suspend fun sendSignatureUpload(request: Request.SignatureUpload) {
sendSignatureUpload(request.body)
}
suspend fun sendSignatureUpload(request: SignatureUploadRequest) {
sendSignatureUpload(request.body)
}
private suspend fun sendSignatureUpload(body: String) {
val adapter = MoshiProvider.providesMoshi().adapter<Map<String, Map<String, Any>>>(Map::class.java)
val signatures = adapter.fromJson(body)!!
val params = UploadSignaturesTask.Params(signatures)
this.signaturesUploadTask.executeRetry(params, REQUEST_RETRY_COUNT)
}
suspend fun uploadCrossSigningKeys(
request: UploadSigningKeysRequest,
interactiveAuthInterceptor: UserInteractiveAuthInterceptor?
) {
val adapter = MoshiProvider.providesMoshi().adapter(RestKeyInfo::class.java)
val masterKey = adapter.fromJson(request.masterKey)!!.toCryptoModel()
val selfSigningKey = adapter.fromJson(request.selfSigningKey)!!.toCryptoModel()
val userSigningKey = adapter.fromJson(request.userSigningKey)!!.toCryptoModel()
val uploadSigningKeysParams = UploadSigningKeysTask.Params(
masterKey,
userSigningKey,
selfSigningKey,
null
)
try {
uploadSigningKeysTask.execute(uploadSigningKeysParams)
} catch (failure: Throwable) {
if (interactiveAuthInterceptor == null
|| !handleUIA(
failure = failure,
interceptor = interactiveAuthInterceptor,
retryBlock = { authUpdate ->
uploadSigningKeysTask.executeRetry(
uploadSigningKeysParams.copy(userAuthParam = authUpdate),
REQUEST_RETRY_COUNT
)
}
)
) {
Timber.d("## UIA: propagate failure")
throw failure
}
}
}
suspend fun sendToDevice(request: Request.ToDevice) {
sendToDevice(request.eventType, request.body, request.requestId)
}
suspend fun sendToDevice(request: OutgoingVerificationRequest.ToDevice) {
sendToDevice(request.eventType, request.body, request.requestId)
}
suspend fun sendToDevice(eventType: String, body: String, transactionId: String) {
val adapter = MoshiProvider
.providesMoshi()
.newBuilder()
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
.build()
.adapter<Map<String, HashMap<String, Any>>>(Map::class.java)
val jsonBody = adapter.fromJson(body)!!
val userMap = MXUsersDevicesMap<Any>()
userMap.join(jsonBody)
val sendToDeviceParams = SendToDeviceTask.Params(eventType, userMap, transactionId)
sendToDeviceTask.executeRetry(sendToDeviceParams, REQUEST_RETRY_COUNT)
}
suspend fun getKeyBackupVersion(version: String? = null): KeysVersionResult? {
return try {
if (version != null) {
getKeysBackupVersionTask.execute(version)
} else {
getKeysBackupLastVersionTask.execute(Unit)
}
} catch (failure: Throwable) {
if (failure is Failure.ServerError
&& failure.error.code == MatrixError.M_NOT_FOUND) {
null
} else {
throw failure
}
}
}
suspend fun createKeyBackup(body: CreateKeysBackupVersionBody): KeysVersion {
return createKeysBackupVersionTask.execute(body)
}
suspend fun deleteKeyBackup(version: String) {
val params = DeleteBackupTask.Params(version)
deleteBackupTask.execute(params)
}
suspend fun backupRoomKeys(request: Request.KeysBackup): String {
val adapter = MoshiProvider
.providesMoshi()
.newBuilder()
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
.build()
.adapter<MutableMap<String, RoomKeysBackupData>>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
RoomKeysBackupData::class.java
))
val keys = adapter.fromJson(request.rooms)!!
val params = StoreSessionsDataTask.Params(request.version, KeysBackupData(keys))
val response = backupRoomKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
val responseAdapter = MoshiProvider.providesMoshi().adapter(BackupKeysResult::class.java)
return responseAdapter.toJson(response)!!
}
suspend fun updateBackup(keysBackupVersion: KeysVersionResult, body: UpdateKeysBackupVersionBody) {
val params = UpdateKeysBackupVersionTask.Params(keysBackupVersion.version, body)
updateKeysBackupVersionTask.executeRetry(params, REQUEST_RETRY_COUNT)
}
suspend fun downloadBackedUpKeys(version: String, roomId: String, sessionId: String): KeysBackupData {
val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version))
return KeysBackupData(mutableMapOf(
roomId to RoomKeysBackupData(mutableMapOf(
sessionId to data
))
))
}
suspend fun downloadBackedUpKeys(version: String, roomId: String): KeysBackupData {
val data = getRoomSessionsDataTask.execute(GetRoomSessionsDataTask.Params(roomId, version))
// Convert to KeysBackupData
return KeysBackupData(mutableMapOf(roomId to data))
}
suspend fun downloadBackedUpKeys(version: String): KeysBackupData {
return getSessionsDataTask.execute(GetSessionsDataTask.Params(version))
}
}

View file

@ -21,6 +21,8 @@ import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
@ -28,9 +30,18 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustResult
import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult
import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.foldToCallback import org.matrix.android.sdk.internal.extensions.foldToCallback
import javax.inject.Inject
internal class RustCrossSigningService(private val olmMachine: OlmMachine) : CrossSigningService { internal class RustCrossSigningService @Inject constructor(
@SessionId private val sessionId: String,
@UserId private val myUserId: String,
private val olmMachineProvider: OlmMachineProvider
) : CrossSigningService {
val olmMachine = olmMachineProvider.olmMachine
/** /**
* Is our own device signed by our own cross signing identity * Is our own device signed by our own cross signing identity
*/ */
@ -89,7 +100,9 @@ internal class RustCrossSigningService(private val olmMachine: OlmMachine) : Cro
sskPrivateKey: String? sskPrivateKey: String?
): UserTrustResult { ): UserTrustResult {
val export = PrivateKeysInfo(masterKeyPrivateKey, sskPrivateKey, uskKeyPrivateKey) val export = PrivateKeysInfo(masterKeyPrivateKey, sskPrivateKey, uskKeyPrivateKey)
return runBlocking { olmMachine.importCrossSigningKeys(export) } return runBlocking {
olmMachineProvider.olmMachine.importCrossSigningKeys(export)
}
} }
/** /**
@ -206,4 +219,46 @@ internal class RustCrossSigningService(private val olmMachine: OlmMachine) : Cro
override fun onSecretUSKGossip(uskPrivateKey: String) { override fun onSecretUSKGossip(uskPrivateKey: String) {
// And this. // And this.
} }
override suspend fun shieldForGroup(userIds: List<String>): RoomEncryptionTrustLevel {
val myIdentity = olmMachine.getIdentity(myUserId)
val allTrustedUserIds = userIds
.filter { userId ->
olmMachine.getIdentity(userId)?.verified() == true
}
return if (allTrustedUserIds.isEmpty()) {
RoomEncryptionTrustLevel.Default
} else {
// If one of the verified user as an untrusted device -> warning
// If all devices of all verified users are trusted -> green
// else -> black
allTrustedUserIds
.map { userId ->
olmMachineProvider.olmMachine.getUserDevices(userId)
}
.flatten()
.let { allDevices ->
if (myIdentity != null) {
allDevices.any { !it.toCryptoDeviceInfo().trustLevel?.crossSigningVerified.orFalse() }
} else {
// TODO check that if myIdentity is null ean
// Legacy method
allDevices.any { !it.toCryptoDeviceInfo().isVerified }
}
}
.let { hasWarning ->
if (hasWarning) {
RoomEncryptionTrustLevel.Warning
} else {
if (userIds.size == allTrustedUserIds.size) {
// all users are trusted and all devices are verified
RoomEncryptionTrustLevel.Trusted
} else {
RoomEncryptionTrustLevel.Default
}
}
}
}
}
} }

View file

@ -37,7 +37,7 @@ internal class SasVerification(
private val machine: OlmMachine, private val machine: OlmMachine,
private var inner: Sas, private var inner: Sas,
private val sender: RequestSender, private val sender: RequestSender,
listeners: ArrayList<VerificationService.Listener>, listeners: ArrayList<VerificationService.Listener>
) : ) :
SasVerificationTransaction { SasVerificationTransaction {
private val dispatcher = UpdateDispatcher(listeners) private val dispatcher = UpdateDispatcher(listeners)

View file

@ -250,7 +250,14 @@ internal class UserIdentity(
* Convert the identity into a MxCrossSigningInfo class. * Convert the identity into a MxCrossSigningInfo class.
*/ */
override fun toMxCrossSigningInfo(): MXCrossSigningInfo { override fun toMxCrossSigningInfo(): MXCrossSigningInfo {
val crossSigningKeys = listOf(this.masterKey, this.selfSigningKey) // val crossSigningKeys = listOf(this.masterKey, this.selfSigningKey)
return MXCrossSigningInfo(this.userId, crossSigningKeys) val trustLevel = DeviceTrustLevel(runBlocking { verified() }, false)
// TODO remove this, this is silly, we have way too many methods to check if a user is verified
masterKey.trustLevel = trustLevel
selfSigningKey.trustLevel = trustLevel
return MXCrossSigningInfo(this.userId, listOf(
this.masterKey.also { it.trustLevel = trustLevel },
this.selfSigningKey.also { it.trustLevel = trustLevel }
))
} }
} }

View file

@ -45,7 +45,7 @@ internal class VerificationRequest(
private val machine: OlmMachine, private val machine: OlmMachine,
private var inner: VerificationRequest, private var inner: VerificationRequest,
private val sender: RequestSender, private val sender: RequestSender,
private val listeners: ArrayList<VerificationService.Listener>, private val listeners: ArrayList<VerificationService.Listener>
) { ) {
private val uiHandler = Handler(Looper.getMainLooper()) private val uiHandler = Handler(Looper.getMainLooper())

View file

@ -24,7 +24,6 @@ import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimBody
import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryBody import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryBody
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadBody
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
import org.matrix.android.sdk.internal.crypto.model.rest.SendToDeviceBody import org.matrix.android.sdk.internal.crypto.model.rest.SendToDeviceBody
import org.matrix.android.sdk.internal.crypto.model.rest.SignatureUploadResponse import org.matrix.android.sdk.internal.crypto.model.rest.SignatureUploadResponse

View file

@ -1,347 +1,389 @@
/* // /*
* Copyright 2020 The Matrix.org Foundation C.I.C. // * Copyright 2020 The Matrix.org Foundation C.I.C.
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* http://www.apache.org/licenses/LICENSE-2.0 // * http://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
//
package org.matrix.android.sdk.internal.crypto.crosssigning // package org.matrix.android.sdk.internal.crypto.crosssigning
//
import android.content.Context // import android.content.Context
import androidx.work.WorkerParameters // import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass // import com.squareup.moshi.JsonClass
import io.realm.Realm // import io.realm.Realm
import io.realm.RealmConfiguration // import io.realm.RealmConfiguration
import io.realm.kotlin.where // import io.realm.kotlin.where
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel // import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.extensions.orFalse // import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo // import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore // import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper // import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity // import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields // import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper // import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity // import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity // import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields // import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
import org.matrix.android.sdk.internal.database.awaitTransaction // import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity // import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields // import org.matrix.android.sdk.internal.database.awaitTransaction
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity // import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields // import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.query.where // import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.di.CryptoDatabase // import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.di.SessionDatabase // import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.UserId // import org.matrix.android.sdk.internal.di.CryptoDatabase
import org.matrix.android.sdk.internal.session.SessionComponent // import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper // import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.util.logLimit // import org.matrix.android.sdk.internal.session.SessionComponent
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker // import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
import org.matrix.android.sdk.internal.worker.SessionWorkerParams // import org.matrix.android.sdk.internal.util.logLimit
import timber.log.Timber // import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
import javax.inject.Inject // import org.matrix.android.sdk.internal.worker.SessionWorkerParams
// import timber.log.Timber
internal class UpdateTrustWorker(context: Context, // import javax.inject.Inject
params: WorkerParameters) : //
SessionSafeCoroutineWorker<UpdateTrustWorker.Params>(context, params, Params::class.java) { // @Deprecated("Now using olm machine")
// internal class UpdateTrustWorker(context: Context,
@JsonClass(generateAdapter = true) // params: WorkerParameters)
internal data class Params( // : SessionSafeCoroutineWorker<UpdateTrustWorker.Params>(context, params, Params::class.java) {
override val sessionId: String, //
override val lastFailureMessage: String? = null, // @JsonClass(generateAdapter = true)
// Kept for compatibility, but not used anymore (can be used for pending Worker) // internal data class Params(
val updatedUserIds: List<String>? = null, // override val sessionId: String,
// Passing a long list of userId can break the Work Manager due to data size limitation. // override val lastFailureMessage: String? = null,
// so now we use a temporary file to store the data // // Kept for compatibility, but not used anymore (can be used for pending Worker)
val filename: String? = null // val updatedUserIds: List<String>? = null,
) : SessionWorkerParams // // Passing a long list of userId can break the Work Manager due to data size limitation.
// // so now we use a temporary file to store the data
@Inject lateinit var crossSigningService: DefaultCrossSigningService // val filename: String? = null
// ) : SessionWorkerParams
// It breaks the crypto store contract, but we need to batch things :/ //
@CryptoDatabase // // @Inject lateinit var crossSigningService: RustCrossSigningService
@Inject lateinit var cryptoRealmConfiguration: RealmConfiguration // @Inject lateinit var olmMachineProvider: OlmMachineProvider//: RustCrossSigningService
//
@SessionDatabase // // It breaks the crypto store contract, but we need to batch things :/
@Inject lateinit var sessionRealmConfiguration: RealmConfiguration // @CryptoDatabase
// @Inject lateinit var cryptoRealmConfiguration: RealmConfiguration
@UserId //
@Inject lateinit var myUserId: String // @SessionDatabase
@Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper // @Inject lateinit var sessionRealmConfiguration: RealmConfiguration
@Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository //
// @UserId
// @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater // @Inject lateinit var myUserId: String
@Inject lateinit var cryptoStore: IMXCryptoStore // @Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper
// @Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
override fun injectWith(injector: SessionComponent) { //
injector.inject(this) // // @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater
} // @Inject lateinit var cryptoStore: IMXCryptoStore
//
override suspend fun doSafeWork(params: Params): Result { // override fun injectWith(injector: SessionComponent) {
val userList = params.filename // injector.inject(this)
?.let { updateTrustWorkerDataRepository.getParam(it) } // }
?.userIds //
?: params.updatedUserIds.orEmpty() // override suspend fun doSafeWork(params: Params): Result {
// val userList = params.filename
// List should not be empty, but let's avoid go further in case of empty list // ?.let { updateTrustWorkerDataRepository.getParam(it) }
if (userList.isNotEmpty()) { // ?.userIds
// Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user, // ?: params.updatedUserIds.orEmpty()
// or a new device?) So we check all again :/ //
Timber.d("## CrossSigning - Updating trust for users: ${userList.logLimit()}") // // List should not be empty, but let's avoid go further in case of empty list
updateTrust(userList) // if (userList.isNotEmpty()) {
} // // Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user,
// // or a new device?) So we check all again :/
cleanup(params) // Timber.d("## CrossSigning - Updating trust for users: ${userList.logLimit()}")
return Result.success() // updateTrust(userList)
} // }
//
private suspend fun updateTrust(userListParam: List<String>) { // cleanup(params)
var userList = userListParam // return Result.success()
var myCrossSigningInfo: MXCrossSigningInfo? = null // }
//
// First we check that the users MSK are trusted by mine // private suspend fun updateTrust(userListParam: List<String>) {
// After that we check the trust chain for each devices of each users // var userList = userListParam
awaitTransaction(cryptoRealmConfiguration) { cryptoRealm -> // var myCrossSigningInfo: MXCrossSigningInfo? = null
// By mapping here to model, this object is not live //
// I should update it if needed // // First we check that the users MSK are trusted by mine
myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId) // // After that we check the trust chain for each devices of each users
// awaitTransaction(cryptoRealmConfiguration) { cryptoRealm ->
var myTrustResult: UserTrustResult? = null // // By mapping here to model, this object is not live
// // I should update it if needed
if (userList.contains(myUserId)) { // myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
Timber.d("## CrossSigning - Clear all trust as a change on my user was detected") //
// i am in the list.. but i don't know exactly the delta of change :/ // var myTrustResult: UserTrustResult? = null
// If it's my cross signing keys we should refresh all trust //
// do it anyway ? // if (userList.contains(myUserId)) {
userList = cryptoRealm.where(CrossSigningInfoEntity::class.java) // Timber.d("## CrossSigning - Clear all trust as a change on my user was detected")
.findAll() // // i am in the list.. but i don't know exactly the delta of change :/
.mapNotNull { it.userId } // // If it's my cross signing keys we should refresh all trust
// // do it anyway ?
// check right now my keys and mark it as trusted as other trust depends on it // userList = cryptoRealm.where(CrossSigningInfoEntity::class.java)
val myDevices = cryptoRealm.where<UserEntity>() // .findAll()
.equalTo(UserEntityFields.USER_ID, myUserId) // .mapNotNull { it.userId }
.findFirst() //
?.devices // // check right now my keys and mark it as trusted as other trust depends on it
?.map { CryptoMapper.mapToModel(it) } // // val myDevices = olmMachineProvider.olmMachine.getUserDevices(myUserId)
// // cryptoRealm.where<UserEntity>()
myTrustResult = crossSigningService.checkSelfTrust(myCrossSigningInfo, myDevices) // // .equalTo(UserEntityFields.USER_ID, myUserId)
updateCrossSigningKeysTrust(cryptoRealm, myUserId, myTrustResult.isVerified()) // // .findFirst()
// update model reference // // ?.devices
myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId) // // ?.map { CryptoMapper.mapToModel(it) }
} //
//
val otherInfos = userList.associateWith { userId -> // val identity = olmMachineProvider.olmMachine.getIdentity(olmMachineProvider.olmMachine.userId())
getCrossSigningInfo(cryptoRealm, userId) // myTrustResult = if (identity?.verified() == true) {
} // UserTrustResult.Success
// } else {
val trusts = otherInfos.mapValues { entry -> // if (identity?.toMxCrossSigningInfo() == null) {
when (entry.key) { // UserTrustResult.CrossSigningNotConfigured(olmMachineProvider.olmMachine.userId())
myUserId -> myTrustResult // } else {
else -> { // UserTrustResult.KeysNotTrusted(identity.toMxCrossSigningInfo())
crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also { // }
Timber.d("## CrossSigning - user:${entry.key} result:$it") // }
} //
} // // crossSigningService.checkSelfTrust(myCrossSigningInfo, myDevices)
} // updateCrossSigningKeysTrust(cryptoRealm, myUserId, myTrustResult.isVerified())
} // // update model reference
// myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
// TODO! if it's me and my keys has changed... I have to reset trust for everyone! // }
// i have all the new trusts, update DB //
trusts.forEach { // val otherInfos = userList.associateWith { userId ->
val verified = it.value?.isVerified() == true // getCrossSigningInfo(cryptoRealm, userId)
updateCrossSigningKeysTrust(cryptoRealm, it.key, verified) // }
} //
// val trusts = otherInfos.mapValues { entry ->
// Ok so now we have to check device trust for all these users.. // when (entry.key) {
Timber.v("## CrossSigning - Updating devices cross trust users: ${trusts.keys.logLimit()}") // myUserId -> myTrustResult
trusts.keys.forEach { userId -> // else -> {
val devicesEntities = cryptoRealm.where<UserEntity>() // val userId = entry.value?.userId ?: ""
.equalTo(UserEntityFields.USER_ID, userId) // val identity = olmMachineProvider.olmMachine.getIdentity(userId)
.findFirst() // if (identity?.verified() == true) {
?.devices // UserTrustResult.Success
// } else {
val trustMap = devicesEntities?.associateWith { device -> // if (identity?.toMxCrossSigningInfo() == null) {
// get up to date from DB has could have been updated // UserTrustResult.CrossSigningNotConfigured(userId)
val otherInfo = getCrossSigningInfo(cryptoRealm, userId) // } else {
crossSigningService.checkDeviceTrust(myCrossSigningInfo, otherInfo, CryptoMapper.mapToModel(device)) // UserTrustResult.KeysNotTrusted(identity.toMxCrossSigningInfo())
} // }
// }
// Update trust if needed // }
devicesEntities?.forEach { device -> // }
val crossSignedVerified = trustMap?.get(device)?.isCrossSignedVerified() // }
Timber.d("## CrossSigning - Trust for ${device.userId}|${device.deviceId} : cross verified: ${trustMap?.get(device)}") //
if (device.trustLevelEntity?.crossSignedVerified != crossSignedVerified) { // // TODO! if it's me and my keys has changed... I have to reset trust for everyone!
Timber.d("## CrossSigning - Trust change detected for ${device.userId}|${device.deviceId} : cross verified: $crossSignedVerified") // // i have all the new trusts, update DB
// need to save // // trusts.forEach {
val trustEntity = device.trustLevelEntity // // val verified = it.value?.isVerified() == true
if (trustEntity == null) { // // updateCrossSigningKeysTrust(cryptoRealm, it.key, verified)
device.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also { // // }
it.locallyVerified = false //
it.crossSignedVerified = crossSignedVerified // // Ok so now we have to check device trust for all these users..
} // Timber.v("## CrossSigning - Updating devices cross trust users: ${trusts.keys.logLimit()}")
} else { // trusts.keys.forEach { userId ->
trustEntity.crossSignedVerified = crossSignedVerified // val devicesEntities = olmMachineProvider.olmMachine.getUserDevices(userId)
} // // cryptoRealm.where<UserEntity>()
} // // .equalTo(UserEntityFields.USER_ID, userId)
} // // .findFirst()
} // // ?.devices
} //
// val trustMap = devicesEntities.associateWith { device ->
// So Cross Signing keys trust is updated, device trust is updated // // val cryptoDevice = device.toCryptoDeviceInfo()
// We can now update room shields? in the session DB? // // get up to date from DB has could have been updated
updateTrustStep2(userList, myCrossSigningInfo) // // val otherInfo = getCrossSigningInfo(cryptoRealm, userId)
} // // val deviceId = device.i deviceId ?: ""
// // val device = olmMachineProvider.olmMachine.getDevice(userId, deviceId)
private suspend fun updateTrustStep2(userList: List<String>, myCrossSigningInfo: MXCrossSigningInfo?) { // // if (device != null) {
Timber.d("## CrossSigning - Updating shields for impacted rooms...") // // TODO i don't quite understand the semantics here and there are no docs for
awaitTransaction(sessionRealmConfiguration) { sessionRealm -> // // DeviceTrustResult, what do the different result types mean exactly,
Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm -> // // do you return success only if the Device is cross signing verified?
sessionRealm.where(RoomMemberSummaryEntity::class.java) // // what about the local trust if it isn't? why is the local trust passed as an argument here?
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray()) // DeviceTrustResult.Success(runBlocking { device.trustLevel() })
.distinct(RoomMemberSummaryEntityFields.ROOM_ID) // // } else {
.findAll() // // DeviceTrustResult.UnknownDevice(deviceId)
.map { it.roomId } // // }
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") } // // crossSigningService.checkDeviceTrust(myCrossSigningInfo, otherInfo, CryptoMapper.mapToModel(device))
.forEach { roomId -> // }
RoomSummaryEntity.where(sessionRealm, roomId) //
.equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true) // // Update trust if needed
.findFirst() // // devicesEntities?.forEach { device ->
?.let { roomSummary -> // // val crossSignedVerified = trustMap?.get(device)?.isCrossSignedVerified()
Timber.d("## CrossSigning - Check shield state for room $roomId") // // Timber.d("## CrossSigning - Trust for ${device.userId}|${device.deviceId} : cross verified: ${trustMap?.get(device)}")
val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds() // // if (device.trustLevelEntity?.crossSignedVerified != crossSignedVerified) {
try { // // Timber.d("## CrossSigning - Trust change detected for ${device.userId}|${device.deviceId} : cross verified: $crossSignedVerified")
val updatedTrust = computeRoomShield( // // // need to save
myCrossSigningInfo, // // val trustEntity = device.trustLevelEntity
cryptoRealm, // // if (trustEntity == null) {
allActiveRoomMembers, // // device.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
roomSummary // // it.locallyVerified = false
) // // it.crossSignedVerified = crossSignedVerified
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) { // // }
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust") // // } else {
roomSummary.roomEncryptionTrustLevel = updatedTrust // // trustEntity.crossSignedVerified = crossSignedVerified
} // // }
} catch (failure: Throwable) { // // }
Timber.e(failure) // // }
} // }
} // }
} //
} // // So Cross Signing keys trust is updated, device trust is updated
} // // We can now update room shields? in the session DB?
} // updateTrustStep2(userList, myCrossSigningInfo)
// }
private fun getCrossSigningInfo(cryptoRealm: Realm, userId: String): MXCrossSigningInfo? { //
return cryptoRealm.where(CrossSigningInfoEntity::class.java) // private suspend fun updateTrustStep2(userList: List<String>, myCrossSigningInfo: MXCrossSigningInfo?) {
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId) // Timber.d("## CrossSigning - Updating shields for impacted rooms...")
.findFirst() // awaitTransaction(sessionRealmConfiguration) { sessionRealm ->
?.let { mapCrossSigningInfoEntity(it) } // Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
} // sessionRealm.where(RoomMemberSummaryEntity::class.java)
// .`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
private fun cleanup(params: Params) { // .distinct(RoomMemberSummaryEntityFields.ROOM_ID)
params.filename // .findAll()
?.let { updateTrustWorkerDataRepository.delete(it) } // .map { it.roomId }
} // .also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
// .forEach { roomId ->
private fun updateCrossSigningKeysTrust(cryptoRealm: Realm, userId: String, verified: Boolean) { // RoomSummaryEntity.where(sessionRealm, roomId)
cryptoRealm.where(CrossSigningInfoEntity::class.java) // .equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true)
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId) // .findFirst()
.findFirst() // ?.let { roomSummary ->
?.crossSigningKeys // Timber.d("## CrossSigning - Check shield state for room $roomId")
?.forEach { info -> // val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds()
// optimization to avoid trigger updates when there is no change.. // try {
if (info.trustLevelEntity?.isVerified() != verified) { // val updatedTrust = computeRoomShield(
Timber.d("## CrossSigning - Trust change for $userId : $verified") // myCrossSigningInfo,
val level = info.trustLevelEntity // cryptoRealm,
if (level == null) { // allActiveRoomMembers,
info.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also { // roomSummary
it.locallyVerified = verified // )
it.crossSignedVerified = verified // if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
} // Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
} else { // roomSummary.roomEncryptionTrustLevel = updatedTrust
level.locallyVerified = verified // }
level.crossSignedVerified = verified // } catch (failure: Throwable) {
} // Timber.e(failure)
} // }
} // }
} // }
// }
private fun computeRoomShield(myCrossSigningInfo: MXCrossSigningInfo?, // }
cryptoRealm: Realm, // }
activeMemberUserIds: List<String>, //
roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel { // private suspend fun getCrossSigningInfo(cryptoRealm: Realm, userId: String): MXCrossSigningInfo? {
Timber.d("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> ${activeMemberUserIds.logLimit()}") // return olmMachineProvider.olmMachine.getIdentity(userId)?.toMxCrossSigningInfo()
// The set of “all users” depends on the type of room: // // cryptoRealm.where(CrossSigningInfoEntity::class.java)
// For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room // // .equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
// For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room // // .findFirst()
val listToCheck = if (roomSummaryEntity.isDirect || activeMemberUserIds.size <= 2) { // // ?.let { mapCrossSigningInfoEntity(it) }
activeMemberUserIds.filter { it != myUserId } // }
} else { //
activeMemberUserIds // private fun cleanup(params: Params) {
} // params.filename
// ?.let { updateTrustWorkerDataRepository.delete(it) }
val allTrustedUserIds = listToCheck // }
.filter { userId -> //
getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true // private fun updateCrossSigningKeysTrust(cryptoRealm: Realm, userId: String, verified: Boolean) {
} // cryptoRealm.where(CrossSigningInfoEntity::class.java)
// .equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
return if (allTrustedUserIds.isEmpty()) { // .findFirst()
RoomEncryptionTrustLevel.Default // ?.crossSigningKeys
} else { // ?.forEach { info ->
// If one of the verified user as an untrusted device -> warning // // optimization to avoid trigger updates when there is no change..
// If all devices of all verified users are trusted -> green // if (info.trustLevelEntity?.isVerified() != verified) {
// else -> black // Timber.d("## CrossSigning - Trust change for $userId : $verified")
allTrustedUserIds // val level = info.trustLevelEntity
.mapNotNull { userId -> // if (level == null) {
cryptoRealm.where<UserEntity>() // info.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
.equalTo(UserEntityFields.USER_ID, userId) // it.locallyVerified = verified
.findFirst() // it.crossSignedVerified = verified
?.devices // }
?.map { CryptoMapper.mapToModel(it) } // } else {
} // level.locallyVerified = verified
.flatten() // level.crossSignedVerified = verified
.let { allDevices -> // }
Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} devices ${allDevices.map { it.deviceId }.logLimit()}") // }
if (myCrossSigningInfo != null) { // }
allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() } // }
} else { //
// Legacy method // private suspend fun computeRoomShield(myCrossSigningInfo: MXCrossSigningInfo?,
allDevices.any { !it.isVerified } // cryptoRealm: Realm,
} // activeMemberUserIds: List<String>,
} // roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
.let { hasWarning -> // Timber.d("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> ${activeMemberUserIds.logLimit()}")
if (hasWarning) { // // The set of “all users” depends on the type of room:
RoomEncryptionTrustLevel.Warning // // For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
} else { // // For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
if (listToCheck.size == allTrustedUserIds.size) { // val listToCheck = if (roomSummaryEntity.isDirect || activeMemberUserIds.size <= 2) {
// all users are trusted and all devices are verified // activeMemberUserIds.filter { it != myUserId }
RoomEncryptionTrustLevel.Trusted // } else {
} else { // activeMemberUserIds
RoomEncryptionTrustLevel.Default // }
} //
} // val allTrustedUserIds = listToCheck
} // .filter { userId ->
} // getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true
} // }
// Timber.d("## CrossSigning - allTrustedIds ${allTrustedUserIds}")
private fun mapCrossSigningInfoEntity(xsignInfo: CrossSigningInfoEntity): MXCrossSigningInfo { //
val userId = xsignInfo.userId ?: "" // return if (allTrustedUserIds.isEmpty()) {
return MXCrossSigningInfo( // RoomEncryptionTrustLevel.Default
userId = userId, // } else {
crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull { // // If one of the verified user as an untrusted device -> warning
crossSigningKeysMapper.map(userId, it) // // If all devices of all verified users are trusted -> green
} // // else -> black
) // allTrustedUserIds
} // .mapNotNull { userId ->
// // cryptoRealm.where<UserEntity>()
override fun buildErrorParams(params: Params, message: String): Params { // // .equalTo(UserEntityFields.USER_ID, userId)
return params.copy(lastFailureMessage = params.lastFailureMessage ?: message) // // .findFirst()
} // // ?.devices
} // // ?.map { CryptoMapper.mapToModel(it) }
// olmMachineProvider.olmMachine.getUserDevices(userId)
// }
// .flatten()
// .let { allDevices ->
// Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} devices ${allDevices.map { "${it.toCryptoDeviceInfo().deviceId} trust ${it.toCryptoDeviceInfo().trustLevel}" }.logLimit()}")
//
// if (myCrossSigningInfo != null) {
// allDevices.any { !it.toCryptoDeviceInfo().trustLevel?.crossSigningVerified.orFalse() }
// } else {
// // Legacy method
// allDevices.any { !it.toCryptoDeviceInfo().isVerified }
// }
// }
// .let { hasWarning ->
// if (hasWarning) {
// RoomEncryptionTrustLevel.Warning
// } else {
// if (listToCheck.size == allTrustedUserIds.size) {
// // all users are trusted and all devices are verified
// RoomEncryptionTrustLevel.Trusted
// } else {
// RoomEncryptionTrustLevel.Default
// }
// }
// }
// }
// }
//
// private fun mapCrossSigningInfoEntity(xsignInfo: CrossSigningInfoEntity): MXCrossSigningInfo {
// val userId = xsignInfo.userId ?: ""
// return MXCrossSigningInfo(
// userId = userId,
// crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull {
// crossSigningKeysMapper.map(userId, it)
// }
// )
// }
//
// override fun buildErrorParams(params: Params, message: String): Params {
// return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
// }
// }

View file

@ -24,8 +24,8 @@ import com.squareup.moshi.JsonClass
*/ */
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class KeysClaimResponse( internal data class KeysClaimResponse(
/// If any remote homeservers could not be reached, they are recorded here. // / If any remote homeservers could not be reached, they are recorded here.
/// The names of the properties are the names of the unreachable servers. // / The names of the properties are the names of the unreachable servers.
@Json(name = "failures") @Json(name = "failures")
val failures: Map<String, Any>, val failures: Map<String, Any>,

View file

@ -17,14 +17,11 @@
package org.matrix.android.sdk.internal.crypto.tasks package org.matrix.android.sdk.internal.crypto.tasks
import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.api.CryptoApi
import org.matrix.android.sdk.internal.crypto.model.MXKey
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimBody import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimBody
import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.task.Task
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysForUsersDeviceTask.Params, KeysClaimResponse> { internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysForUsersDeviceTask.Params, KeysClaimResponse> {

View file

@ -18,8 +18,6 @@ package org.matrix.android.sdk.internal.crypto.tasks
import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.api.CryptoApi
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeys
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadBody
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.network.executeRequest

View file

@ -16,8 +16,6 @@
package org.matrix.android.sdk.internal.crypto.verification package org.matrix.android.sdk.internal.crypto.verification
import android.os.Handler
import android.os.Looper
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -30,7 +28,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
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.room.model.message.MessageRelationContent import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.internal.crypto.OlmMachine import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
import org.matrix.android.sdk.internal.crypto.OwnUserIdentity import org.matrix.android.sdk.internal.crypto.OwnUserIdentity
import org.matrix.android.sdk.internal.crypto.SasVerification import org.matrix.android.sdk.internal.crypto.SasVerification
import org.matrix.android.sdk.internal.crypto.UserIdentity import org.matrix.android.sdk.internal.crypto.UserIdentity
@ -38,13 +36,15 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE
import org.matrix.android.sdk.internal.crypto.model.rest.toValue import org.matrix.android.sdk.internal.crypto.model.rest.toValue
import org.matrix.android.sdk.internal.session.SessionScope
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject
/** A helper class to deserialize to-device `m.key.verification.*` events to fetch the transaction id out */ /** A helper class to deserialize to-device `m.key.verification.*` events to fetch the transaction id out */
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class ToDeviceVerificationEvent( internal data class ToDeviceVerificationEvent(
@Json(name = "sender") val sender: String?, @Json(name = "sender") val sender: String?,
@Json(name = "transaction_id") val transactionId: String, @Json(name = "transaction_id") val transactionId: String
) )
/** Helper method to fetch the unique ID of the verification event */ /** Helper method to fetch the unique ID of the verification event */
@ -70,61 +70,13 @@ internal fun prepareMethods(methods: List<VerificationMethod>): List<String> {
return stringMethods return stringMethods
} }
/** Class that implements some common methods to dispatch updates for the verification related classes */ @SessionScope
internal class UpdateDispatcher(private val listeners: ArrayList<VerificationService.Listener>) { internal class RustVerificationService @Inject constructor(private val olmMachineProvider: OlmMachineProvider) : VerificationService {
private val uiHandler = Handler(Looper.getMainLooper())
internal fun addListener(listener: VerificationService.Listener) { val olmMachine by lazy {
uiHandler.post { olmMachineProvider.olmMachine
if (!this.listeners.contains(listener)) {
this.listeners.add(listener)
}
}
} }
internal fun removeListener(listener: VerificationService.Listener) {
uiHandler.post { this.listeners.remove(listener) }
}
internal fun dispatchTxAdded(tx: VerificationTransaction) {
uiHandler.post {
this.listeners.forEach {
try {
it.transactionCreated(tx)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
internal fun dispatchTxUpdated(tx: VerificationTransaction) {
uiHandler.post {
this.listeners.forEach {
try {
it.transactionUpdated(tx)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
internal fun dispatchRequestAdded(tx: PendingVerificationRequest) {
Timber.v("## SAS dispatchRequestAdded txId:${tx.transactionId} $tx")
uiHandler.post {
this.listeners.forEach {
try {
it.verificationRequestCreated(tx)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
}
internal class RustVerificationService(private val olmMachine: OlmMachine) : VerificationService {
private val dispatcher = UpdateDispatcher(this.olmMachine.verificationListeners) private val dispatcher = UpdateDispatcher(this.olmMachine.verificationListeners)
/** The main entry point for the verification service /** The main entry point for the verification service
@ -279,8 +231,8 @@ internal class RustVerificationService(private val olmMachine: OlmMachine) : Ver
): PendingVerificationRequest { ): PendingVerificationRequest {
val verification = when (val identity = runBlocking { olmMachine.getIdentity(otherUserId) }) { val verification = when (val identity = runBlocking { olmMachine.getIdentity(otherUserId) }) {
is OwnUserIdentity -> runBlocking { identity.requestVerification(methods) } is OwnUserIdentity -> runBlocking { identity.requestVerification(methods) }
is UserIdentity -> throw IllegalArgumentException("This method doesn't support verification of other users devices") is UserIdentity -> throw IllegalArgumentException("This method doesn't support verification of other users devices")
null -> throw IllegalArgumentException("Cross signing has not been bootstrapped for our own user") null -> throw IllegalArgumentException("Cross signing has not been bootstrapped for our own user")
} }
return verification.toPendingVerificationRequest() return verification.toPendingVerificationRequest()
@ -294,9 +246,9 @@ internal class RustVerificationService(private val olmMachine: OlmMachine) : Ver
): PendingVerificationRequest { ): PendingVerificationRequest {
Timber.i("## SAS Requesting verification to user: $otherUserId in room $roomId") Timber.i("## SAS Requesting verification to user: $otherUserId in room $roomId")
val verification = when (val identity = runBlocking { olmMachine.getIdentity(otherUserId) }) { val verification = when (val identity = runBlocking { olmMachine.getIdentity(otherUserId) }) {
is UserIdentity -> runBlocking { identity.requestVerification(methods, roomId, localId!!) } is UserIdentity -> runBlocking { identity.requestVerification(methods, roomId, localId!!) }
is OwnUserIdentity -> throw IllegalArgumentException("This method doesn't support verification of our own user") is OwnUserIdentity -> throw IllegalArgumentException("This method doesn't support verification of our own user")
null -> throw IllegalArgumentException("The user that we wish to verify doesn't support cross signing") null -> throw IllegalArgumentException("The user that we wish to verify doesn't support cross signing")
} }
return verification.toPendingVerificationRequest() return verification.toPendingVerificationRequest()

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2021 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.crypto.verification
import android.os.Handler
import android.os.Looper
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
import timber.log.Timber
/** Class that implements some common methods to dispatch updates for the verification related classes */
internal class UpdateDispatcher(private val listeners: ArrayList<VerificationService.Listener>) {
private val uiHandler = Handler(Looper.getMainLooper())
internal fun addListener(listener: VerificationService.Listener) {
uiHandler.post {
if (!this.listeners.contains(listener)) {
this.listeners.add(listener)
}
}
}
internal fun removeListener(listener: VerificationService.Listener) {
uiHandler.post { this.listeners.remove(listener) }
}
internal fun dispatchTxAdded(tx: VerificationTransaction) {
uiHandler.post {
this.listeners.forEach {
try {
it.transactionCreated(tx)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
internal fun dispatchTxUpdated(tx: VerificationTransaction) {
uiHandler.post {
this.listeners.forEach {
try {
it.transactionUpdated(tx)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
internal fun dispatchRequestAdded(tx: PendingVerificationRequest) {
Timber.v("## SAS dispatchRequestAdded txId:${tx.transactionId} $tx")
uiHandler.post {
this.listeners.forEach {
try {
it.verificationRequestCreated(tx)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
}

View file

@ -68,7 +68,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
isEncrypted = roomSummaryEntity.isEncrypted, isEncrypted = roomSummaryEntity.isEncrypted,
encryptionEventTs = roomSummaryEntity.encryptionEventTs, encryptionEventTs = roomSummaryEntity.encryptionEventTs,
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex, breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel, roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel.takeIf { roomSummaryEntity.isEncrypted },
inviterId = roomSummaryEntity.inviterId, inviterId = roomSummaryEntity.inviterId,
hasFailedSending = roomSummaryEntity.hasFailedSending, hasFailedSending = roomSummaryEntity.hasFailedSending,
roomType = roomSummaryEntity.roomType, roomType = roomSummaryEntity.roomType,

View file

@ -23,9 +23,9 @@ import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.crypto.CancelGossipRequestWorker import org.matrix.android.sdk.internal.crypto.CancelGossipRequestWorker
import org.matrix.android.sdk.internal.crypto.CryptoModule import org.matrix.android.sdk.internal.crypto.CryptoModule
import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
import org.matrix.android.sdk.internal.crypto.SendGossipRequestWorker import org.matrix.android.sdk.internal.crypto.SendGossipRequestWorker
import org.matrix.android.sdk.internal.crypto.SendGossipWorker import org.matrix.android.sdk.internal.crypto.SendGossipWorker
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
import org.matrix.android.sdk.internal.di.MatrixComponent import org.matrix.android.sdk.internal.di.MatrixComponent
import org.matrix.android.sdk.internal.federation.FederationModule import org.matrix.android.sdk.internal.federation.FederationModule
import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker
@ -117,6 +117,8 @@ internal interface SessionComponent {
fun taskExecutor(): TaskExecutor fun taskExecutor(): TaskExecutor
fun olmMachineProvider() : OlmMachineProvider
fun inject(worker: SendEventWorker) fun inject(worker: SendEventWorker)
fun inject(worker: MultipleEventSendingDispatcherWorker) fun inject(worker: MultipleEventSendingDispatcherWorker)
@ -137,7 +139,7 @@ internal interface SessionComponent {
fun inject(worker: SendGossipWorker) fun inject(worker: SendGossipWorker)
fun inject(worker: UpdateTrustWorker) // fun inject(worker: UpdateTrustWorker)
@Component.Factory @Component.Factory
interface Factory { interface Factory {

View file

@ -23,8 +23,8 @@ import org.matrix.android.sdk.api.session.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium import org.matrix.android.sdk.api.session.identity.toMedium
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.util.MimeTypes import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
@ -39,7 +39,8 @@ import javax.inject.Inject
internal class CreateRoomBodyBuilder @Inject constructor( internal class CreateRoomBodyBuilder @Inject constructor(
private val ensureIdentityTokenTask: EnsureIdentityTokenTask, private val ensureIdentityTokenTask: EnsureIdentityTokenTask,
private val deviceListManager: DeviceListManager, // private val deviceListManager: DeviceListManager,
private val olmMachineProvider: OlmMachineProvider,
private val identityStore: IdentityStore, private val identityStore: IdentityStore,
private val fileUploader: FileUploader, private val fileUploader: FileUploader,
@UserId @UserId
@ -173,14 +174,15 @@ internal class CreateRoomBodyBuilder @Inject constructor(
} }
private suspend fun canEnableEncryption(params: CreateRoomParams): Boolean { private suspend fun canEnableEncryption(params: CreateRoomParams): Boolean {
return params.enableEncryptionIfInvitedUsersSupportIt && return params.enableEncryptionIfInvitedUsersSupportIt
// Parity with web, enable if users have encryption ready devices // Parity with web, enable if users have encryption ready devices
// for now remove checks on cross signing and 3pid invites // for now remove checks on cross signing and 3pid invites
// && crossSigningService.isCrossSigningVerified() // && crossSigningService.isCrossSigningVerified()
params.invite3pids.isEmpty() && && params.invite3pids.isEmpty()
params.invitedUserIds.isNotEmpty() && && params.invitedUserIds.isNotEmpty()
params.invitedUserIds.let { userIds -> && params.invitedUserIds.let { userIds ->
val keys = deviceListManager.downloadKeys(userIds, forceDownload = false) val keys = olmMachineProvider.olmMachine.getUserDevicesMap(userIds)
// deviceListManager.downloadKeys(userIds, forceDownload = false)
userIds.all { userId -> userIds.all { userId ->
keys.map[userId].let { deviceMap -> keys.map[userId].let { deviceMap ->

View file

@ -17,13 +17,14 @@
package org.matrix.android.sdk.internal.session.room.membership package org.matrix.android.sdk.internal.session.room.membership
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import dagger.Lazy
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider
import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
@ -60,7 +61,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
private val roomSummaryUpdater: RoomSummaryUpdater, private val roomSummaryUpdater: RoomSummaryUpdater,
private val roomMemberEventHandler: RoomMemberEventHandler, private val roomMemberEventHandler: RoomMemberEventHandler,
private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
private val deviceListManager: DeviceListManager, private val cryptoService: Lazy<CryptoService>,
private val globalErrorReceiver: GlobalErrorReceiver private val globalErrorReceiver: GlobalErrorReceiver
) : LoadRoomMembersTask { ) : LoadRoomMembersTask {
@ -130,7 +131,10 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
} }
if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) { if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) {
deviceListManager.onRoomMembersLoadedFor(roomId) cryptoService.get().onE2ERoomMemberLoadedFromServer(roomId)
// val userIds = cryptoSessionInfoProvider.getRoomUserIds(roomId, true)
// olmMachineProvider.olmMachine.updateTrackedUsers(userIds)
// deviceListManager.onRoomMembersLoadedFor(roomId)
} }
} }

View file

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.summary
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
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.room.accountdata.RoomAccountDataTypes import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
@ -36,7 +37,6 @@ import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary
import org.matrix.android.sdk.api.session.sync.model.RoomSyncUnreadNotifications import org.matrix.android.sdk.api.session.sync.model.RoomSyncUnreadNotifications
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventEntity
@ -71,9 +71,8 @@ internal class RoomSummaryUpdater @Inject constructor(
@UserId private val userId: String, @UserId private val userId: String,
private val roomDisplayNameResolver: RoomDisplayNameResolver, private val roomDisplayNameResolver: RoomDisplayNameResolver,
private val roomAvatarResolver: RoomAvatarResolver, private val roomAvatarResolver: RoomAvatarResolver,
private val crossSigningService: DefaultCrossSigningService, private val crossSigningService: CrossSigningService,
private val roomAccountDataDataSource: RoomAccountDataDataSource, private val roomAccountDataDataSource: RoomAccountDataDataSource) {
private val normalizer: Normalizer) {
fun update(realm: Realm, fun update(realm: Realm,
roomId: String, roomId: String,
@ -168,8 +167,8 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummaryEntity.otherMemberIds.clear() roomSummaryEntity.otherMemberIds.clear()
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
if (roomSummaryEntity.isEncrypted && otherRoomMembers.isNotEmpty()) { if (roomSummaryEntity.isEncrypted && otherRoomMembers.isNotEmpty()) {
// mmm maybe we could only refresh shield instead of checking trust also? // TODO do we really need to force a shield refresh here?
crossSigningService.onUsersDeviceUpdate(otherRoomMembers) // crossSigningService.ensureRoomShieldForRoom(roomId)
} }
} }
} }

View file

@ -1,11 +1,19 @@
x86_64: # x86_64:
cargo build --release --target x86_64-linux-android # cargo build --release --target x86_64-linux-android
install -D target/x86_64-linux-android/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/x86_64/libuniffi_olm.so # mkdir -p ../matrix-sdk-android/src/main/jniLibs/x86_64/
# cp target/x86_64-linux-android/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/x86_64/libuniffi_olm.so
x86: x86:
cargo build --release --target i686-linux-android cargo build --release --target i686-linux-android
install -D target/i686-linux-android/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/x86/libuniffi_olm.so mkdir -p ../matrix-sdk-android/src/main/jniLibs/x86/
cp target/i686-linux-android/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/x86/libuniffi_olm.so
aarch64: aarch64:
cargo build --release --target aarch64-linux-android cargo build --release --target aarch64-linux-android
install -D target/aarch64-linux-android/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/arm64-v8a/libuniffi_olm.so mkdir -p ../matrix-sdk-android/src/main/jniLibs/arm64-v8a/
cp target/aarch64-linux-android/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/arm64-v8a/libuniffi_olm.so
armv7-linux-androideabi:
cargo build --release --target armv7-linux-androideabi
mkdir -p ../matrix-sdk-android/src/main/jniLibs/armeabi-v7a/
cp target/armv7-linux-androideabi/release/libmatrix_crypto.so ../matrix-sdk-android/src/main/jniLibs/armeabi-v7a/libuniffi_olm.so