merge develop

This commit is contained in:
Valere 2019-07-08 10:58:41 +02:00
parent 4521ea14ee
commit e50dd265d4
10 changed files with 341 additions and 151 deletions

View File

@ -20,12 +20,11 @@ import android.text.TextUtils
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
import im.vector.matrix.android.internal.di.MoshiProvider
import timber.log.Timber
import java.util.*
import kotlin.collections.HashMap

typealias Content = JsonDict

@ -79,6 +78,10 @@ data class Event(
@Json(name = "redacts") val redacts: String? = null
) {


var mxDecryptionResult: MXDecryptionResult? = null
var mCryptoError: MXCryptoError? = null

/**
* Check if event is a state event.
* @return true if event is state event.
@ -91,41 +94,41 @@ data class Event(
// Crypto
//==============================================================================================================

/**
* For encrypted events, the plaintext payload for the event.
* This is a small MXEvent instance with typically value for `type` and 'content' fields.
*/
@Transient
var mClearEvent: Event? = null
private set

/**
* Curve25519 key which we believe belongs to the sender of the event.
* See `senderKey` property.
*/
@Transient
private var mSenderCurve25519Key: String? = null

/**
* Ed25519 key which the sender of this event (for olm) or the creator of the megolm session (for megolm) claims to own.
* See `claimedEd25519Key` property.
*/
@Transient
private var mClaimedEd25519Key: String? = null

/**
* Curve25519 keys of devices involved in telling us about the senderCurve25519Key and claimedEd25519Key.
* See `forwardingCurve25519KeyChain` property.
*/
@Transient
private var mForwardingCurve25519KeyChain: List<String> = ArrayList()

/**
* Decryption error
*/
@Transient
var mCryptoError: MXCryptoError? = null
private set
// /**
// * For encrypted events, the plaintext payload for the event.
// * This is a small MXEvent instance with typically value for `type` and 'content' fields.
// */
// @Transient
// var mClearEvent: Event? = null
// private set
//
// /**
// * Curve25519 key which we believe belongs to the sender of the event.
// * See `senderKey` property.
// */
// @Transient
// private var mSenderCurve25519Key: String? = null
//
// /**
// * Ed25519 key which the sender of this event (for olm) or the creator of the megolm session (for megolm) claims to own.
// * See `claimedEd25519Key` property.
// */
// @Transient
// private var mClaimedEd25519Key: String? = null
//
// /**
// * Curve25519 keys of devices involved in telling us about the senderCurve25519Key and claimedEd25519Key.
// * See `forwardingCurve25519KeyChain` property.
// */
// @Transient
// private var mForwardingCurve25519KeyChain: List<String> = ArrayList()
//
// /**
// * Decryption error
// */
// @Transient
// var mCryptoError: MXCryptoError? = null
// private set

/**
* @return true if this event is encrypted.
@ -140,88 +143,96 @@ data class Event(
*
* @param decryptionResult the decryption result, including the plaintext and some key info.
*/
internal fun setClearData(decryptionResult: MXEventDecryptionResult) {
mClearEvent = null
mCryptoError = null

val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
mClearEvent = adapter.fromJsonValue(decryptionResult.clearEvent)

if (mClearEvent != null) {
mSenderCurve25519Key = decryptionResult.senderCurve25519Key
mClaimedEd25519Key = decryptionResult.claimedEd25519Key
mForwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain

// For encrypted events with relation, the m.relates_to is kept in clear, so we need to put it back
// in the clear event
try {
content?.get("m.relates_to")?.let { clearRelates ->
mClearEvent = mClearEvent?.copy(
content = HashMap(mClearEvent!!.content).apply {
this["m.relates_to"] = clearRelates
}
)
}
} catch (e: Exception) {
Timber.e(e, "Unable to restore 'm.relates_to' the clear event")
}
}
}
// internal fun setClearData(decryptionResult: MXEventDecryptionResult?) {
// mClearEvent = null
// if (decryptionResult != null) {
// if (decryptionResult.clearEvent != null) {
// val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
// mClearEvent = adapter.fromJsonValue(decryptionResult.clearEvent)
//
// if (mClearEvent != null) {
// mSenderCurve25519Key = decryptionResult.senderCurve25519Key
// mClaimedEd25519Key = decryptionResult.claimedEd25519Key
// mForwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain
//
// // For encrypted events with relation, the m.relates_to is kept in clear, so we need to put it back
// // in the clear event
// try {
// content?.get("m.relates_to")?.let { clearRelates ->
// mClearEvent = mClearEvent?.copy(
// content = HashMap(mClearEvent!!.content).apply {
// this["m.relates_to"] = clearRelates
// }
// )
// }
// } catch (e: Exception) {
// Timber.e(e, "Unable to restore 'm.relates_to' the clear event")
// }
// }
//
//
// }
// }
// mCryptoError = null
// }

/**
* @return The curve25519 key that sent this event.
*/
fun getSenderKey(): String? {
return mClearEvent?.mSenderCurve25519Key ?: mSenderCurve25519Key
return mxDecryptionResult?.senderKey
// return mClearEvent?.mSenderCurve25519Key ?: mSenderCurve25519Key
}

/**
* @return The additional keys the sender of this encrypted event claims to possess.
*/
fun getKeysClaimed(): Map<String, String> {
val res = HashMap<String, String>()

val claimedEd25519Key = if (null != mClearEvent) mClearEvent!!.mClaimedEd25519Key else mClaimedEd25519Key

if (null != claimedEd25519Key) {
res["ed25519"] = claimedEd25519Key
}

return res
return mxDecryptionResult?.keysClaimed ?: HashMap()
// val res = HashMap<String, String>()
//
// val claimedEd25519Key = if (null != mClearEvent) mClearEvent!!.mClaimedEd25519Key else mClaimedEd25519Key
//
// if (null != claimedEd25519Key) {
// res["ed25519"] = claimedEd25519Key
// }
//
// return res
}

//
/**
* @return the event type
*/
fun getClearType(): String {
return mClearEvent?.type ?: type
return mxDecryptionResult?.payload?.get("type")?.toString()
?: type//get("type")?.toString() ?: type
}

/**
* @return the event content
*/
fun getClearContent(): Content? {
return mClearEvent?.content ?: content
return mxDecryptionResult?.payload?.get("content") as? Content ?: content
}

/**
* @return the linked crypto error
*/
fun getCryptoError(): MXCryptoError? {
return mCryptoError
}

/**
* Update the linked crypto error
*
* @param error the new crypto error.
*/
fun setCryptoError(error: MXCryptoError?) {
mCryptoError = error
if (null != error) {
mClearEvent = null
}
}
// /**
// * @return the linked crypto error
// */
// fun getCryptoError(): MXCryptoError? {
// return mCryptoError
// }
//
// /**
// * Update the linked crypto error
// *
// * @param error the new crypto error.
// */
// fun setCryptoError(error: MXCryptoError?) {
// mCryptoError = error
// if (null != error) {
// mClearEvent = null
// }
// }

/**
* Tells if the event is redacted

View File

@ -16,6 +16,7 @@

package im.vector.matrix.android.api.session.room.timeline

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.events.model.EventType
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
@ -34,7 +35,7 @@ data class TimelineEvent(
val isUniqueDisplayName: Boolean,
val senderAvatar: String?,
val sendState: SendState,
val hasClearEventFlag: Boolean = false,
// val hasClearEventFlag: Boolean = false,
val annotations: EventAnnotationsSummary? = null
) {


View File

@ -17,10 +17,13 @@
package im.vector.matrix.android.internal.database.mapper

import com.squareup.moshi.JsonDataException
import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.UnsignedData
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.di.MoshiProvider
import timber.log.Timber
import java.util.*

internal object EventMapper {
@ -46,7 +49,6 @@ internal object EventMapper {
}

fun map(eventEntity: EventEntity): Event {
//TODO proxy the event to only parse unsigned data when accessed?
val ud = if (eventEntity.unsignedData.isNullOrBlank()) {
null
} else {
@ -68,7 +70,17 @@ internal object EventMapper {
roomId = eventEntity.roomId,
unsignedData = ud,
redacts = eventEntity.redacts
)
).also {
eventEntity.decryptionResultJson?.let { json ->
try {
it.mxDecryptionResult = MoshiProvider.providesMoshi().adapter(MXDecryptionResult::class.java).fromJson(json)
} catch (t: JsonDataException) {
Timber.e(t, "Failed to parse decryption result")
}
}
//TODO get the full crypto error object
it.mCryptoError = eventEntity.decryptionErrorCode?.let { MXCryptoError(it, it) }
}
}

}

View File

@ -16,10 +16,12 @@

package im.vector.matrix.android.internal.database.mapper

import com.squareup.moshi.Types
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.di.MoshiProvider

internal object TimelineEventMapper {

@ -33,17 +35,18 @@ internal object TimelineEventMapper {
}

fun map(timelineEventEntity: TimelineEventEntity): TimelineEvent {
val listMapper = MoshiProvider.providesMoshi().adapter<List<String>>(Types.newParameterizedType(List::class.java, String::class.java))

return TimelineEvent(
root = timelineEventEntity.root?.asDomain()
?: Event("", timelineEventEntity.eventId),
?: Event("", timelineEventEntity.eventId),
annotations = timelineEventEntity.annotations?.asDomain(),
localId = timelineEventEntity.localId,
displayIndex = timelineEventEntity.root?.displayIndex ?: 0,
senderName = timelineEventEntity.senderName,
isUniqueDisplayName = timelineEventEntity.isUniqueDisplayName,
senderAvatar = timelineEventEntity.senderAvatar,
sendState = timelineEventEntity.root?.sendState ?: SendState.UNKNOWN,
hasClearEventFlag = false
sendState = timelineEventEntity.root?.sendState ?: SendState.UNKNOWN
)
}


View File

@ -17,7 +17,9 @@
package im.vector.matrix.android.internal.database.model

import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
import im.vector.matrix.android.internal.di.MoshiProvider
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Index
@ -39,7 +41,9 @@ internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUI
var redacts: String? = null,
@Index var stateIndex: Int = 0,
@Index var displayIndex: Int = 0,
@Index var isUnlinked: Boolean = false
@Index var isUnlinked: Boolean = false,
var decryptionResultJson: String? = null,
var decryptionErrorCode: String? = null
) : RealmObject() {

enum class LinkFilterMode {
@ -68,4 +72,14 @@ internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUI
val timelineEventEntity: RealmResults<TimelineEventEntity>? = null


fun setDecryptionResult(result: MXEventDecryptionResult) {
val decryptionResult = MXDecryptionResult(
payload = result.clearEvent,
senderKey = result.senderCurve25519Key,
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
)
val adapter = MoshiProvider.providesMoshi().adapter<MXDecryptionResult>(MXDecryptionResult::class.java)
decryptionResultJson = adapter.toJson(decryptionResult)
}
}

View File

@ -16,6 +16,10 @@

package im.vector.matrix.android.internal.database.model

import com.squareup.moshi.Types
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.database.mapper.ContentMapper
import im.vector.matrix.android.internal.di.MoshiProvider
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Index

View File

@ -19,19 +19,15 @@ package im.vector.matrix.android.internal.session.room.timeline
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.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.util.CancelableBag
import im.vector.matrix.android.api.util.addTo
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.*
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.findIncludingEvent
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
import im.vector.matrix.android.internal.database.query.where
@ -41,13 +37,7 @@ import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.Debouncer
import im.vector.matrix.android.internal.util.createBackgroundHandler
import im.vector.matrix.android.internal.util.createUIHandler
import io.realm.OrderedCollectionChangeSet
import io.realm.OrderedRealmCollectionChangeListener
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmQuery
import io.realm.RealmResults
import io.realm.Sort
import io.realm.*
import timber.log.Timber
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
@ -67,7 +57,7 @@ internal class DefaultTimeline(
private val taskExecutor: TaskExecutor,
private val contextOfEventTask: GetContextOfEventTask,
private val paginationTask: PaginationTask,
private val cryptoService: CryptoService,
cryptoService: CryptoService,
private val allowedTypes: List<String>?
) : Timeline {

@ -102,8 +92,12 @@ internal class DefaultTimeline(
private val forwardsPaginationState = AtomicReference(PaginationState())


private val timelineID = UUID.randomUUID().toString()

private lateinit var eventRelations: RealmResults<EventAnnotationsSummaryEntity>

private val eventDecryptor = TimelineEventDecryptor(realmConfiguration, timelineID, cryptoService)

private val eventsChangeListener = OrderedRealmCollectionChangeListener<RealmResults<TimelineEventEntity>> { results, changeSet ->
if (changeSet.state == OrderedCollectionChangeSet.State.INITIAL) {
handleInitialLoad()
@ -172,32 +166,32 @@ internal class DefaultTimeline(
postSnapshot()
}

private val newSessionListener = object : NewSessionListener {
override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
if (roomId == this@DefaultTimeline.roomId) {
Timber.v("New session id detected for this room")
BACKGROUND_HANDLER.post {
val realm = backgroundRealm.get()
var hasChange = false
builtEvents.forEachIndexed { index, timelineEvent ->
if (timelineEvent.isEncrypted()) {
val eventContent = timelineEvent.root.content.toModel<EncryptedEventContent>()
if (eventContent?.sessionId == sessionId
&& (timelineEvent.root.mClearEvent == null || timelineEvent.root.mCryptoError != null)) {
//we need to rebuild this event
EventEntity.where(realm, eventId = timelineEvent.root.eventId!!).findFirst()?.let {
//builtEvents[index] = timelineEventFactory.create(it, realm)
hasChange = true
}
}
}
}
if (hasChange) postSnapshot()
}
}
}

}
// private val newSessionListener = object : NewSessionListener {
// override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
// if (roomId == this@DefaultTimeline.roomId) {
// Timber.v("New session id detected for this room")
// BACKGROUND_HANDLER.post {
// val realm = backgroundRealm.get()
// var hasChange = false
// builtEvents.forEachIndexed { index, timelineEvent ->
// if (timelineEvent.isEncrypted()) {
// val eventContent = timelineEvent.root.content.toModel<EncryptedEventContent>()
// if (eventContent?.sessionId == sessionId
// && (timelineEvent.root.mClearEvent == null || timelineEvent.root.mCryptoError != null)) {
// //we need to rebuild this event
// EventEntity.where(realm, eventId = timelineEvent.root.eventId!!).findFirst()?.let {
// //builtEvents[index] = timelineEventFactory.create(it, realm)
// hasChange = true
// }
// }
// }
// }
// if (hasChange) postSnapshot()
// }
// }
// }
//
// }

// Public methods ******************************************************************************

@ -219,7 +213,7 @@ internal class DefaultTimeline(
override fun start() {
if (isStarted.compareAndSet(false, true)) {
Timber.v("Start timeline for roomId: $roomId and eventId: $initialEventId")
cryptoService.addNewSessionListener(newSessionListener)
eventDecryptor.start()
BACKGROUND_HANDLER.post {
val realm = Realm.getInstance(realmConfiguration)
backgroundRealm.set(realm)
@ -247,7 +241,7 @@ internal class DefaultTimeline(

override fun dispose() {
if (isStarted.compareAndSet(true, false)) {
cryptoService.removeSessionListener(newSessionListener)
eventDecryptor.destroy()
Timber.v("Dispose timeline for roomId: $roomId and eventId: $initialEventId")
BACKGROUND_HANDLER.post {
cancelableBag.cancel()
@ -387,9 +381,9 @@ internal class DefaultTimeline(
private fun executePaginationTask(direction: Timeline.Direction, limit: Int) {
val token = getTokenLive(direction) ?: return
val params = PaginationTask.Params(roomId = roomId,
from = token,
direction = direction.toPaginationDirection(),
limit = limit)
from = token,
direction = direction.toPaginationDirection(),
limit = limit)

Timber.v("Should fetch $limit items $direction")
cancelableBag += paginationTask.configureWith(params)
@ -453,6 +447,12 @@ internal class DefaultTimeline(
}
offsetResults.forEach { eventEntity ->
val timelineEvent = eventEntity.asDomain()

if (timelineEvent.isEncrypted()
&& timelineEvent.root.mxDecryptionResult == null) {
timelineEvent.root.eventId?.let { eventDecryptor.requestDecryption(it) }
}

val position = if (direction == Timeline.Direction.FORWARDS) 0 else builtEvents.size
builtEvents.add(position, timelineEvent)
//Need to shift :/

View File

@ -0,0 +1,133 @@
/*
* 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.timeline

import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.internal.crypto.MXDecryptionException
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
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 io.realm.Realm
import io.realm.RealmConfiguration
import timber.log.Timber
import java.util.concurrent.Executors


internal class TimelineEventDecryptor(
private val realmConfiguration: RealmConfiguration,
private val timelineId: String,
private val cryptoService: CryptoService
) {

private val newSessionListener = object : NewSessionListener {
override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
synchronized(unknownSessionsFailure) {
unknownSessionsFailure[sessionId]?.let { eventIds ->
eventIds.forEach {
requestDecryption(it)
}
}
unknownSessionsFailure[sessionId]?.clear()
}
}

}

private val executor = Executors.newSingleThreadExecutor()

private val existingRequests = HashSet<String>()
private val unknownSessionsFailure = HashMap<String, MutableList<String>>()

fun start() {
cryptoService.addNewSessionListener(newSessionListener)
}

fun destroy() {
cryptoService.removeSessionListener(newSessionListener)
executor.shutdownNow()
unknownSessionsFailure.clear()
existingRequests.clear()
}

fun requestDecryption(eventId: String) {
synchronized(existingRequests) {
if (existingRequests.contains(eventId)) {
return Unit.also {
Timber.d("Skip Decryption request for event ${eventId}, already requested")
}
}
existingRequests.add(eventId)
}
synchronized(unknownSessionsFailure) {
unknownSessionsFailure.values.forEach {
if (it.contains(eventId)) return@synchronized Unit.also {
Timber.d("Skip Decryption request for event ${eventId}, unknown session")
}
}
}
executor.execute {
Realm.getInstance(realmConfiguration).use { realm ->
realm.executeTransaction {
processDecryptRequest(eventId, it)
}
}
}
}

private fun processDecryptRequest(eventId: String, realm: Realm) {
Timber.v("Decryption request for event ${eventId}")
val eventEntity = EventEntity.where(realm, eventId = eventId).findFirst()
?: return Unit.also {
Timber.d("Decryption request for unknown message")
}
val event = eventEntity.asDomain()
try {
val result = cryptoService.decryptEvent(event, timelineId)
if (result == null) {
Timber.e("Null decryption result for event ${eventId}")
} else {
Timber.v("Successfully decrypted event ${eventId}")
eventEntity.setDecryptionResult(result)
}

} catch (e: MXDecryptionException) {
if (e.cryptoError?.code == MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE) {
//Keep track of unknown sessions to automatically try to decrypt on new session
event.content?.toModel<EncryptedEventContent>()?.let { content ->
content.sessionId?.let { sessionId ->
synchronized(unknownSessionsFailure) {
val list = unknownSessionsFailure[sessionId]
?: ArrayList<String>().also {
unknownSessionsFailure[sessionId] = it
}
list.add(eventId)
}
}
}
}
} catch (t: Throwable) {
Timber.e(t, "Failed to decrypt event $eventId")
} finally {
synchronized(existingRequests) {
existingRequests.remove(eventId)
}
}
}
}

View File

@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.session.sync.model.ToDeviceSyncResponse
@ -39,7 +40,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoManager:
// Decrypt event if necessary
decryptEvent(event, null)
if (TextUtils.equals(event.getClearType(), EventType.MESSAGE)
&& event.mClearEvent?.content?.toModel<MessageContent>()?.type == "m.bad.encrypted") {
&& event.getClearContent()?.toModel<MessageContent>()?.type == "m.bad.encrypted") {
Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.content)
} else {
sasVerificationService.onToDeviceEvent(event)
@ -70,7 +71,18 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoManager:
}

if (null != result) {
event.setClearData(result)
// event.mxDecryptionResult = MXDecryptionResult(
// payload = result.clearEvent,
// keysClaimed = map
// )
//TODO persist that?
event.mxDecryptionResult = MXDecryptionResult(
payload = result.clearEvent,
senderKey = result.senderCurve25519Key,
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
)
// event.setClearData(result)
return true
}
}

View File

@ -176,7 +176,7 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M

this.add(SimpleAction(VIEW_SOURCE, R.string.view_source, R.drawable.ic_view_source, JSONObject(event.root.toContent()).toString(4)))
if (event.isEncrypted()) {
val decryptedContent = event.root.mClearEvent.toContent()?.let {
val decryptedContent = event.root.getClearContent()?.let {
JSONObject(it).toString(4)
} ?: stringProvider.getString(R.string.encryption_information_decryption_error)
this.add(SimpleAction(VIEW_DECRYPTED_SOURCE, R.string.view_decrypted_source, R.drawable.ic_view_source, decryptedContent))