Valere 2019-07-03 16:48:53 +02:00 committed by Benoit Marty
parent 20c8e8d922
commit b4ea85fc76
7 changed files with 83 additions and 82 deletions

View File

@ -81,6 +81,7 @@ class MXCryptoError(var code: String,
/** /**
* Error codes * Error codes
*/ */
const val UNKNOWN_ERROR_CODE = "UNKNOWN_ERROR_CODE"
const val ENCRYPTING_NOT_ENABLED_ERROR_CODE = "ENCRYPTING_NOT_ENABLED" const val ENCRYPTING_NOT_ENABLED_ERROR_CODE = "ENCRYPTING_NOT_ENABLED"
const val UNABLE_TO_ENCRYPT_ERROR_CODE = "UNABLE_TO_ENCRYPT" const val UNABLE_TO_ENCRYPT_ERROR_CODE = "UNABLE_TO_ENCRYPT"
const val UNABLE_TO_DECRYPT_ERROR_CODE = "UNABLE_TO_DECRYPT" const val UNABLE_TO_DECRYPT_ERROR_CODE = "UNABLE_TO_DECRYPT"

View File

@ -388,12 +388,12 @@ internal class CryptoManager @Inject constructor(
var isUpdated = false var isUpdated = false
val deviceIds = devicesIdListByUserId[userId] val deviceIds = devicesIdListByUserId[userId]


for (deviceId in deviceIds!!) { deviceIds?.forEach { deviceId ->
val device = storedDeviceIDs[deviceId] val device = storedDeviceIDs[deviceId]


// assume if the device is either verified or blocked // assume if the device is either verified or blocked
// it means that the device is known // it means that the device is known
if (null != device && device.isUnknown) { if (device?.isUnknown == true) {
device.verified = MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED device.verified = MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED
isUpdated = true isUpdated = true
} }
@ -445,7 +445,7 @@ internal class CryptoManager @Inject constructor(
val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm) val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm)


if (!encryptingClass) { if (!encryptingClass) {
Timber.e("## setEncryptionInRoom() : Unable to encrypt with " + algorithm!!) Timber.e("## setEncryptionInRoom() : Unable to encrypt room ${roomId} with $algorithm")
return false return false
} }


@ -560,7 +560,7 @@ internal class CryptoManager @Inject constructor(
.fold( .fold(
{ callback.onFailure(it) }, { callback.onFailure(it) },
{ {
Timber.v("## encryptEventContent() : succeeds after " + (System.currentTimeMillis() - t0) + " ms") Timber.v("## encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
callback.onSuccess(MXEncryptEventContentResult(it, EventType.ENCRYPTED)) callback.onSuccess(MXEncryptEventContentResult(it, EventType.ENCRYPTED))
} }
) )
@ -615,16 +615,17 @@ internal class CryptoManager @Inject constructor(
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
* @return the MXEventDecryptionResult data, or null in case of error wrapped into [Try] * @return the MXEventDecryptionResult data, or null in case of error wrapped into [Try]
*/ */
private suspend fun internalDecryptEvent(event: Event, timeline: String): Try<MXEventDecryptionResult?> { private suspend fun internalDecryptEvent(event: Event, timeline: String): Try<MXEventDecryptionResult> {
return Try { return Try {
val eventContent = event.content val eventContent = event.content
if (eventContent == null) { if (eventContent == null) {
Timber.e("## decryptEvent : empty event content") Timber.e("## decryptEvent : empty event content")
return@Try null throw MXDecryptionException(MXCryptoError(MXCryptoError.UNKNOWN_ERROR_CODE, MXCryptoError.UNKNOWN_ERROR_CODE))
} }
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String) val algorithm = eventContent["algorithm"]?.toString()
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
if (alg == null) { if (alg == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String) val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
Timber.e("## decryptEvent() : $reason") Timber.e("## decryptEvent() : $reason")
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason)) throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason))
} else { } else {
@ -676,7 +677,7 @@ internal class CryptoManager @Inject constructor(
} }
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm) val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
if (alg == null) { if (alg == null) {
Timber.e("## onRoomKeyEvent() : Unable to handle keys for " + roomKeyContent.algorithm) Timber.e("## onRoomKeyEvent() : Unable to handle keys for ${roomKeyContent.algorithm}")
return return
} }
alg.onRoomKeyEvent(event, keysBackup) alg.onRoomKeyEvent(event, keysBackup)
@ -692,9 +693,9 @@ internal class CryptoManager @Inject constructor(
val params = LoadRoomMembersTask.Params(roomId) val params = LoadRoomMembersTask.Params(roomId)
loadRoomMembersTask loadRoomMembersTask
.execute(params) .execute(params)
.map { allLoaded -> .map { _ ->
val userIds = getRoomUserIds(roomId) val userIds = getRoomUserIds(roomId)
setEncryptionInRoom(roomId, event.content!!["algorithm"] as String, true, userIds) setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), true, userIds)
} }
} }
} }
@ -839,7 +840,7 @@ internal class CryptoManager @Inject constructor(
val roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password) val roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password)
val t1 = System.currentTimeMillis() val t1 = System.currentTimeMillis()


Timber.v("## importRoomKeys : decryptMegolmKeyFile done in " + (t1 - t0) + " ms") Timber.v("""## importRoomKeys : decryptMegolmKeyFile done in ${t1 - t0} ms""")


val importedSessions = MoshiProvider.providesMoshi() val importedSessions = MoshiProvider.providesMoshi()
.adapter<List<MegolmSessionData>>(Types.newParameterizedType(List::class.java, MegolmSessionData::class.java)) .adapter<List<MegolmSessionData>>(Types.newParameterizedType(List::class.java, MegolmSessionData::class.java))
@ -847,7 +848,7 @@ internal class CryptoManager @Inject constructor(


val t2 = System.currentTimeMillis() val t2 = System.currentTimeMillis()


Timber.v("## importRoomKeys : JSON parsing " + (t2 - t1) + " ms") Timber.v("""## importRoomKeys : JSON parsing ${t2 - t1} ms""")


if (importedSessions == null) { if (importedSessions == null) {
throw Exception("Error") throw Exception("Error")
@ -931,11 +932,8 @@ internal class CryptoManager @Inject constructor(
*/ */
// TODO add this info in CryptoRoomEntity? // TODO add this info in CryptoRoomEntity?
override fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean { override fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean {
return if (null != roomId) { return roomId?.let { cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(it) }
cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId) ?: false
} else {
false
}
} }


/** /**
@ -993,18 +991,18 @@ internal class CryptoManager @Inject constructor(
* @param event the event to decrypt again. * @param event the event to decrypt again.
*/ */
override fun reRequestRoomKeyForEvent(event: Event) { override fun reRequestRoomKeyForEvent(event: Event) {
val wireContent = event.content!! val wireContent = event.content

if (wireContent == null) {
val algorithm = wireContent["algorithm"].toString() Timber.e("## reRequestRoomKeyForEvent Failed to re-request key, null content")
val senderKey = wireContent["sender_key"].toString() return
val sessionId = wireContent["session_id"].toString() }


val requestBody = RoomKeyRequestBody() val requestBody = RoomKeyRequestBody()


requestBody.roomId = event.roomId requestBody.roomId = event.roomId
requestBody.algorithm = algorithm requestBody.algorithm = wireContent["algorithm"].toString()
requestBody.senderKey = senderKey requestBody.senderKey = wireContent["sender_key"].toString()
requestBody.sessionId = sessionId requestBody.sessionId = wireContent["session_id"].toString()


outgoingRoomKeyRequestManager.resendRoomKeyRequest(requestBody) outgoingRoomKeyRequestManager.resendRoomKeyRequest(requestBody)
} }
@ -1038,12 +1036,12 @@ internal class CryptoManager @Inject constructor(
val userIds = devicesInRoom.userIds val userIds = devicesInRoom.userIds
for (userId in userIds) { for (userId in userIds) {
val deviceIds = devicesInRoom.getUserDeviceIds(userId) val deviceIds = devicesInRoom.getUserDeviceIds(userId)
for (deviceId in deviceIds!!) { deviceIds?.forEach { deviceId ->
val deviceInfo = devicesInRoom.getObject(userId, deviceId) devicesInRoom.getObject(userId, deviceId)

?.takeIf { it.isUnknown }
if (deviceInfo?.isUnknown == true) { ?.let {
unknownDevices.setObject(userId, deviceId, deviceInfo) unknownDevices.setObject(userId, deviceId, it)
} }
} }
} }



View File

@ -29,12 +29,7 @@ import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.convertFromUTF8 import im.vector.matrix.android.internal.util.convertFromUTF8
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import org.matrix.olm.OlmAccount import org.matrix.olm.*
import org.matrix.olm.OlmInboundGroupSession
import org.matrix.olm.OlmMessage
import org.matrix.olm.OlmOutboundGroupSession
import org.matrix.olm.OlmSession
import org.matrix.olm.OlmUtility
import timber.log.Timber import timber.log.Timber
import java.net.URLEncoder import java.net.URLEncoder
import java.util.* import java.util.*
@ -119,13 +114,13 @@ internal class MXOlmDevice @Inject constructor(
try { try {
deviceCurve25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY] deviceCurve25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_IDENTITY_KEY + " with error") Timber.e(e, """## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_IDENTITY_KEY} with error""")
} }


try { try {
deviceEd25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY] deviceEd25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_FINGER_PRINT_KEY + " with error") Timber.e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_FINGER_PRINT_KEY} with error")
} }
} }


