From 52d9adad7009ee18d60f0050d2d073f6b1f8801d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 21 May 2019 15:42:09 +0200 Subject: [PATCH] WIP --- .../api/session/crypto/CryptoService.kt | 26 ++-- .../session/room/crypto/RoomCryptoService.kt | 11 +- .../room/members/RoomMembersService.kt | 14 -- .../android/internal/crypto/CryptoManager.kt | 124 ++++++++++-------- .../android/internal/crypto/CryptoModule.kt | 3 +- .../internal/crypto/DefaultCryptoService.kt | 22 ---- .../crypto/live/EnableEncryptionWorker.kt | 93 +++++++++++++ .../live/RealmLiveEncryptionObserver.kt | 55 ++++++++ .../internal/crypto/store/IMXCryptoStore.kt | 6 +- .../crypto/store/db/RealmCryptoStore.kt | 23 +++- .../crypto/store/db/model/CryptoRoomEntity.kt | 1 + .../database/RealmLiveEntityObserver.kt | 3 + .../database/query/EventEntityQueries.kt | 4 + .../android/internal/di/MoshiProvider.kt | 1 + .../internal/session/DefaultSession.kt | 25 +++- .../android/internal/session/SessionModule.kt | 4 +- .../internal/session/room/DefaultRoom.kt | 16 ++- .../internal/session/room/RoomFactory.kt | 7 +- .../internal/session/room/RoomModule.kt | 2 +- .../room/members/DefaultRoomMembersService.kt | 22 ---- .../session/room/members/RoomMembers.kt | 33 +++++ .../session/room/send/DefaultSendService.kt | 54 ++++++-- .../session/room/send/EncryptEventWorker.kt | 88 +++++++++++++ .../internal/session/sync/RoomSyncHandler.kt | 11 +- 24 files changed, 493 insertions(+), 155 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/EnableEncryptionWorker.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/RealmLiveEncryptionObserver.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt index 7e58fafe..c48035f9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt @@ -22,12 +22,15 @@ import im.vector.matrix.android.api.listeners.ProgressListener import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService +import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo -import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody +import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse +import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody interface CryptoService { @@ -57,7 +60,7 @@ interface CryptoService { fun getMyDevice(): MXDeviceInfo - fun getGlobalBlacklistUnverifiedDevices() : Boolean + fun getGlobalBlacklistUnverifiedDevices(): Boolean fun setGlobalBlacklistUnverifiedDevices(block: Boolean) @@ -83,6 +86,13 @@ interface CryptoService { fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int + fun isRoomEncrypted(roomId: String): Boolean + + fun encryptEventContent(eventContent: Content, + eventType: String, + room: Room, + callback: MatrixCallback) + /* fun start(isInitialSync: Boolean, aCallback: MatrixCallback?) @@ -92,14 +102,6 @@ interface CryptoService { fun close() - fun encryptEventContent(eventContent: Content, - eventType: String, - room: Room, - callback: MatrixCallback) - - fun onToDeviceEvent(event: Event) - - fun onSyncCompleted(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean) fun getOlmDevice(): MXOlmDevice? @@ -118,4 +120,8 @@ interface CryptoService { */ fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? + + fun getEncryptionAlgorithm(roomId: String): String? + + fun shouldEncryptForInvitedMembers(roomId: String): Boolean } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt index 52a139cf..910002ab 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt @@ -16,16 +16,11 @@ package im.vector.matrix.android.api.session.room.crypto -import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM - interface RoomCryptoService { - // TODO - fun isEncrypted(): Boolean = false + fun isEncrypted(): Boolean - // TODO - fun encryptionAlgorithm(): String? = MXCRYPTO_ALGORITHM_MEGOLM + fun encryptionAlgorithm(): String? - // TODO - fun shouldEncryptForInvitedMembers(): Boolean = false + fun shouldEncryptForInvitedMembers(): Boolean } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt index e04cebea..930afd7a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt @@ -54,18 +54,4 @@ interface RoomMembersService { */ fun invite(userId: String, callback: MatrixCallback) - /** - * Return all the roomMembers ids which are joined or invited to the room - * - * @return a roomMember id list of joined or invited members. - */ - fun getActiveRoomMemberIds(): List - - /** - * Return all the roomMembers ids which are joined to the room - * - * @return a roomMember id list of joined members. - */ - fun getJoinedRoomMemberIds(): List - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt index 94f8c0ce..28262683 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt @@ -35,8 +35,8 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.Room -import im.vector.matrix.android.api.session.room.RoomService -import im.vector.matrix.android.api.session.room.model.Membership +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibilityContent import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction import im.vector.matrix.android.internal.crypto.actions.MegolmSessionDataImporter import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction @@ -97,8 +97,6 @@ internal class CryptoManager( private val mIncomingRoomKeyRequestManager: IncomingRoomKeyRequestManager, // private val mOutgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager, - // Room service - private val mRoomService: RoomService, // Olm Manager private val mOlmManager: OlmManager, // Actions @@ -140,11 +138,23 @@ internal class CryptoManager( // } //} - fun onLiveEvent(roomId: String, event: Event) { + fun onStateEvent(roomId: String, event: Event) { if (event.type == EventType.ENCRYPTION) { - onRoomEncryptionEvent(roomId, event) + // TODO Remove onRoomEncryptionEvent(roomId, event) } else if (event.type == EventType.STATE_ROOM_MEMBER) { onRoomMembershipEvent(roomId, event) + } else if (event.type == EventType.STATE_HISTORY_VISIBILITY) { + onRoomHistoryVisibilityEvent(roomId, event) + } + } + + fun onLiveEvent(roomId: String, event: Event) { + if (event.type == EventType.ENCRYPTION) { + // TODO Remove onRoomEncryptionEvent(roomId, event) + } else if (event.type == EventType.STATE_ROOM_MEMBER) { + onRoomMembershipEvent(roomId, event) + } else if (event.type == EventType.STATE_HISTORY_VISIBILITY) { + onRoomHistoryVisibilityEvent(roomId, event) } } @@ -522,21 +532,15 @@ internal class CryptoManager( * @param roomId the room id * @return true if the room is encrypted */ - fun isRoomEncrypted(roomId: String?): Boolean { - var res = false + override fun isRoomEncrypted(roomId: String): Boolean { + var res: Boolean - if (null != roomId) { - synchronized(mRoomEncryptors) { - res = mRoomEncryptors.containsKey(roomId) + synchronized(mRoomEncryptors) { + res = mRoomEncryptors.containsKey(roomId) + } - if (!res) { - val room = mRoomService.getRoom(roomId) - - if (null != room) { - res = room.isEncrypted() - } - } - } + if (!res) { + res = !mCryptoStore.getRoomAlgorithm(roomId).isNullOrBlank() } return res @@ -564,6 +568,26 @@ internal class CryptoManager( mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, callback) } + fun isEncryptionEnabledForInvitedUser(): Boolean { + return mCryptoConfig.mEnableEncryptionForInvitedMembers + } + + override fun getEncryptionAlgorithm(roomId: String): String? { + return mCryptoStore.getRoomAlgorithm(roomId) + } + + /** + * Determine whether we should encrypt messages for invited users in this room. + *

+ * Check here whether the invited members are allowed to read messages in the room history + * from the point they were invited onwards. + * + * @return true if we should encrypt messages for invited users. + */ + override fun shouldEncryptForInvitedMembers(roomId: String): Boolean { + return mCryptoStore.shouldEncryptForInvitedMembers(roomId) + } + /** * Encrypt an event content according to the configuration of the room. * @@ -572,10 +596,10 @@ internal class CryptoManager( * @param room the room the event will be sent. * @param callback the asynchronous callback */ - fun encryptEventContent(eventContent: Content, - eventType: String, - room: Room, - callback: MatrixCallback) { + override fun encryptEventContent(eventContent: Content, + eventType: String, + room: Room, + callback: MatrixCallback) { // wait that the crypto is really started if (!isStarted()) { Timber.v("## encryptEventContent() : wait after e2e init") @@ -596,13 +620,15 @@ internal class CryptoManager( } // Check whether the event content must be encrypted for the invited members. - val encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers && room.shouldEncryptForInvitedMembers() + val encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers && shouldEncryptForInvitedMembers(room.roomId) - val userIds = if (encryptForInvitedMembers) { - room.getActiveRoomMemberIds() - } else { - room.getJoinedRoomMemberIds() - } + // TODO + //val userIds = if (encryptForInvitedMembers) { + // room.getActiveRoomMemberIds() + //} else { + // room.getJoinedRoomMemberIds() + //} + val userIds = emptyList() // just as you are sending a secret message? @@ -749,22 +775,8 @@ internal class CryptoManager( * * @param event the encryption event. */ - private fun onRoomEncryptionEvent(roomId: String, event: Event) { - // TODO Parse the event - val eventContent = event.content // wireEventContent - - val room = mRoomService.getRoom(roomId)!! - - // Check whether the event content must be encrypted for the invited members. - val encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers && room.shouldEncryptForInvitedMembers() - - val userIds = if (encryptForInvitedMembers) { - room.getActiveRoomMemberIds() - } else { - room.getJoinedRoomMemberIds() - } - - setEncryptionInRoom(roomId, eventContent!!["algorithm"] as String, true, userIds) + fun onRoomEncryptionEvent(event: Event, userIds: List) { + setEncryptionInRoom(event.roomId!!, event.content!!["algorithm"] as String, true, userIds) } /** @@ -785,6 +797,8 @@ internal class CryptoManager( } val userId = event.stateKey!! + + /* FIXME val room = mRoomService.getRoom(roomId) val roomMember = room?.getRoomMember(userId) @@ -796,7 +810,7 @@ internal class CryptoManager( // make sure we are tracking the deviceList for this user. deviceListManager.startTrackingDeviceList(Arrays.asList(userId)) } else if (membership == Membership.INVITE - && room.shouldEncryptForInvitedMembers() + && shouldEncryptForInvitedMembers(roomId) && mCryptoConfig.mEnableEncryptionForInvitedMembers) { // track the deviceList for this invited user. // Caution: there's a big edge case here in that federated servers do not @@ -806,8 +820,18 @@ internal class CryptoManager( deviceListManager.startTrackingDeviceList(Arrays.asList(userId)) } } + */ } + private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) { + val eventContent = event.content.toModel() + + eventContent?.historyVisibility?.let { + mCryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED) + } + } + + /** * Upload my user's device keys. * This method must called on getEncryptingThreadHandler() thread. @@ -996,6 +1020,7 @@ internal class CryptoManager( * @param roomId the room id * @return true if the client should encrypt messages only for the verified devices. */ + // TODO add this info in CryptoRoomEntity? override fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean { return if (null != roomId) { mCryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId) @@ -1011,13 +1036,6 @@ internal class CryptoManager( * @param add true to add the room id to the list, false to remove it. */ private fun setRoomBlacklistUnverifiedDevices(roomId: String, add: Boolean) { - val room = mRoomService.getRoom(roomId) - - // sanity check - if (null == room) { - return - } - val roomIds = mCryptoStore.getRoomsListBlacklistUnverifiedDevices().toMutableList() if (add) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt index bdf172d1..72f7fdc3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt @@ -80,7 +80,7 @@ internal class CryptoModule { // CryptoService scope(DefaultSession.SCOPE) { - DefaultCryptoService(get()) as CryptoService + get() as CryptoService } // @@ -187,7 +187,6 @@ internal class CryptoModule { get(), get(), get(), - get(), // Actions get(), get(), diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt deleted file mode 100644 index 00ecc525..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2019 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.matrix.android.internal.crypto - -import im.vector.matrix.android.api.session.crypto.CryptoService - -internal class DefaultCryptoService(val cryptoManager: CryptoManager) - : CryptoService by cryptoManager \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/EnableEncryptionWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/EnableEncryptionWorker.kt new file mode 100644 index 00000000..8cbab2f5 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/EnableEncryptionWorker.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.crypto.live + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.squareup.moshi.JsonClass +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.internal.crypto.CryptoManager +import im.vector.matrix.android.internal.database.mapper.asDomain +import im.vector.matrix.android.internal.database.model.EventEntity +import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.MatrixKoinComponent +import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask +import im.vector.matrix.android.internal.session.room.members.RoomMembers +import im.vector.matrix.android.internal.task.TaskExecutor +import im.vector.matrix.android.internal.task.TaskThread +import im.vector.matrix.android.internal.task.configureWith +import im.vector.matrix.android.internal.util.WorkerParamsFactory +import org.koin.standalone.inject + +internal class EnableEncryptionWorker(context: Context, + workerParameters: WorkerParameters +) : Worker(context, workerParameters), MatrixKoinComponent { + + private val monarchy by inject() + private val cryptoManager by inject() + private val loadRoomMembersTask by inject() + private val taskExecutor by inject() + + @JsonClass(generateAdapter = true) + internal class Params( + val eventIds: List + ) + + + override fun doWork(): Result { + val params = WorkerParamsFactory.fromData(inputData) + ?: return Result.failure() + + + val events = monarchy.fetchAllMappedSync( + { EventEntity.where(it, params.eventIds) }, + { it.asDomain() } + ) + + events.forEach { + val roomId = it.roomId!! + + loadRoomMembersTask + .configureWith(LoadRoomMembersTask.Params(roomId)) + .executeOn(TaskThread.CALLER) + .executeBy(taskExecutor) + + var userIds: List = emptyList() + + monarchy.doWithRealm { realm -> + // Check whether the event content must be encrypted for the invited members. + val encryptForInvitedMembers = cryptoManager.isEncryptionEnabledForInvitedUser() + && cryptoManager.shouldEncryptForInvitedMembers(roomId) + + + userIds = if (encryptForInvitedMembers) { + RoomMembers(realm, roomId).getActiveRoomMemberIds() + } else { + RoomMembers(realm, roomId).getJoinedRoomMemberIds() + } + + } + + cryptoManager.onRoomEncryptionEvent(it, userIds) + } + + return Result.success() + } + + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/RealmLiveEncryptionObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/RealmLiveEncryptionObserver.kt new file mode 100644 index 00000000..4fd9dc9f --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/live/RealmLiveEncryptionObserver.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.crypto.live + +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.internal.database.RealmLiveEntityObserver +import im.vector.matrix.android.internal.database.mapper.asDomain +import im.vector.matrix.android.internal.database.model.EventEntity +import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.util.WorkerParamsFactory +import timber.log.Timber + +private const val ENABLE_ENCRYPTION_EVENT_WORKER = "ENABLE_ENCRYPTION_EVENT_WORKER" + +internal class RoomEncryptionEnabler(monarchy: Monarchy) : RealmLiveEntityObserver(monarchy) { + + override val query: Monarchy.Query + get() = Monarchy.Query { EventEntity.where(it, type = EventType.ENCRYPTION) } + + + override fun processChanges(inserted: List, updated: List, deleted: List) { + Timber.v("RoomEncryption received") + + val eventIds = inserted.mapNotNull { it.asDomain().eventId } + + val workParam = EnableEncryptionWorker.Params(eventIds) + val workData = WorkerParamsFactory.toData(workParam) + + val work = OneTimeWorkRequestBuilder() + .setInputData(workData) + .build() + + WorkManager.getInstance() + .beginUniqueWork(ENABLE_ENCRYPTION_EVENT_WORKER, ExistingWorkPolicy.APPEND, work) + .enqueue() + } +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index d08ba7d9..7d3022fc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -19,11 +19,11 @@ package im.vector.matrix.android.internal.crypto.store import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest -import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXOlmInboundGroupSession2 import im.vector.matrix.android.internal.crypto.model.MXOlmSession import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody +import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity import org.matrix.olm.OlmAccount /** @@ -204,6 +204,10 @@ internal interface IMXCryptoStore { */ fun getRoomAlgorithm(roomId: String): String? + fun shouldEncryptForInvitedMembers(roomId: String): Boolean + + fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) + /** * Store a session between the logged-in user and another device. * diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index d21648a8..9cabfdb5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -20,15 +20,15 @@ import android.text.TextUtils import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest +import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo +import im.vector.matrix.android.internal.crypto.model.MXOlmInboundGroupSession2 +import im.vector.matrix.android.internal.crypto.model.MXOlmSession +import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.db.model.* import im.vector.matrix.android.internal.crypto.store.db.query.delete import im.vector.matrix.android.internal.crypto.store.db.query.getById import im.vector.matrix.android.internal.crypto.store.db.query.getOrCreate -import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo -import im.vector.matrix.android.internal.crypto.model.MXOlmInboundGroupSession2 -import im.vector.matrix.android.internal.crypto.model.MXOlmSession -import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody import io.realm.RealmConfiguration import io.realm.Sort import io.realm.kotlin.where @@ -55,7 +55,7 @@ internal class RealmCryptoStore(private val enableFileEncryption: Boolean = fals // Cache for InboundGroupSession, to release them properly private val inboundGroupSessionToRelease = HashMap() - /* ========================================================================================== + /* ========================================================================================== * Other data * ========================================================================================== */ @@ -241,6 +241,19 @@ internal class RealmCryptoStore(private val enableFileEncryption: Boolean = fals ?.algorithm } + override fun shouldEncryptForInvitedMembers(roomId: String): Boolean { + return doRealmQueryAndCopy(realmConfiguration) { + CryptoRoomEntity.getById(it, roomId) + } + ?.shouldEncryptForInvitedMembers ?: false + } + + override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) { + doRealmTransaction(realmConfiguration) { + CryptoRoomEntity.getOrCreate(it, roomId).shouldEncryptForInvitedMembers = shouldEncryptForInvitedMembers + } + } + override fun storeSession(session: MXOlmSession, deviceKey: String) { var sessionIdentifier: String? = null diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt index 09394051..fcec259e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt @@ -22,6 +22,7 @@ import io.realm.annotations.PrimaryKey internal open class CryptoRoomEntity( @PrimaryKey var roomId: String? = null, var algorithm: String? = null, + var shouldEncryptForInvitedMembers: Boolean? = null, var blacklistUnverifiedDevices: Boolean = false) : RealmObject() { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt index 9f31aa2c..3f3c9bde 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt @@ -70,6 +70,9 @@ internal abstract class RealmLiveEntityObserver(protected val m processChanges(inserted, updated, deleted) } + /** + * Do quick treatment or delegate on a task + */ protected abstract fun processChanges(inserted: List, updated: List, deleted: List) } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt index c500a880..bf8d59c4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt @@ -30,6 +30,10 @@ internal fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQu return realm.where().equalTo(EventEntityFields.EVENT_ID, eventId) } +internal fun EventEntity.Companion.where(realm: Realm, eventIds: List): RealmQuery { + return realm.where().`in`(EventEntityFields.EVENT_ID, eventIds.toTypedArray()) +} + internal fun EventEntity.Companion.where(realm: Realm, roomId: String? = null, type: String? = null, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt index f02f8294..acd3353b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt @@ -48,6 +48,7 @@ object MoshiProvider { return moshi } + // TODO Move fun getCanonicalJson(type: Class, o: T): String { val adapter = moshi.adapter(type) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index 166ca029..d3ba342c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -31,6 +31,7 @@ import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService +import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.group.Group import im.vector.matrix.android.api.session.group.GroupService @@ -44,13 +45,14 @@ import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.user.UserService import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.android.api.util.MatrixCallbackDelegate +import im.vector.matrix.android.internal.crypto.CryptoManager import im.vector.matrix.android.internal.crypto.CryptoModule import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo -import im.vector.matrix.android.internal.crypto.CryptoManager -import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody +import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse +import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.di.MatrixKoinComponent import im.vector.matrix.android.internal.di.MatrixKoinHolder @@ -321,6 +323,17 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi cryptoService.setRoomBlacklistUnverifiedDevices(roomId) } + override fun isRoomEncrypted(roomId: String): Boolean { + return cryptoService.isRoomEncrypted(roomId) + } + + override fun encryptEventContent(eventContent: Content, + eventType: String, + room: Room, + callback: MatrixCallback) { + cryptoService.encryptEventContent(eventContent, eventType, room, callback) + } + override fun getDeviceInfo(userId: String, deviceId: String?): MXDeviceInfo? { return cryptoService.getDeviceInfo(userId, deviceId) } @@ -341,6 +354,14 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi return cryptoService.decryptEvent(event, timeline) } + override fun getEncryptionAlgorithm(roomId: String): String? { + return cryptoService.getEncryptionAlgorithm(roomId) + } + + override fun shouldEncryptForInvitedMembers(roomId: String): Boolean { + return cryptoService.shouldEncryptForInvitedMembers(roomId) + } + // Private methods ***************************************************************************** private fun assertMainThread() { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index d877bd3f..604053af 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.signout.SignOutService import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.user.UserService +import im.vector.matrix.android.internal.crypto.live.RoomEncryptionEnabler import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.model.SessionRealmModule import im.vector.matrix.android.internal.session.cache.ClearCacheTask @@ -151,7 +152,8 @@ internal class SessionModule(private val sessionParams: SessionParams) { val groupSummaryUpdater = GroupSummaryUpdater(get()) val eventsPruner = EventsPruner(get()) val userEntityUpdater = UserEntityUpdater(get(), get(), get()) - listOf(groupSummaryUpdater, eventsPruner, userEntityUpdater) + val roomEncryptionEnabler = RoomEncryptionEnabler(get()) + listOf(groupSummaryUpdater, eventsPruner, userEntityUpdater, roomEncryptionEnabler) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt index 6c2ab00f..1a4202b6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.room import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.members.RoomMembersService import im.vector.matrix.android.api.session.room.model.RoomSummary @@ -39,7 +40,8 @@ internal class DefaultRoom( private val sendService: SendService, private val stateService: StateService, private val readService: ReadService, - private val roomMembersService: RoomMembersService + private val roomMembersService: RoomMembersService, + private val cryptoService: CryptoService ) : Room, TimelineService by timelineService, SendService by sendService, @@ -63,4 +65,16 @@ internal class DefaultRoom( } } + override fun isEncrypted(): Boolean { + return cryptoService.isRoomEncrypted(roomId) + } + + override fun encryptionAlgorithm(): String? { + return cryptoService.getEncryptionAlgorithm(roomId) + } + + override fun shouldEncryptForInvitedMembers(): Boolean { + return cryptoService.shouldEncryptForInvitedMembers(roomId) + } + } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt index 24e51355..ed127845 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.internal.session.room.invite.InviteTask import im.vector.matrix.android.internal.session.room.members.DefaultRoomMembersService @@ -42,13 +43,14 @@ internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask, private val contextOfEventTask: GetContextOfEventTask, private val setReadMarkersTask: SetReadMarkersTask, private val eventFactory: LocalEchoEventFactory, + private val cryptoService: CryptoService, private val taskExecutor: TaskExecutor) { fun instantiate(roomId: String): Room { val roomMemberExtractor = SenderRoomMemberExtractor(roomId) val timelineEventFactory = TimelineEventFactory(roomMemberExtractor) val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask) - val sendService = DefaultSendService(roomId, eventFactory, monarchy) + val sendService = DefaultSendService(roomId, eventFactory, cryptoService, monarchy) val stateService = DefaultStateService(roomId, sendStateTask, taskExecutor) val roomMembersService = DefaultRoomMembersService(roomId, monarchy, loadRoomMembersTask, inviteTask, taskExecutor) val readService = DefaultReadService(roomId, monarchy, setReadMarkersTask, taskExecutor) @@ -60,7 +62,8 @@ internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask, sendService, stateService, readService, - roomMembersService + roomMembersService, + cryptoService ) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index 192bbac0..e48d25e2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -71,7 +71,7 @@ class RoomModule { } scope(DefaultSession.SCOPE) { - RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get()) + RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) } scope(DefaultSession.SCOPE) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt index 1e1c898a..a007a1eb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt @@ -68,26 +68,4 @@ internal class DefaultRoomMembersService(private val roomId: String, .dispatchTo(callback) .executeBy(taskExecutor) } - - override fun getActiveRoomMemberIds(): List { - return getRoomMemberIdsFiltered { it.membership == Membership.JOIN || it.membership == Membership.INVITE } - } - - override fun getJoinedRoomMemberIds(): List { - return getRoomMemberIdsFiltered { it.membership == Membership.JOIN } - } - - /* ========================================================================================== - * Private - * ========================================================================================== */ - - private fun getRoomMemberIdsFiltered(predicate: (RoomMember) -> Boolean): List { - return monarchy.fetchAllCopiedSync { RoomMembers(it, roomId).queryRoomMembersEvent() } - .map { it.asDomain() } - .associateBy { it.stateKey!! } - .mapValues { it.value.content.toModel()!! } - .filterValues { predicate(it) } - .keys - .toList() - } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt index 98d33f12..a441af94 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt @@ -95,5 +95,38 @@ internal class RoomMembers(private val realm: Realm, return getNumberOfJoinedMembers() + getNumberOfInvitedMembers() } + /** + * Return all the roomMembers ids which are joined or invited to the room + * + * @return a roomMember id list of joined or invited members. + */ + fun getActiveRoomMemberIds(): List { + return getRoomMemberIdsFiltered { it.membership == Membership.JOIN || it.membership == Membership.INVITE } + } + + /** + * Return all the roomMembers ids which are joined to the room + * + * @return a roomMember id list of joined members. + */ + fun getJoinedRoomMemberIds(): List { + return getRoomMemberIdsFiltered { it.membership == Membership.JOIN } + } + + /* ========================================================================================== + * Private + * ========================================================================================== */ + + private fun getRoomMemberIdsFiltered(predicate: (RoomMember) -> Boolean): List { + return RoomMembers(realm, roomId) + .queryRoomMembersEvent() + .findAll() + .map { it.asDomain() } + .associateBy { it.stateKey!! } + .mapValues { it.value.content.toModel()!! } + .filterValues { predicate(it) } + .keys + .toList() + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt index 0089844c..36fd74a5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt @@ -16,15 +16,10 @@ package im.vector.matrix.android.internal.session.room.send -import androidx.work.BackoffPolicy -import androidx.work.Constraints -import androidx.work.ExistingWorkPolicy -import androidx.work.NetworkType -import androidx.work.OneTimeWorkRequest -import androidx.work.OneTimeWorkRequestBuilder -import androidx.work.WorkManager +import androidx.work.* import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.content.ContentAttachmentData +import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.util.Cancelable @@ -39,6 +34,7 @@ import im.vector.matrix.android.internal.session.content.UploadContentWorker import im.vector.matrix.android.internal.util.CancelableWork import im.vector.matrix.android.internal.util.WorkerParamsFactory import im.vector.matrix.android.internal.util.tryTransactionAsync +import timber.log.Timber import java.util.concurrent.TimeUnit private const val SEND_WORK = "SEND_WORK" @@ -51,6 +47,7 @@ private val WORK_CONSTRAINTS = Constraints.Builder() internal class DefaultSendService(private val roomId: String, private val eventFactory: LocalEchoEventFactory, + private val cryptoService: CryptoService, private val monarchy: Monarchy) : SendService { @@ -59,6 +56,33 @@ internal class DefaultSendService(private val roomId: String, val event = eventFactory.createTextEvent(roomId, msgType, text).also { saveLocalEcho(it) } + + // Encrypted room handling + if (cryptoService.isRoomEncrypted(roomId)) { + Timber.v("Send event in encrypted room") + // Encrypt then send + + val encryptWork = createEncryptEventWork(event) + + val sendWork = OneTimeWorkRequestBuilder() + .setConstraints(WORK_CONSTRAINTS) + .setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS) + .build() + + WorkManager.getInstance() + // Encrypt + .beginUniqueWork(buildWorkIdentifier(SEND_WORK), ExistingWorkPolicy.APPEND, encryptWork) + // then send + .then(sendWork) + .enqueue() + + return CancelableWork(encryptWork.id) + } else { + return sendEvent(event) + } + } + + private fun sendEvent(event: Event): Cancelable { val sendWork = createSendEventWork(event) WorkManager.getInstance() .beginUniqueWork(buildWorkIdentifier(SEND_WORK), ExistingWorkPolicy.APPEND, sendWork) @@ -93,9 +117,9 @@ internal class DefaultSendService(private val roomId: String, private fun saveLocalEcho(event: Event) { monarchy.tryTransactionAsync { realm -> val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() - ?: return@tryTransactionAsync + ?: return@tryTransactionAsync val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId = roomId) - ?: return@tryTransactionAsync + ?: return@tryTransactionAsync roomEntity.addSendingEvent(event, liveChunk.forwardsStateIndex ?: 0) } @@ -105,6 +129,18 @@ internal class DefaultSendService(private val roomId: String, return "${roomId}_$identifier" } + private fun createEncryptEventWork(event: Event): OneTimeWorkRequest { + // Same parameter + val sendContentWorkerParams = SendEventWorker.Params(roomId, event) + val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) + + return OneTimeWorkRequestBuilder() + .setConstraints(WORK_CONSTRAINTS) + .setInputData(sendWorkData) + .setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS) + .build() + } + private fun createSendEventWork(event: Event): OneTimeWorkRequest { val sendContentWorkerParams = SendEventWorker.Params(roomId, event) val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt new file mode 100644 index 00000000..e6619cc4 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.room.send + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.crypto.CryptoService +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.room.RoomService +import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult +import im.vector.matrix.android.internal.di.MatrixKoinComponent +import im.vector.matrix.android.internal.util.WorkerParamsFactory +import org.koin.standalone.inject +import java.util.concurrent.CountDownLatch + +internal class EncryptEventWorker(context: Context, params: WorkerParameters) + : Worker(context, params), MatrixKoinComponent { + + + @JsonClass(generateAdapter = true) + internal data class Params( + val roomId: String, + val event: Event + ) + + private val crypto by inject() + private val roomService by inject() + + override fun doWork(): Result { + + val params = WorkerParamsFactory.fromData(inputData) + ?: return Result.failure() + + val localEvent = params.event + if (localEvent.eventId == null) { + return Result.failure() + } + + // TODO Better async handling + val latch = CountDownLatch(1) + + var result: MXEncryptEventContentResult? = null + var error: Throwable? = null + + crypto.encryptEventContent(localEvent.content!!, localEvent.type, roomService.getRoom(params.roomId)!!, object : MatrixCallback { + override fun onSuccess(data: MXEncryptEventContentResult) { + result = data + latch.countDown() + } + + override fun onFailure(failure: Throwable) { + error = failure + latch.countDown() + } + }) + + latch.await() + + // TODO Update local echo + + if (error != null) { + return Result.failure() // TODO Pass error!!) + } else if (result != null) { + return Result.success(WorkerParamsFactory.toData(SendEventWorker.Params(params.roomId, + Event(type = result!!.mEventType, + content = result!!.mEventContent)))) + } else { + return Result.failure() + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt index 3ed252d5..43ffb758 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt @@ -63,9 +63,9 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, private fun handleRoomSync(realm: Realm, handlingStrategy: HandlingStrategy) { val rooms = when (handlingStrategy) { - is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) } + is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) } is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedRoom(realm, it.key, it.value) } - is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) } + is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) } } realm.insertOrUpdate(rooms) } @@ -91,9 +91,16 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, val numberOfStateEvents = roomSync.state?.events?.size ?: 0 val stateIndexOffset = lastStateIndex + numberOfStateEvents + // State event if (roomSync.state != null && roomSync.state.events.isNotEmpty()) { val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset roomEntity.addStateEvents(roomSync.state.events, filterDuplicates = true, stateIndex = untimelinedStateIndex) + + // Give info to crypto module + // TODO Remove + roomSync.state.events.forEach { + mCrypto.onStateEvent(roomId, it) + } } if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {