mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-03 20:47:32 +01:00
Remove decryption from room summary mapper and make TimelineEventDecryptor scoped to session
This commit is contained in:
parent
cf8ffa3a7a
commit
d57f6838e9
@ -16,19 +16,12 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.database.mapper
|
package im.vector.matrix.android.internal.database.mapper
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.UUID
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RoomSummaryMapper @Inject constructor(
|
internal class RoomSummaryMapper @Inject constructor(private val timelineEventMapper: TimelineEventMapper) {
|
||||||
private val cryptoService: CryptoService,
|
|
||||||
private val timelineEventMapper: TimelineEventMapper
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
||||||
val tags = roomSummaryEntity.tags.map {
|
val tags = roomSummaryEntity.tags.map {
|
||||||
@ -38,22 +31,6 @@ internal class RoomSummaryMapper @Inject constructor(
|
|||||||
val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
|
val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
|
||||||
timelineEventMapper.map(it, buildReadReceipts = false)
|
timelineEventMapper.map(it, buildReadReceipts = false)
|
||||||
}
|
}
|
||||||
if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) {
|
|
||||||
// TODO use a global event decryptor? attache to session and that listen to new sessionId?
|
|
||||||
// for now decrypt sync
|
|
||||||
try {
|
|
||||||
val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString())
|
|
||||||
latestEvent.root.mxDecryptionResult = OlmDecryptionResult(
|
|
||||||
payload = result.clearEvent,
|
|
||||||
senderKey = result.senderCurve25519Key,
|
|
||||||
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
|
|
||||||
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
|
|
||||||
)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.d(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RoomSummary(
|
return RoomSummary(
|
||||||
roomId = roomSummaryEntity.roomId,
|
roomId = roomSummaryEntity.roomId,
|
||||||
displayName = roomSummaryEntity.displayName ?: "",
|
displayName = roomSummaryEntity.displayName ?: "",
|
||||||
|
@ -49,6 +49,7 @@ import im.vector.matrix.android.internal.crypto.crosssigning.ShieldTrustUpdater
|
|||||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.di.SessionId
|
import im.vector.matrix.android.internal.di.SessionId
|
||||||
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
||||||
|
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecryptor
|
||||||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
||||||
@ -93,6 +94,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
|
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
|
||||||
private val accountDataService: Lazy<AccountDataService>,
|
private val accountDataService: Lazy<AccountDataService>,
|
||||||
private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
|
private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
|
||||||
|
private val timelineEventDecryptor: TimelineEventDecryptor,
|
||||||
private val shieldTrustUpdater: ShieldTrustUpdater)
|
private val shieldTrustUpdater: ShieldTrustUpdater)
|
||||||
: Session,
|
: Session,
|
||||||
RoomService by roomService.get(),
|
RoomService by roomService.get(),
|
||||||
@ -126,6 +128,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
isOpen = true
|
isOpen = true
|
||||||
liveEntityObservers.forEach { it.start() }
|
liveEntityObservers.forEach { it.start() }
|
||||||
eventBus.register(this)
|
eventBus.register(this)
|
||||||
|
timelineEventDecryptor.start()
|
||||||
shieldTrustUpdater.start()
|
shieldTrustUpdater.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +166,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
override fun close() {
|
override fun close() {
|
||||||
assert(isOpen)
|
assert(isOpen)
|
||||||
stopSync()
|
stopSync()
|
||||||
|
timelineEventDecryptor.destroy()
|
||||||
liveEntityObservers.forEach { it.dispose() }
|
liveEntityObservers.forEach { it.dispose() }
|
||||||
cryptoService.get().close()
|
cryptoService.get().close()
|
||||||
isOpen = false
|
isOpen = false
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import dagger.Lazy
|
||||||
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
|
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
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.events.model.toModel
|
||||||
@ -41,17 +42,20 @@ import im.vector.matrix.android.internal.database.query.whereType
|
|||||||
import im.vector.matrix.android.internal.di.UserId
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver
|
import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver
|
||||||
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
|
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
|
||||||
|
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecryptor
|
||||||
import im.vector.matrix.android.internal.session.sync.RoomSyncHandler
|
import im.vector.matrix.android.internal.session.sync.RoomSyncHandler
|
||||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
||||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RoomSummaryUpdater @Inject constructor(
|
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 timelineEventDecryptor: Lazy<TimelineEventDecryptor>,
|
||||||
private val eventBus: EventBus,
|
private val eventBus: EventBus,
|
||||||
private val monarchy: Monarchy) {
|
private val monarchy: Monarchy) {
|
||||||
|
|
||||||
@ -141,6 +145,11 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||||||
roomSummaryEntity.inviterId = null
|
roomSummaryEntity.inviterId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (latestPreviewableEvent?.root?.type == EventType.ENCRYPTED && latestPreviewableEvent.root?.decryptionResultJson == null) {
|
||||||
|
Timber.v("Should decrypt ${latestPreviewableEvent.eventId}")
|
||||||
|
timelineEventDecryptor.get().requestDecryption(TimelineEventDecryptor.DecryptionRequest(latestPreviewableEvent.eventId, ""))
|
||||||
|
}
|
||||||
|
|
||||||
if (updateMembers) {
|
if (updateMembers) {
|
||||||
val otherRoomMembers = RoomMemberHelper(realm, roomId)
|
val otherRoomMembers = RoomMemberHelper(realm, roomId)
|
||||||
.queryRoomMembersEvent()
|
.queryRoomMembersEvent()
|
||||||
|
@ -73,11 +73,11 @@ internal class DefaultTimeline(
|
|||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
private val paginationTask: PaginationTask,
|
private val paginationTask: PaginationTask,
|
||||||
private val cryptoService: CryptoService,
|
|
||||||
private val timelineEventMapper: TimelineEventMapper,
|
private val timelineEventMapper: TimelineEventMapper,
|
||||||
private val settings: TimelineSettings,
|
private val settings: TimelineSettings,
|
||||||
private val hiddenReadReceipts: TimelineHiddenReadReceipts,
|
private val hiddenReadReceipts: TimelineHiddenReadReceipts,
|
||||||
private val eventBus: EventBus
|
private val eventBus: EventBus,
|
||||||
|
private val eventDecryptor: TimelineEventDecryptor
|
||||||
) : Timeline, TimelineHiddenReadReceipts.Delegate {
|
) : Timeline, TimelineHiddenReadReceipts.Delegate {
|
||||||
|
|
||||||
data class OnNewTimelineEvents(val roomId: String, val eventIds: List<String>)
|
data class OnNewTimelineEvents(val roomId: String, val eventIds: List<String>)
|
||||||
@ -114,8 +114,6 @@ internal class DefaultTimeline(
|
|||||||
override val isLive
|
override val isLive
|
||||||
get() = !hasMoreToLoad(Timeline.Direction.FORWARDS)
|
get() = !hasMoreToLoad(Timeline.Direction.FORWARDS)
|
||||||
|
|
||||||
private val eventDecryptor = TimelineEventDecryptor(realmConfiguration, timelineID, cryptoService)
|
|
||||||
|
|
||||||
private val eventsChangeListener = OrderedRealmCollectionChangeListener<RealmResults<TimelineEventEntity>> { results, changeSet ->
|
private val eventsChangeListener = OrderedRealmCollectionChangeListener<RealmResults<TimelineEventEntity>> { results, changeSet ->
|
||||||
if (!results.isLoaded || !results.isValid) {
|
if (!results.isLoaded || !results.isValid) {
|
||||||
return@OrderedRealmCollectionChangeListener
|
return@OrderedRealmCollectionChangeListener
|
||||||
@ -607,7 +605,7 @@ internal class DefaultTimeline(
|
|||||||
|
|
||||||
if (timelineEvent.isEncrypted()
|
if (timelineEvent.isEncrypted()
|
||||||
&& timelineEvent.root.mxDecryptionResult == null) {
|
&& timelineEvent.root.mxDecryptionResult == null) {
|
||||||
timelineEvent.root.eventId?.let { eventDecryptor.requestDecryption(it) }
|
timelineEvent.root.eventId?.also { eventDecryptor.requestDecryption(TimelineEventDecryptor.DecryptionRequest(it, timelineID)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val position = if (direction == Timeline.Direction.FORWARDS) 0 else builtEvents.size
|
val position = if (direction == Timeline.Direction.FORWARDS) 0 else builtEvents.size
|
||||||
|
@ -41,7 +41,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
|
|||||||
private val eventBus: EventBus,
|
private val eventBus: EventBus,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
private val cryptoService: CryptoService,
|
private val eventDecryptor: TimelineEventDecryptor,
|
||||||
private val paginationTask: PaginationTask,
|
private val paginationTask: PaginationTask,
|
||||||
private val timelineEventMapper: TimelineEventMapper,
|
private val timelineEventMapper: TimelineEventMapper,
|
||||||
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper
|
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper
|
||||||
@ -60,11 +60,11 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
|
|||||||
taskExecutor = taskExecutor,
|
taskExecutor = taskExecutor,
|
||||||
contextOfEventTask = contextOfEventTask,
|
contextOfEventTask = contextOfEventTask,
|
||||||
paginationTask = paginationTask,
|
paginationTask = paginationTask,
|
||||||
cryptoService = cryptoService,
|
|
||||||
timelineEventMapper = timelineEventMapper,
|
timelineEventMapper = timelineEventMapper,
|
||||||
settings = settings,
|
settings = settings,
|
||||||
hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings),
|
hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings),
|
||||||
eventBus = eventBus
|
eventBus = eventBus,
|
||||||
|
eventDecryptor = eventDecryptor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,15 +23,20 @@ import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventConten
|
|||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
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.model.EventEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||||
|
import im.vector.matrix.android.internal.session.SessionScope
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.UUID
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class TimelineEventDecryptor(
|
@SessionScope
|
||||||
|
internal class TimelineEventDecryptor @Inject constructor(
|
||||||
|
@SessionDatabase
|
||||||
private val realmConfiguration: RealmConfiguration,
|
private val realmConfiguration: RealmConfiguration,
|
||||||
private val timelineId: String,
|
|
||||||
private val cryptoService: CryptoService
|
private val cryptoService: CryptoService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -53,9 +58,9 @@ internal class TimelineEventDecryptor(
|
|||||||
private var executor: ExecutorService? = null
|
private var executor: ExecutorService? = null
|
||||||
|
|
||||||
// Set of eventIds which are currently decrypting
|
// Set of eventIds which are currently decrypting
|
||||||
private val existingRequests = mutableSetOf<String>()
|
private val existingRequests = mutableSetOf<DecryptionRequest>()
|
||||||
// sessionId -> list of eventIds
|
// sessionId -> list of eventIds
|
||||||
private val unknownSessionsFailure = mutableMapOf<String, MutableSet<String>>()
|
private val unknownSessionsFailure = mutableMapOf<String, MutableSet<DecryptionRequest>>()
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
executor = Executors.newSingleThreadExecutor()
|
executor = Executors.newSingleThreadExecutor()
|
||||||
@ -74,53 +79,51 @@ internal class TimelineEventDecryptor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestDecryption(eventId: String) {
|
fun requestDecryption(request: DecryptionRequest) {
|
||||||
synchronized(unknownSessionsFailure) {
|
synchronized(unknownSessionsFailure) {
|
||||||
for (eventIds in unknownSessionsFailure.values) {
|
for (requests in unknownSessionsFailure.values) {
|
||||||
if (eventId in eventIds) {
|
if (request in requests) {
|
||||||
Timber.d("Skip Decryption request for event $eventId, unknown session")
|
Timber.d("Skip Decryption request for event ${request.eventId}, unknown session")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronized(existingRequests) {
|
synchronized(existingRequests) {
|
||||||
if (!existingRequests.add(eventId)) {
|
if (!existingRequests.add(request)) {
|
||||||
Timber.d("Skip Decryption request for event $eventId, already requested")
|
Timber.d("Skip Decryption request for event ${request.eventId}, already requested")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executor?.execute {
|
executor?.execute {
|
||||||
Realm.getInstance(realmConfiguration).use { realm ->
|
Realm.getInstance(realmConfiguration).use { realm ->
|
||||||
processDecryptRequest(eventId, realm)
|
processDecryptRequest(request, realm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processDecryptRequest(eventId: String, realm: Realm) {
|
private fun processDecryptRequest(request: DecryptionRequest, realm: Realm) = realm.executeTransaction {
|
||||||
|
val eventId = request.eventId
|
||||||
|
val timelineId = request.timelineId
|
||||||
Timber.v("Decryption request for event $eventId")
|
Timber.v("Decryption request for event $eventId")
|
||||||
val eventEntity = EventEntity.where(realm, eventId = eventId).findFirst()
|
val eventEntity = EventEntity.where(realm, eventId = eventId).findFirst()
|
||||||
?: return Unit.also {
|
?: return@executeTransaction Unit.also {
|
||||||
Timber.d("Decryption request for unknown message")
|
Timber.d("Decryption request for unknown message")
|
||||||
}
|
}
|
||||||
val event = eventEntity.asDomain()
|
val event = eventEntity.asDomain()
|
||||||
try {
|
try {
|
||||||
val result = cryptoService.decryptEvent(event, timelineId)
|
val result = cryptoService.decryptEvent(event, timelineId)
|
||||||
Timber.v("Successfully decrypted event $eventId")
|
Timber.v("Successfully decrypted event $eventId")
|
||||||
realm.executeTransaction {
|
eventEntity.setDecryptionResult(result)
|
||||||
eventEntity.setDecryptionResult(result)
|
|
||||||
}
|
|
||||||
} catch (e: MXCryptoError) {
|
} catch (e: MXCryptoError) {
|
||||||
Timber.w(e, "Failed to decrypt event $eventId")
|
Timber.w(e, "Failed to decrypt event $eventId")
|
||||||
if (e is MXCryptoError.Base && e.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) {
|
if (e is MXCryptoError.Base && e.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) {
|
||||||
// Keep track of unknown sessions to automatically try to decrypt on new session
|
// Keep track of unknown sessions to automatically try to decrypt on new session
|
||||||
realm.executeTransaction {
|
eventEntity.decryptionErrorCode = e.errorType.name
|
||||||
eventEntity.decryptionErrorCode = e.errorType.name
|
|
||||||
}
|
|
||||||
event.content?.toModel<EncryptedEventContent>()?.let { content ->
|
event.content?.toModel<EncryptedEventContent>()?.let { content ->
|
||||||
content.sessionId?.let { sessionId ->
|
content.sessionId?.let { sessionId ->
|
||||||
synchronized(unknownSessionsFailure) {
|
synchronized(unknownSessionsFailure) {
|
||||||
val list = unknownSessionsFailure.getOrPut(sessionId) { mutableSetOf() }
|
val list = unknownSessionsFailure.getOrPut(sessionId) { mutableSetOf() }
|
||||||
list.add(eventId)
|
list.add(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,8 +132,13 @@ internal class TimelineEventDecryptor(
|
|||||||
Timber.e(t, "Failed to decrypt event $eventId")
|
Timber.e(t, "Failed to decrypt event $eventId")
|
||||||
} finally {
|
} finally {
|
||||||
synchronized(existingRequests) {
|
synchronized(existingRequests) {
|
||||||
existingRequests.remove(eventId)
|
existingRequests.remove(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class DecryptionRequest(
|
||||||
|
val eventId: String,
|
||||||
|
val timelineId: String
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user