@ -297,13 +292,13 @@ internal class MXOlmDevice @Inject constructor(


val res = HashMap<String, String>() val res = HashMap<String, String>()


if (!TextUtils.isEmpty(payloadString)) { if (!payloadString.isNullOrEmpty()) {
res["payload"] = payloadString!! res["payload"] = payloadString
} }


val sessionIdentifier = olmSession.sessionIdentifier() val sessionIdentifier = olmSession.sessionIdentifier()


if (!TextUtils.isEmpty(sessionIdentifier)) { if (!sessionIdentifier.isNullOrEmpty()) {
res["session_id"] = sessionIdentifier res["session_id"] = sessionIdentifier
} }


@ -525,9 +520,7 @@ internal class MXOlmDevice @Inject constructor(


//If our existing session is better we keep it //If our existing session is better we keep it
if (newKnownFirstIndex != null && existingFirstKnown <= newKnownFirstIndex) { if (newKnownFirstIndex != null && existingFirstKnown <= newKnownFirstIndex) {
if (session.olmInboundGroupSession != null) { session.olmInboundGroupSession?.releaseSession()
session.olmInboundGroupSession!!.releaseSession()
}
return false return false
} }
} }
@ -545,7 +538,7 @@ internal class MXOlmDevice @Inject constructor(
return false return false
} }
} catch (e: Exception) { } catch (e: Exception) {
session.olmInboundGroupSession!!.releaseSession() session.olmInboundGroupSession?.releaseSession()
Timber.e(e, "## addInboundGroupSession : sessionIdentifier() failed") Timber.e(e, "## addInboundGroupSession : sessionIdentifier() failed")
return false return false
} }
@ -584,13 +577,13 @@ internal class MXOlmDevice @Inject constructor(
} }


// sanity check // sanity check
if (null == session || null == session.olmInboundGroupSession) { if (session?.olmInboundGroupSession == null) {
Timber.e("## importInboundGroupSession : invalid session") Timber.e("## importInboundGroupSession : invalid session")
continue continue
} }


