This commit is contained in:
Benoit Marty 2019-05-17 11:20:22 +02:00
parent 102bc9c01b
commit a2210a6b0d
12 changed files with 111 additions and 78 deletions

View File

@ -26,8 +26,7 @@ import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.di.MoshiProvider
import timber.log.Timber
import java.lang.reflect.ParameterizedType
import java.util.ArrayList
import java.util.HashMap
import java.util.*

typealias Content = JsonDict

@ -94,7 +93,8 @@ data class Event(
* This is a small MXEvent instance with typically value for `type` and 'content' fields.
*/
@Transient
private var mClearEvent: Event? = null
var mClearEvent: Event? = null
private set

/**
* Curve25519 key which we believe belongs to the sender of the event.
@ -121,7 +121,8 @@ data class Event(
* Decryption error
*/
@Transient
private var mCryptoError: MXCryptoError? = null
var mCryptoError: MXCryptoError? = null
private set

/**
* @return true if this event is encrypted.
@ -141,16 +142,16 @@ data class Event(
mClearEvent = null

if (null != decryptionResult) {
if (null != decryptionResult!!.mClearEvent) {
mClearEvent = decryptionResult!!.mClearEvent
if (null != decryptionResult.mClearEvent) {
mClearEvent = decryptionResult.mClearEvent
}

if (null != mClearEvent) {
mClearEvent!!.mSenderCurve25519Key = decryptionResult!!.mSenderCurve25519Key
mClearEvent!!.mClaimedEd25519Key = decryptionResult!!.mClaimedEd25519Key
mClearEvent!!.mSenderCurve25519Key = decryptionResult.mSenderCurve25519Key
mClearEvent!!.mClaimedEd25519Key = decryptionResult.mClaimedEd25519Key

if (null != decryptionResult!!.mForwardingCurve25519KeyChain) {
mClearEvent!!.mForwardingCurve25519KeyChain = decryptionResult!!.mForwardingCurve25519KeyChain
if (null != decryptionResult.mForwardingCurve25519KeyChain) {
mClearEvent!!.mForwardingCurve25519KeyChain = decryptionResult.mForwardingCurve25519KeyChain
} else {
mClearEvent!!.mForwardingCurve25519KeyChain = ArrayList()
}
@ -163,7 +164,7 @@ data class Event(
// .add("m.relates_to", getWireContent().getAsJsonObject().get("m.relates_to"))
//}
} catch (e: Exception) {
Timber.e(e,"Unable to restore 'm.relates_to' the clear event")
Timber.e(e, "Unable to restore 'm.relates_to' the clear event")
}

}

View File

@ -151,7 +151,7 @@ internal class CryptoManager(

fun onLiveEvent(roomId: String, event: Event) {
if (event.type == EventType.ENCRYPTION) {
onCryptoEvent(roomId, event)
onRoomEncryptionEvent(roomId, event)
} else if (event.type == EventType.STATE_ROOM_MEMBER) {
onRoomMembershipEvent(roomId, event)
}
@ -206,7 +206,7 @@ internal class CryptoManager(
mCryptoConfig = MXCryptoConfig()
}

mRoomEncryptors = HashMap()
mRoomEncryptors = HashMap() // TODO Merge with declaration

var deviceId = mCredentials.deviceId
// deviceId should always be defined
@ -770,6 +770,7 @@ internal class CryptoManager(

alg.initWithMatrixSession(this,
mOlmDevice,
mKeysBackup,
deviceListManager,
mCredentials,
mSendToDeviceTask,
@ -1146,7 +1147,7 @@ internal class CryptoManager(

getDecryptingThreadHandler().post {
var result: MXEventDecryptionResult? = null
val alg = roomDecryptorProvider.getRoomDecryptor(event.roomId, eventContent["algorithm"] as String)
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(this, event.roomId, eventContent["algorithm"] as String)

if (null == alg) {
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
@ -1342,7 +1343,8 @@ internal class CryptoManager(
*
* @param event the encryption event.
*/
fun onCryptoEvent(roomId: String, event: Event) {
private fun onRoomEncryptionEvent(roomId: String, event: Event) {
// TODO Parse the event
val eventContent = event.content // wireEventContent

val room = mRoomService.getRoom(roomId)!!
@ -1520,7 +1522,7 @@ internal class CryptoManager(
// But that message might never arrive leaving us stuck with duff
// private keys clogging up our local storage.
// So we need some kind of enginering compromise to balance all of
// these factors.
// these factors. // TODO Why we do not set mOneTimeKeyCount here?
val keyCount = data.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
uploadOTK(keyCount, keyLimit, callback)
}
@ -1765,7 +1767,7 @@ internal class CryptoManager(
cpt++


val decrypting = roomDecryptorProvider.getRoomDecryptor(megolmSessionData.roomId, megolmSessionData.algorithm)
val decrypting = roomDecryptorProvider.getOrCreateRoomDecryptor(this, megolmSessionData.roomId, megolmSessionData.algorithm)

if (null != decrypting) {
try {

View File

@ -51,10 +51,10 @@ internal class MXOlmDevice(
var deviceEd25519Key: String? = null
private set

// The OLMKit account instance.
// The OLM lib account instance.
private var mOlmAccount: OlmAccount? = null

// The OLMKit utility instance.
// The OLM lib utility instance.
private var mOlmUtility: OlmUtility? = null

// The outbound group session.
@ -144,9 +144,7 @@ internal class MXOlmDevice(
* Release the instance
*/
fun release() {
if (null != mOlmAccount) {
mOlmAccount!!.releaseAccount()
}
mOlmAccount?.releaseAccount()
}

/**
@ -265,7 +263,7 @@ internal class MXOlmDevice(

Timber.d("## createInboundSession() : ciphertext: $ciphertext")
try {
Timber.d("## createInboundSession() :ciphertext: SHA256:" + mOlmUtility!!.sha256(URLEncoder.encode(ciphertext, "utf-8")))
Timber.d("## createInboundSession() :ciphertext: SHA256:" + mOlmUtility!!.sha256(URLEncoder.encode(ciphertext, "utf-8"))) // TODO Extract code from the Log method...
} catch (e: Exception) {
Timber.e(e, "## createInboundSession() :ciphertext: cannot encode ciphertext")
}

View File

@ -298,7 +298,7 @@ internal class MXOutgoingRoomKeyRequestManager(
val contentMap = MXUsersDevicesMap<Any>()

for (recipient in recipients) {
contentMap.setObject(message, recipient["userId"], recipient["deviceId"])
contentMap.setObject(message, recipient["userId"], recipient["deviceId"]) // TODO Change this two hard coded key to something better
}

mSendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.ROOM_KEY_REQUEST, contentMap, transactionId))

View File

@ -33,7 +33,7 @@ internal class RoomDecryptorProvider(
) {

// A map from algorithm to MXDecrypting instance, for each room
private val mRoomDecryptors: MutableMap<String, MutableMap<String /* algorithm */, IMXDecrypting>>/* room id */ = HashMap()
private val mRoomDecryptors: MutableMap<String /* room id */, MutableMap<String /* algorithm */, IMXDecrypting>> = HashMap()

/**
* Get a decryptor for a given room and algorithm.
@ -43,7 +43,7 @@ internal class RoomDecryptorProvider(
* @param roomId the room id
* @param algorithm the crypto algorithm
* @return the decryptor
* TODO do not provide cryptoManager?
* TODO do not provide cryptoManager? // TODO Create another method for the case of roomId is null
*/
fun getOrCreateRoomDecryptor(cryptoManager: CryptoManager, roomId: String?, algorithm: String?): IMXDecrypting? {
// sanity check

View File

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.internal.crypto.DeviceListManager
import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.task.TaskExecutor

@ -39,6 +40,7 @@ internal interface IMXEncrypting {
*/
fun initWithMatrixSession(crypto: CryptoManager,
olmDevice: MXOlmDevice,
keysBackup: KeysBackup,
deviceListManager: DeviceListManager,
credentials: Credentials,
sendToDeviceTask: SendToDeviceTask,

View File

@ -62,7 +62,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
* Events which we couldn't decrypt due to unknown sessions / indexes: map from
* senderKey|sessionId to timelines to list of MatrixEvents.
*/
private var mPendingEvents: MutableMap<String, MutableMap<String /* timelineId */, MutableList<Event>>>? = null/* senderKey|sessionId */
private var mPendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap()

/**
* Init the object fields
@ -74,11 +74,11 @@ internal class MXMegolmDecryption : IMXDecrypting {
sendToDeviceTask: SendToDeviceTask,
taskExecutor: TaskExecutor) {
mCredentials = credentials
mCrypto = crypto
mOlmDevice = olmDevice
mDeviceListManager = deviceListManager
mSendToDeviceTask = sendToDeviceTask
mTaskExecutor = taskExecutor
mOlmDevice = olmDevice
mPendingEvents = HashMap()
}

@Throws(MXDecryptionException::class)
@ -167,7 +167,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
val recipients = ArrayList<Map<String, String>>()

val selfMap = HashMap<String, String>()
selfMap["userId"] = mCredentials.userId
selfMap["userId"] = mCredentials.userId // TODO Replace this hard coded keys (see MXOutgoingRoomKeyRequestManager)
selfMap["deviceId"] = "*"
recipients.add(selfMap)

@ -196,27 +196,21 @@ internal class MXMegolmDecryption : IMXDecrypting {
* @param timelineId the timeline identifier
*/
private fun addEventToPendingList(event: Event, timelineId: String) {
var timelineId = timelineId
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!!

val k = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}"

// avoid undefined timelineId
if (TextUtils.isEmpty(timelineId)) {
timelineId = ""
if (!mPendingEvents.containsKey(k)) {
mPendingEvents[k] = HashMap()
}

if (!mPendingEvents!!.containsKey(k)) {
mPendingEvents!![k] = HashMap()
if (!mPendingEvents[k]!!.containsKey(timelineId)) {
mPendingEvents[k]!!.put(timelineId, ArrayList<Event>())
}

if (!mPendingEvents!![k]!!.containsKey(timelineId)) {
mPendingEvents!![k]!!.put(timelineId, ArrayList<Event>())
}

if (mPendingEvents!![k]!![timelineId]!!.indexOf(event) < 0) {
if (mPendingEvents[k]!![timelineId]!!.indexOf(event) < 0) {
Timber.d("## addEventToPendingList() : add Event " + event.eventId + " in room id " + event.roomId)
mPendingEvents!![k]!![timelineId]!!.add(event)
mPendingEvents[k]!![timelineId]!!.add(event)
}
}

@ -304,11 +298,11 @@ internal class MXMegolmDecryption : IMXDecrypting {
override fun onNewSession(senderKey: String, sessionId: String) {
val k = "$senderKey|$sessionId"

val pending = mPendingEvents!![k]
val pending = mPendingEvents[k]

if (null != pending) {
// Have another go at decrypting events sent with this session.
mPendingEvents!!.remove(k)
mPendingEvents.remove(k)

val timelineIds = pending.keys


View File

@ -27,17 +27,13 @@ import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
import im.vector.matrix.android.internal.crypto.DeviceListManager
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.*
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
import im.vector.matrix.android.internal.crypto.model.MXQueuedEncryption
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.task.TaskExecutor
@ -51,15 +47,15 @@ internal class MXMegolmEncryption : IMXEncrypting {

private lateinit var mCrypto: CryptoManager
private lateinit var olmDevice: MXOlmDevice
private lateinit var mKeysBackup: KeysBackup
private lateinit var mDeviceListManager: DeviceListManager

private lateinit var mKeysBackup: KeysBackup
private lateinit var mCredentials: Credentials
private lateinit var mSendToDeviceTask: SendToDeviceTask
private lateinit var mTaskExecutor: TaskExecutor

// The id of the room we will be sending to.
private var mRoomId: String? = null
private lateinit var mRoomId: String

private var mDeviceId: String? = null

@ -93,6 +89,7 @@ internal class MXMegolmEncryption : IMXEncrypting {

override fun initWithMatrixSession(crypto: CryptoManager,
olmDevice: MXOlmDevice,
keysBackup: KeysBackup,
deviceListManager: DeviceListManager,
credentials: Credentials,
sendToDeviceTask: SendToDeviceTask,
@ -101,6 +98,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
mCrypto = crypto
this.olmDevice = olmDevice
mDeviceListManager = deviceListManager
mKeysBackup = keysBackup
mCredentials = credentials
mSendToDeviceTask = sendToDeviceTask
mTaskExecutor = taskExecutor
@ -108,6 +106,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
mRoomId = roomId
mDeviceId = mCredentials.deviceId


// Default rotation periods
// TODO: Make it configurable via parameters
mSessionRotationPeriodMsgs = 100

View File

@ -25,10 +25,9 @@ import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.internal.crypto.*
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.model.event.OlmEventContent
import im.vector.matrix.android.internal.crypto.model.event.OlmPayloadContent
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.convertFromUTF8
@ -42,7 +41,7 @@ import java.util.*
internal class MXOlmDecryption : IMXDecrypting {

// The olm device interface
private var mOlmDevice: MXOlmDevice? = null
private lateinit var mOlmDevice: MXOlmDevice

// the matrix credentials
private lateinit var mCredentials: Credentials
@ -60,9 +59,9 @@ internal class MXOlmDecryption : IMXDecrypting {
taskExecutor: TaskExecutor) {
mCredentials = credentials
mCrypto = crypto
mOlmDevice = olmDevice
mSendToDeviceTask = sendToDeviceTask
mTaskExecutor = taskExecutor
mOlmDevice = olmDevice
}

@Throws(MXDecryptionException::class)
@ -81,15 +80,15 @@ internal class MXOlmDecryption : IMXDecrypting {
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON))
}

if (!olmEventContent.ciphertext!!.containsKey(mOlmDevice!!.deviceCurve25519Key)) {
Timber.e("## decryptEvent() : our device " + mOlmDevice!!.deviceCurve25519Key
if (!olmEventContent.ciphertext!!.containsKey(mOlmDevice.deviceCurve25519Key)) {
Timber.e("## decryptEvent() : our device " + mOlmDevice.deviceCurve25519Key
+ " is not included in recipients. Event")
throw MXDecryptionException(MXCryptoError(MXCryptoError.NOT_INCLUDE_IN_RECIPIENTS_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.NOT_INCLUDED_IN_RECIPIENT_REASON))
}

// The message for myUser
val message = olmEventContent.ciphertext!![mOlmDevice!!.deviceCurve25519Key] as Map<String, Any>
val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as Map<String, Any>
val payloadString = decryptMessage(message, olmEventContent.senderKey)

if (null == payloadString) {
@ -131,7 +130,7 @@ internal class MXOlmDecryption : IMXDecrypting {

val ed25519 = olmPayloadContent.recipient_keys!!.get("ed25519")

if (!TextUtils.equals(ed25519, mOlmDevice!!.deviceEd25519Key)) {
if (!TextUtils.equals(ed25519, mOlmDevice.deviceEd25519Key)) {
Timber.e("## decryptEvent() : Event " + event.eventId + ": Intended recipient ed25519 key " + ed25519 + " did not match ours")
throw MXDecryptionException(MXCryptoError(MXCryptoError.BAD_RECIPIENT_KEY_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.BAD_RECIPIENT_KEY_REASON))
@ -194,7 +193,7 @@ internal class MXOlmDecryption : IMXDecrypting {
* @return payload, if decrypted successfully.
*/
private fun decryptMessage(message: Map<String, Any>, theirDeviceIdentityKey: String?): String? {
val sessionIdsSet = mOlmDevice!!.getSessionIds(theirDeviceIdentityKey!!)
val sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey!!)

val sessionIds: List<String>

@ -226,13 +225,13 @@ internal class MXOlmDecryption : IMXDecrypting {
// Try each session in turn
// decryptionErrors = {};
for (sessionId in sessionIds) {
val payload = mOlmDevice!!.decryptMessage(messageBody, messageType, sessionId, theirDeviceIdentityKey)
val payload = mOlmDevice.decryptMessage(messageBody, messageType, sessionId, theirDeviceIdentityKey)

if (null != payload) {
Timber.d("## decryptMessage() : Decrypted Olm message from $theirDeviceIdentityKey with session $sessionId")
return payload
} else {
val foundSession = mOlmDevice!!.matchesSession(theirDeviceIdentityKey, sessionId, messageType, messageBody)
val foundSession = mOlmDevice.matchesSession(theirDeviceIdentityKey, sessionId, messageType, messageBody)

if (foundSession) {
// Decryption failed, but it was a prekey message matching this
@ -258,7 +257,7 @@ internal class MXOlmDecryption : IMXDecrypting {

// prekey message which doesn't match any existing sessions: make a new
// session.
val res = mOlmDevice!!.createInboundSession(theirDeviceIdentityKey, messageType, messageBody)
val res = mOlmDevice.createInboundSession(theirDeviceIdentityKey, messageType, messageBody)

if (null == res) {
Timber.e("## decryptMessage() : Error decrypting non-prekey message with existing sessions")
@ -269,8 +268,4 @@ internal class MXOlmDecryption : IMXDecrypting {

return res["payload"]
}

companion object {
private val LOG_TAG = "MXOlmDecryption"
}
}

View File

@ -24,13 +24,14 @@ import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.DeviceListManager
import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.task.TaskExecutor
import java.util.*
@ -49,6 +50,7 @@ internal class MXOlmEncryption : IMXEncrypting {

override fun initWithMatrixSession(crypto: CryptoManager,
olmDevice: MXOlmDevice,
keysBackup: KeysBackup,
deviceListManager: DeviceListManager,
credentials: Credentials,
sendToDeviceTask: SendToDeviceTask,
@ -69,7 +71,7 @@ internal class MXOlmEncryption : IMXEncrypting {
//
// TODO: there is a race condition here! What if a new user turns up
ensureSession(userIds, object : MatrixCallback<Unit> {
override fun onSuccess(info: Unit) {
override fun onSuccess(data: Unit) {
val deviceInfos = ArrayList<MXDeviceInfo>()

for (userId in userIds) {
@ -95,11 +97,11 @@ internal class MXOlmEncryption : IMXEncrypting {
}

val messageMap = HashMap<String, Any>()
messageMap["room_id"] = mRoomId!!
messageMap["room_id"] = mRoomId
messageMap["type"] = eventType
messageMap["content"] = eventContent

mCrypto!!.encryptMessage(messageMap, deviceInfos)
mCrypto.encryptMessage(messageMap, deviceInfos)

callback.onSuccess(messageMap.toContent()!!)
}
@ -116,7 +118,7 @@ internal class MXOlmEncryption : IMXEncrypting {
mDeviceListManager.downloadKeys(users, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {

override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
mCrypto!!.ensureOlmSessionsForUsers(users, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
mCrypto.ensureOlmSessionsForUsers(users, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
callback?.onSuccess(Unit)
}

View File

@ -201,7 +201,7 @@ internal class RealmCryptoStore(private val enableFileEncryption: Boolean = fals
.let { u ->
// Add the devices
// Ensure all other devices are deleted
u.devices.deleteAllFromRealm()
u.devices.deleteAllFromRealm() // Device is null!!

u.devices.addAll(
devices.map {

View File

@ -16,25 +16,65 @@

package im.vector.matrix.android.internal.session.sync

import android.text.TextUtils
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.model.message.MessageContent
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.MXDecryptionException
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
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
import timber.log.Timber


internal class CryptoSyncHandler(private val cryptoManager: CryptoManager,
private val sasVerificationService: DefaultSasVerificationService) {

fun handleToDevice(toDevice: ToDeviceSyncResponse) {
toDevice.events?.forEach {
sasVerificationService.onToDeviceEvent(it)
cryptoManager.onToDeviceEvent(it)
}
toDevice.events?.forEach { event ->
// Decrypt event if necessary
decryptEvent(event, null)

if (TextUtils.equals(event.getClearType(), EventType.MESSAGE)
&& event.mClearEvent?.content?.toModel<MessageContent>()?.type == "m.bad.encrypted") {
Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.content)
} else {
sasVerificationService.onToDeviceEvent(event)
cryptoManager.onToDeviceEvent(event)
}
}
}

fun onSyncCompleted(syncResponse: SyncResponse, fromToken: String?, catchingUp: Boolean) {
cryptoManager.onSyncCompleted(syncResponse, fromToken, catchingUp)
}


/**
* Decrypt an encrypted event
*
* @param event the event to decrypt
* @param timelineId the timeline identifier
* @return true if the event has been decrypted
*/
private fun decryptEvent(event: Event, timelineId: String?): Boolean {
if (event.type == EventType.ENCRYPTED) {
var result: MXEventDecryptionResult? = null
try {
result = cryptoManager.decryptEvent(event, timelineId ?: "")
} catch (exception: MXDecryptionException) {
event.setCryptoError(exception.cryptoError)
}

if (null != result) {
event.setClearData(result)
return true
}
}

return false
}
}