try { try {
if (!TextUtils.equals(session.olmInboundGroupSession!!.sessionIdentifier(), sessionId)) { if (!TextUtils.equals(session.olmInboundGroupSession?.sessionIdentifier(), sessionId)) {
Timber.e("## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: " + senderKey!!) Timber.e("## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: " + senderKey!!)
if (session.olmInboundGroupSession != null) session.olmInboundGroupSession!!.releaseSession() if (session.olmInboundGroupSession != null) session.olmInboundGroupSession!!.releaseSession()
continue continue
@ -678,7 +671,7 @@ internal class MXOlmDevice @Inject constructor(
val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex) val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex)
Timber.e("## decryptGroupMessage() : $reason") Timber.e("## decryptGroupMessage() : $reason")
throw MXDecryptionException(MXCryptoError(MXCryptoError.DUPLICATED_MESSAGE_INDEX_ERROR_CODE, throw MXDecryptionException(MXCryptoError(MXCryptoError.DUPLICATED_MESSAGE_INDEX_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, reason)) MXCryptoError.UNABLE_TO_DECRYPT, reason))
} }


inboundGroupSessionMessageIndexes[timeline]!!.put(messageIndexKey, true) inboundGroupSessionMessageIndexes[timeline]!!.put(messageIndexKey, true)
@ -711,7 +704,7 @@ internal class MXOlmDevice @Inject constructor(
val reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.roomId) val reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.roomId)
Timber.e("## decryptGroupMessage() : $reason") Timber.e("## decryptGroupMessage() : $reason")
throw MXDecryptionException(MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE, throw MXDecryptionException(MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, reason)) MXCryptoError.UNABLE_TO_DECRYPT, reason))
} }
} else { } else {
Timber.e("## decryptGroupMessage() : Cannot retrieve inbound group session $sessionId") Timber.e("## decryptGroupMessage() : Cannot retrieve inbound group session $sessionId")
@ -767,9 +760,9 @@ internal class MXOlmDevice @Inject constructor(
*/ */
private fun getSessionForDevice(theirDeviceIdentityKey: String, sessionId: String): OlmSessionWrapper? { private fun getSessionForDevice(theirDeviceIdentityKey: String, sessionId: String): OlmSessionWrapper? {
// sanity check // sanity check
return if (!TextUtils.isEmpty(theirDeviceIdentityKey) && !TextUtils.isEmpty(sessionId)) { return if (theirDeviceIdentityKey.isEmpty() || sessionId.isEmpty()) null else {
store.getDeviceSession(sessionId, theirDeviceIdentityKey) store.getDeviceSession(sessionId, theirDeviceIdentityKey)
} else null }


} }


@ -785,7 +778,8 @@ internal class MXOlmDevice @Inject constructor(
fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): OlmInboundGroupSessionWrapper? { fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): OlmInboundGroupSessionWrapper? {
inboundGroupSessionWithIdError = null inboundGroupSessionWithIdError = null


val session = store.getInboundGroupSession(sessionId!!, senderKey!!) if (sessionId.isNullOrBlank() || senderKey.isNullOrBlank()) return null
val session = store.getInboundGroupSession(sessionId, senderKey)


if (null != session) { if (null != session) {
// Check that the room id matches the original one for the session. This stops // Check that the room id matches the original one for the session. This stops
@ -794,12 +788,12 @@ internal class MXOlmDevice @Inject constructor(
val errorDescription = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.roomId) val errorDescription = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.roomId)
Timber.e("## getInboundGroupSession() : $errorDescription") Timber.e("## getInboundGroupSession() : $errorDescription")
inboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE, inboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, errorDescription) MXCryptoError.UNABLE_TO_DECRYPT, errorDescription)
} }
} else { } else {
Timber.e("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId") Timber.e("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId")
inboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, inboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE,
MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON, null) MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON, null)
} }
return session return session
} }

View File

@ -37,7 +37,7 @@ internal interface IMXDecrypting {
* @throws MXDecryptionException the decryption failure reason * @throws MXDecryptionException the decryption failure reason
*/ */
@Throws(MXDecryptionException::class) @Throws(MXDecryptionException::class)
suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult


/** /**
* Handle a key event. * Handle a key event.

View File

@ -43,6 +43,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import kotlin.collections.HashMap


internal class MXMegolmDecryption(private val credentials: Credentials, internal class MXMegolmDecryption(private val credentials: Credentials,
private val olmDevice: MXOlmDevice, private val olmDevice: MXOlmDevice,
@ -64,19 +65,19 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
private var pendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap() private var pendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap()


@Throws(MXDecryptionException::class) @Throws(MXDecryptionException::class)
override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? { override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
return decryptEvent(event, timeline, true) return decryptEvent(event, timeline, true)
} }


@Throws(MXDecryptionException::class) @Throws(MXDecryptionException::class)
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult? { private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult {
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!! val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!!
if (TextUtils.isEmpty(encryptedEventContent.senderKey) || TextUtils.isEmpty(encryptedEventContent.sessionId) || TextUtils.isEmpty(encryptedEventContent.ciphertext)) { if (TextUtils.isEmpty(encryptedEventContent.senderKey) || TextUtils.isEmpty(encryptedEventContent.sessionId) || TextUtils.isEmpty(encryptedEventContent.ciphertext)) {
throw MXDecryptionException(MXCryptoError(MXCryptoError.MISSING_FIELDS_ERROR_CODE, throw MXDecryptionException(MXCryptoError(MXCryptoError.MISSING_FIELDS_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_FIELDS_REASON)) MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_FIELDS_REASON))
} }


var eventDecryptionResult: MXEventDecryptionResult? = null val eventDecryptionResult: MXEventDecryptionResult?
var cryptoError: MXCryptoError? = null var cryptoError: MXCryptoError? = null
var decryptGroupMessageResult: MXDecryptionResult? = null var decryptGroupMessageResult: MXDecryptionResult? = null


@ -86,17 +87,19 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
cryptoError = e.cryptoError cryptoError = e.cryptoError
} }
// the decryption succeeds // the decryption succeeds
if (decryptGroupMessageResult?.payload != null && cryptoError == null) { if (decryptGroupMessageResult?.payload != null) {
eventDecryptionResult = MXEventDecryptionResult() eventDecryptionResult = MXEventDecryptionResult()


eventDecryptionResult.clearEvent = decryptGroupMessageResult.payload eventDecryptionResult.clearEvent = decryptGroupMessageResult.payload
eventDecryptionResult.senderCurve25519Key = decryptGroupMessageResult.senderKey eventDecryptionResult.senderCurve25519Key = decryptGroupMessageResult.senderKey


if (null != decryptGroupMessageResult.keysClaimed) { if (null != decryptGroupMessageResult.keysClaimed) {
eventDecryptionResult.claimedEd25519Key = decryptGroupMessageResult.keysClaimed!!["ed25519"] eventDecryptionResult.claimedEd25519Key = decryptGroupMessageResult.keysClaimed?.get("ed25519")
} }


eventDecryptionResult.forwardingCurve25519KeyChain = decryptGroupMessageResult.forwardingCurve25519KeyChain!! eventDecryptionResult.forwardingCurve25519KeyChain = decryptGroupMessageResult.forwardingCurve25519KeyChain
?: emptyList()
return eventDecryptionResult
} else if (cryptoError != null) { } else if (cryptoError != null) {
if (cryptoError.isOlmError) { if (cryptoError.isOlmError) {
if (MXCryptoError.UNKNOWN_MESSAGE_INDEX == cryptoError.message) { if (MXCryptoError.UNKNOWN_MESSAGE_INDEX == cryptoError.message) {
@ -118,13 +121,13 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
if (requestKeysOnFail) { if (requestKeysOnFail) {
requestKeysForEvent(event) requestKeysForEvent(event)
} }
throw MXDecryptionException(cryptoError)
} }
throw MXDecryptionException(cryptoError)
} }

throw MXDecryptionException(MXCryptoError(MXCryptoError.UNKNOWN_ERROR_CODE, MXCryptoError.UNKNOWN_ERROR_CODE))
return eventDecryptionResult
} }



/** /**
* Helper for the real decryptEvent and for _retryDecryption. If * Helper for the real decryptEvent and for _retryDecryption. If
* requestKeysOnFail is true, we'll send an m.room_key_request when we fail * requestKeysOnFail is true, we'll send an m.room_key_request when we fail
@ -172,6 +175,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return
val pendingEventsKey = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}" val pendingEventsKey = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}"



if (!pendingEvents.containsKey(pendingEventsKey)) { if (!pendingEvents.containsKey(pendingEventsKey)) {
pendingEvents[pendingEventsKey] = HashMap() pendingEvents[pendingEventsKey] = HashMap()
} }
@ -197,22 +201,25 @@ internal class MXMegolmDecryption(private val credentials: Credentials,


var senderKey: String? = event.getSenderKey() var senderKey: String? = event.getSenderKey()
var keysClaimed: MutableMap<String, String> = HashMap() var keysClaimed: MutableMap<String, String> = HashMap()
var forwardingCurve25519KeyChain: MutableList<String> = ArrayList() val forwardingCurve25519KeyChain: MutableList<String> = ArrayList()


if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.sessionId) || TextUtils.isEmpty(roomKeyContent.sessionKey)) { if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.sessionId) || TextUtils.isEmpty(roomKeyContent.sessionKey)) {
Timber.e("## onRoomKeyEvent() : Key event is missing fields") Timber.e("## onRoomKeyEvent() : Key event is missing fields")
return return
} }
if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) { if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
Timber.v("## onRoomKeyEvent(), forward adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId Timber.v("## onRoomKeyEvent(), forward adding key : roomId ${roomKeyContent.roomId} sessionId ${roomKeyContent.sessionId} sessionKey ${roomKeyContent.sessionKey}") // from " + event);
+ " sessionKey " + roomKeyContent.sessionKey) // from " + event);
val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>() val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()
?: return ?: return
forwardingCurve25519KeyChain = if (forwardedRoomKeyContent.forwardingCurve25519KeyChain == null) {
ArrayList() forwardedRoomKeyContent.forwardingCurve25519KeyChain?.let {
} else { forwardingCurve25519KeyChain.addAll(it)
ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain)
} }
// forwardingCurve25519KeyChain = if (forwardedRoomKeyContent.forwardingCurve25519KeyChain == null) {
// ArrayList()
// } else {
// ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain)
// }


if (senderKey == null) { if (senderKey == null) {
Timber.e("## onRoomKeyEvent() : event is missing sender_key field") Timber.e("## onRoomKeyEvent() : event is missing sender_key field")
@ -284,8 +291,10 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
} }


override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean { override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
return (null != request.requestBody val roomId = request.requestBody?.roomId ?: return false
&& olmDevice.hasInboundSessionKeys(request.requestBody!!.roomId!!, request.requestBody!!.senderKey!!, request.requestBody!!.sessionId!!)) val senderKey = request.requestBody?.senderKey ?: return false
val sessionId = request.requestBody?.sessionId ?: return false
return olmDevice.hasInboundSessionKeys(roomId, senderKey, sessionId)
} }


override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) { override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {
@ -293,13 +302,13 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
if (request.requestBody == null) { if (request.requestBody == null) {
return return
} }
val userId = request.userId!! val userId = request.userId ?: return
CoroutineScope(coroutineDispatchers.crypto).launch { CoroutineScope(coroutineDispatchers.crypto).launch {
deviceListManager deviceListManager
.downloadKeys(listOf(userId), false) .downloadKeys(listOf(userId), false)
.flatMap { .flatMap {
val deviceId = request.deviceId val deviceId = request.deviceId
val deviceInfo = cryptoStore.getUserDevice(deviceId!!, userId) val deviceInfo = cryptoStore.getUserDevice(deviceId ?: "", userId)
if (deviceInfo == null) { if (deviceInfo == null) {
throw RuntimeException() throw RuntimeException()
} else { } else {
@ -315,9 +324,8 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
// were no one-time keys. // were no one-time keys.
Try.just(Unit) Try.just(Unit)
} }
Timber.v("## shareKeysWithDevice() : sharing keys for session " + body!!.senderKey + "|" + body.sessionId Timber.v("""## shareKeysWithDevice() : sharing keys for session ${body?.senderKey}|${body?.sessionId} with device $userId:$deviceId""")
+ " with device " + userId + ":" + deviceId) val inboundGroupSession = olmDevice.getInboundGroupSession(body?.sessionId, body?.senderKey, body?.roomId)
val inboundGroupSession = olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId)


val payloadJson = HashMap<String, Any>() val payloadJson = HashMap<String, Any>()
payloadJson["type"] = EventType.FORWARDED_ROOM_KEY payloadJson["type"] = EventType.FORWARDED_ROOM_KEY

View File

@ -43,7 +43,7 @@ internal class MXOlmDecryption(
: IMXDecrypting { : IMXDecrypting {


@Throws(MXDecryptionException::class) @Throws(MXDecryptionException::class)
override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? { override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
val olmEventContent = event.content.toModel<OlmEventContent>()!! val olmEventContent = event.content.toModel<OlmEventContent>()!!


if (null == olmEventContent.ciphertext) { if (null == olmEventContent.ciphertext) {

View File

@ -21,4 +21,4 @@ import com.airbnb.mvrx.MvRxState
import im.vector.riotx.BuildConfig import im.vector.riotx.BuildConfig


abstract class VectorViewModel<S : MvRxState>(initialState: S) abstract class VectorViewModel<S : MvRxState>(initialState: S)
: BaseMvRxViewModel<S>(initialState, debugMode = BuildConfig.DEBUG) : BaseMvRxViewModel<S>(initialState, false)