Crypto: continue cleaning + fix some issues.

This commit is contained in:
ganfra 2019-06-07 16:01:24 +02:00
parent c4d7711d2f
commit 664e5354d3
16 changed files with 154 additions and 151 deletions

View File

@ -92,34 +92,10 @@ interface CryptoService {
roomId: String, roomId: String,
callback: MatrixCallback<MXEncryptEventContentResult>) callback: MatrixCallback<MXEncryptEventContentResult>)


/*
fun start(isInitialSync: Boolean, aCallback: MatrixCallback<Unit>?)

fun isStarted(): Boolean

fun isStarting(): Boolean

fun close()


fun getOlmDevice(): MXOlmDevice?

fun checkUnknownDevices(userIds: List<String>, callback: MatrixCallback<Unit>)

fun warnOnUnknownDevices(): Boolean

@Throws(MXDecryptionException::class)
fun decryptEvent(event: Event, timelineId: String?): MXEventDecryptionResult?

fun resetReplayAttackCheckInTimeline(timelineId: String)


@VisibleForTesting
fun ensureOlmSessionsForUsers(users: List<String>, callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>)
*/

fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult?


fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>)

fun getEncryptionAlgorithm(roomId: String): String? fun getEncryptionAlgorithm(roomId: String): String?


fun shouldEncryptForInvitedMembers(roomId: String): Boolean fun shouldEncryptForInvitedMembers(roomId: String): Boolean

View File

@ -23,5 +23,5 @@ import com.squareup.moshi.JsonClass


@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class RoomHistoryVisibilityContent( data class RoomHistoryVisibilityContent(
@Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility @Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility? = null
) )

View File

@ -73,6 +73,7 @@ import org.matrix.olm.OlmManager
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.EmptyCoroutineContext


/** /**
* A `CryptoService` class instance manages the end-to-end crypto for a session. * A `CryptoService` class instance manages the end-to-end crypto for a session.
@ -134,22 +135,8 @@ internal class CryptoManager(


// MXEncrypting instance for each room. // MXEncrypting instance for each room.
private val roomEncryptors: MutableMap<String, IMXEncrypting> = HashMap() private val roomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()

private val isStarting = AtomicBoolean(false)
// the encryption is starting private val isStarted = AtomicBoolean(false)
private var isStarting = AtomicBoolean(false)

// tell if the crypto is started
private var isStarted = AtomicBoolean(false)

// TODO
//private val mNetworkListener = object : IMXNetworkEventListener {
// override fun onNetworkConnectionUpdate(isConnected: Boolean) {
// if (isConnected && !isStarted()) {
// Timber.v("Start MXCrypto because a network connection has been retrieved ")
// start(false, null)
// }
// }
//}


fun onStateEvent(roomId: String, event: Event) { fun onStateEvent(roomId: String, event: Event) {
when { when {
@ -262,8 +249,6 @@ internal class CryptoManager(
internalStart(isInitialSync) internalStart(isInitialSync)
}, },
{ {
isStarting.set(false)
isStarted.set(true)
outgoingRoomKeyRequestManager.start() outgoingRoomKeyRequestManager.start()
keysBackup.checkAndStartKeysBackup() keysBackup.checkAndStartKeysBackup()
if (isInitialSync) { if (isInitialSync) {
@ -273,6 +258,8 @@ internal class CryptoManager(
} else { } else {
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests() incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
} }
isStarting.set(false)
isStarted.set(true)
} }
) )
} }
@ -589,21 +576,54 @@ internal class CryptoManager(
*/ */
@Throws(MXDecryptionException::class) @Throws(MXDecryptionException::class)
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? { override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
val eventContent = event.content
if (eventContent == null) {
Timber.e("## decryptEvent : empty event content")
return null
}
return runBlocking { return runBlocking {
withContext(coroutineDispatchers.crypto) { internalDecryptEvent(event, timeline).fold(
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String) { throw it },
if (alg == null) { { it }
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String) )
Timber.e("## decryptEvent() : $reason") }
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason)) }
} else {
alg.decryptEvent(event, timeline) /**
} * Decrypt an event asynchronously
*
* @param event the raw event.
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
* @param callback the callback to return data or null
*/
override fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>) {
GlobalScope.launch(EmptyCoroutineContext) {
val result = withContext(coroutineDispatchers.crypto) {
internalDecryptEvent(event, timeline)
}
result.fold(
{ callback.onFailure(it) },
{ callback.onSuccess(it) }
)
}
}

/**
* Decrypt an event
*
* @param event the raw event.
* @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]
*/
private suspend fun internalDecryptEvent(event: Event, timeline: String): Try<MXEventDecryptionResult?> {
return Try {
val eventContent = event.content
if (eventContent == null) {
Timber.e("## decryptEvent : empty event content")
return@Try null
}
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String)
if (alg == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
Timber.e("## decryptEvent() : $reason")
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason))
} else {
alg.decryptEvent(event, timeline)
} }
} }
} }
@ -624,10 +644,16 @@ internal class CryptoManager(
*/ */
fun onToDeviceEvent(event: Event) { fun onToDeviceEvent(event: Event) {
CoroutineScope(coroutineDispatchers.crypto).launch { CoroutineScope(coroutineDispatchers.crypto).launch {
if (event.getClearType() == EventType.ROOM_KEY || event.getClearType() == EventType.FORWARDED_ROOM_KEY) { when (event.getClearType()) {
onRoomKeyEvent(event) EventType.ROOM_KEY, EventType.FORWARDED_ROOM_KEY -> {
} else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) { onRoomKeyEvent(event)
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event) }
EventType.ROOM_KEY_REQUEST -> {
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
}
else -> {
//ignore
}
} }
} }
} }
@ -638,7 +664,7 @@ internal class CryptoManager(
* @param event the key event. * @param event the key event.
*/ */
private fun onRoomKeyEvent(event: Event) { private fun onRoomKeyEvent(event: Event) {
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!! val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) { if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
Timber.e("## onRoomKeyEvent() : missing fields") Timber.e("## onRoomKeyEvent() : missing fields")
return return
@ -722,7 +748,6 @@ internal class CryptoManager(


private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) { private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>() val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()

eventContent?.historyVisibility?.let { eventContent?.historyVisibility?.let {
cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED) cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED)
} }

View File

@ -166,7 +166,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
* @param timelineId the timeline identifier * @param timelineId the timeline identifier
*/ */
private fun addEventToPendingList(event: Event, timelineId: String) { private fun addEventToPendingList(event: Event, timelineId: String) {
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!! 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)) {
@ -190,7 +190,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
*/ */
override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) { override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {
var exportFormat = false var exportFormat = false
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!! val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return


var senderKey: String? = event.getSenderKey() var senderKey: String? = event.getSenderKey()
var keysClaimed: MutableMap<String, String> = HashMap() var keysClaimed: MutableMap<String, String> = HashMap()
@ -203,11 +203,11 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
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
forwardingCurve25519KeyChain = if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) { forwardingCurve25519KeyChain = if (forwardedRoomKeyContent.forwardingCurve25519KeyChain == null) {
ArrayList() ArrayList()
} else { } else {
ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain!!) ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain)
} }
forwardingCurve25519KeyChain.add(senderKey!!) forwardingCurve25519KeyChain.add(senderKey!!)


@ -262,6 +262,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
*/ */
override fun onNewSession(senderKey: String, sessionId: String) { override fun onNewSession(senderKey: String, sessionId: String) {
//TODO see how to handle this //TODO see how to handle this
Timber.v("ON NEW SESSION $sessionId - $senderKey")
/*val k = "$senderKey|$sessionId" /*val k = "$senderKey|$sessionId"


val pending = pendingEvents[k] val pending = pendingEvents[k]

View File

@ -28,29 +28,29 @@ data class EncryptedEventContent(
* the used algorithm * the used algorithm
*/ */
@Json(name = "algorithm") @Json(name = "algorithm")
var algorithm: String? = null, val algorithm: String? = null,


/** /**
* The encrypted event * The encrypted event
*/ */
@Json(name = "ciphertext") @Json(name = "ciphertext")
var ciphertext: String? = null, val ciphertext: String? = null,


/** /**
* The device id * The device id
*/ */
@Json(name = "device_id") @Json(name = "device_id")
var deviceId: String? = null, val deviceId: String? = null,


/** /**
* the sender key * the sender key
*/ */
@Json(name = "sender_key") @Json(name = "sender_key")
var senderKey: String? = null, val senderKey: String? = null,


/** /**
* The session id * The session id
*/ */
@Json(name = "session_id") @Json(name = "session_id")
var sessionId: String? = null val sessionId: String? = null
) )

View File

@ -25,18 +25,18 @@ import com.squareup.moshi.JsonClass
data class RoomKeyContent( data class RoomKeyContent(


@Json(name = "algorithm") @Json(name = "algorithm")
var algorithm: String? = null, val algorithm: String? = null,


@Json(name = "room_id") @Json(name = "room_id")
var roomId: String? = null, val roomId: String? = null,


@Json(name = "session_id") @Json(name = "session_id")
var sessionId: String? = null, val sessionId: String? = null,


@Json(name = "session_key") @Json(name = "session_key")
var sessionKey: String? = null, val sessionKey: String? = null,


// should be a Long but it is sometimes a double // should be a Long but it is sometimes a double
@Json(name = "chain_index") @Json(name = "chain_index")
var chainIndex: Any? = null val chainIndex: Any? = null
) )

View File

@ -25,23 +25,23 @@ import com.squareup.moshi.JsonClass
data class ForwardedRoomKeyContent( data class ForwardedRoomKeyContent(


@Json(name = "algorithm") @Json(name = "algorithm")
var algorithm: String? = null, val algorithm: String? = null,


@Json(name = "room_id") @Json(name = "room_id")
var roomId: String? = null, val roomId: String? = null,


@Json(name = "sender_key") @Json(name = "sender_key")
var senderKey: String? = null, val senderKey: String? = null,


@Json(name = "session_id") @Json(name = "session_id")
var sessionId: String? = null, val sessionId: String? = null,


@Json(name = "session_key") @Json(name = "session_key")
var sessionKey: String? = null, val sessionKey: String? = null,


@Json(name = "forwarding_curve25519_key_chain") @Json(name = "forwarding_curve25519_key_chain")
var forwardingCurve25519KeyChain: List<String>? = null, val forwardingCurve25519KeyChain: List<String>? = null,


@Json(name = "sender_claimed_ed25519_key") @Json(name = "sender_claimed_ed25519_key")
var senderClaimedEd25519Key: String? = null val senderClaimedEd25519Key: String? = null
) )

View File

@ -54,14 +54,14 @@ import kotlin.collections.HashMap
* Short codes interactive verification is a more user friendly way of verifying devices * Short codes interactive verification is a more user friendly way of verifying devices
* that is still maintaining a good level of security (alternative to the 43-character strings compare method). * that is still maintaining a good level of security (alternative to the 43-character strings compare method).
*/ */
internal class DefaultSasVerificationService(private val mCredentials: Credentials, internal class DefaultSasVerificationService(private val credentials: Credentials,
private val mCryptoStore: IMXCryptoStore, private val cryptoStore: IMXCryptoStore,
private val mMyDeviceInfoHolder: MyDeviceInfoHolder, private val myDeviceInfoHolder: MyDeviceInfoHolder,
private val deviceListManager: DeviceListManager, private val deviceListManager: DeviceListManager,
private val setDeviceVerificationAction: SetDeviceVerificationAction, private val setDeviceVerificationAction: SetDeviceVerificationAction,
private val mSendToDeviceTask: SendToDeviceTask, private val sendToDeviceTask: SendToDeviceTask,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val mTaskExecutor: TaskExecutor) private val taskExecutor: TaskExecutor)
: VerificationTransaction.Listener, SasVerificationService { : VerificationTransaction.Listener, SasVerificationService {


private val uiHandler = Handler(Looper.getMainLooper()) private val uiHandler = Handler(Looper.getMainLooper())
@ -194,11 +194,11 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
val tx = IncomingSASVerificationTransaction( val tx = IncomingSASVerificationTransaction(
this, this,
setDeviceVerificationAction, setDeviceVerificationAction,
mCredentials, credentials,
mCryptoStore, cryptoStore,
mSendToDeviceTask, sendToDeviceTask,
mTaskExecutor, taskExecutor,
mMyDeviceInfoHolder.myDevice.fingerprint()!!, myDeviceInfoHolder.myDevice.fingerprint()!!,
startReq.transactionID!!, startReq.transactionID!!,
otherUserId) otherUserId)
addTransaction(tx) addTransaction(tx)
@ -363,11 +363,11 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
val tx = OutgoingSASVerificationRequest( val tx = OutgoingSASVerificationRequest(
this, this,
setDeviceVerificationAction, setDeviceVerificationAction,
mCredentials, credentials,
mCryptoStore, cryptoStore,
mSendToDeviceTask, sendToDeviceTask,
mTaskExecutor, taskExecutor,
mMyDeviceInfoHolder.myDevice.fingerprint()!!, myDeviceInfoHolder.myDevice.fingerprint()!!,
txID, txID,
userId, userId,
deviceID) deviceID)
@ -387,8 +387,8 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
private fun createUniqueIDForTransaction(userId: String, deviceID: String): String { private fun createUniqueIDForTransaction(userId: String, deviceID: String): String {
val buff = StringBuffer() val buff = StringBuffer()
buff buff
.append(mCredentials.userId).append("|") .append(credentials.userId).append("|")
.append(mCredentials.deviceId).append("|") .append(credentials.deviceId).append("|")
.append(userId).append("|") .append(userId).append("|")
.append(deviceID).append("|") .append(deviceID).append("|")
.append(UUID.randomUUID().toString()) .append(UUID.randomUUID().toString())
@ -413,7 +413,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
val contentMap = MXUsersDevicesMap<Any>() val contentMap = MXUsersDevicesMap<Any>()
contentMap.setObject(cancelMessage, userId, userDevice) contentMap.setObject(cancelMessage, userId, userDevice)


mSendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId)) sendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId))
.dispatchTo(object : MatrixCallback<Unit> { .dispatchTo(object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) { override fun onSuccess(data: Unit) {
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}") Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
@ -423,6 +423,6 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.") Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.")
} }
}) })
.executeBy(mTaskExecutor) .executeBy(taskExecutor)
} }
} }

View File

@ -103,13 +103,13 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
val contentModule = ContentModule().definition val contentModule = ContentModule().definition
val cryptoModule = CryptoModule().definition val cryptoModule = CryptoModule().definition
MatrixKoinHolder.instance.loadModules(listOf(sessionModule, MatrixKoinHolder.instance.loadModules(listOf(sessionModule,
syncModule, syncModule,
roomModule, roomModule,
groupModule, groupModule,
userModule, userModule,
signOutModule, signOutModule,
contentModule, contentModule,
cryptoModule)) cryptoModule))
scope = getKoin().getOrCreateScope(SCOPE) scope = getKoin().getOrCreateScope(SCOPE)
if (!monarchy.isMonarchyThreadOpen) { if (!monarchy.isMonarchyThreadOpen) {
monarchy.openManually() monarchy.openManually()
@ -350,6 +350,10 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
return cryptoService.decryptEvent(event, timeline) return cryptoService.decryptEvent(event, timeline)
} }


override fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>) {
return cryptoService.decryptEventAsync(event, timeline, callback)
}

override fun getEncryptionAlgorithm(roomId: String): String? { override fun getEncryptionAlgorithm(roomId: String): String? {
return cryptoService.getEncryptionAlgorithm(roomId) return cryptoService.getEncryptionAlgorithm(roomId)
} }

View File

@ -16,7 +16,9 @@


package im.vector.matrix.android.internal.session.room.timeline 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.crypto.CryptoService
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.EventType
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.crypto.MXDecryptionException import im.vector.matrix.android.internal.crypto.MXDecryptionException
@ -44,23 +46,7 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
} }
val event = eventEntity.asDomain() val event = eventEntity.asDomain()
if (event.getClearType() == EventType.ENCRYPTED) { if (event.getClearType() == EventType.ENCRYPTED) {
try { handleEncryptedEvent(event, eventEntity.localId)
Timber.v("Encrypted event: try to decrypt ${event.eventId}")
val result = if (decryptionCache.containsKey(eventEntity.localId)) {
Timber.v("Encrypted event ${event.eventId} cached")
decryptionCache[eventEntity.localId]
} else {
cryptoService.decryptEvent(event, timelineId)?.also {
decryptionCache[eventEntity.localId] = it
}
}
event.setClearData(result)
} catch (e: Exception) {
Timber.e(e, "Encrypted event: decryption failed")
if (e is MXDecryptionException) {
event.setCryptoError(e.cryptoError)
}
}
} }
return TimelineEvent( return TimelineEvent(
event, event,
@ -72,6 +58,28 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
) )
} }


private fun handleEncryptedEvent(event: Event, eventId: String) {
Timber.v("Encrypted event: try to decrypt ${event.eventId}")
val cachedDecryption = decryptionCache[eventId]
if (cachedDecryption != null) {
Timber.v("Encrypted event ${event.eventId} cached")
event.setClearData(cachedDecryption)
} else {
try {
val result = cryptoService.decryptEvent(event, timelineId)
if (result != null) {
decryptionCache[eventId] = result
}
event.setClearData(result)
} catch (failure: Throwable) {
Timber.e(failure, "Encrypted event: decryption failed")
if (failure is MXDecryptionException) {
event.setCryptoError(failure.cryptoError)
}
}
}
}

fun clear() { fun clear() {
senderCache.clear() senderCache.clear()
} }

View File

@ -47,7 +47,7 @@ internal class CryptoSyncHandler(private val cryptoManager: CryptoManager,
} }
} }


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



View File

@ -51,7 +51,7 @@ internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler,
userAccountDataSyncHandler.handle(syncResponse.accountData) userAccountDataSyncHandler.handle(syncResponse.accountData)
} }
Timber.v("On sync completed") Timber.v("On sync completed")
cryptoSyncHandler.onSyncCompleted(syncResponse, fromToken, isCatchingUp) cryptoSyncHandler.onSyncCompleted(syncResponse)
} }
val isInitialSync = fromToken == null val isInitialSync = fromToken == null
if (!cryptoManager.isStarted()) { if (!cryptoManager.isStarted()) {

View File

@ -67,7 +67,7 @@ class HomeModule {
roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()), roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()),
callItemFactory = CallItemFactory(get()), callItemFactory = CallItemFactory(get()),
encryptionItemFactory = EncryptionItemFactory(get()), encryptionItemFactory = EncryptionItemFactory(get()),
encryptedItemFactory = EncryptedItemFactory(get(), get(), messageItemFactory), encryptedItemFactory = EncryptedItemFactory(get()),
defaultItemFactory = DefaultItemFactory() defaultItemFactory = DefaultItemFactory()
) )
TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider) TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider)

View File

@ -20,29 +20,18 @@ import android.graphics.Typeface
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
import android.text.style.StyleSpan import android.text.style.StyleSpan
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.MXCryptoError 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.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.crypto.MXDecryptionException
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_


class EncryptedItemFactory( // This class handles timeline event who haven't been successfully decrypted
private val session: Session, class EncryptedItemFactory(private val stringProvider: StringProvider) {
private val stringProvider: StringProvider,
private val messageItemFactory: MessageItemFactory) {

fun create(timelineEvent: TimelineEvent,
nextEvent: TimelineEvent?,
callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {


fun create(timelineEvent: TimelineEvent): VectorEpoxyModel<*>? {
return when { return when {
EventType.ENCRYPTED == timelineEvent.root.getClearType() -> { EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
val cryptoError = timelineEvent.root.mCryptoError val cryptoError = timelineEvent.root.mCryptoError
@ -54,7 +43,6 @@ class EncryptedItemFactory(
} }


val message = stringProvider.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription) val message = stringProvider.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription)

val spannableStr = SpannableString(message) val spannableStr = SpannableString(message)
spannableStr.setSpan(StyleSpan(Typeface.ITALIC), 0, message.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) spannableStr.setSpan(StyleSpan(Typeface.ITALIC), 0, message.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
// TODO This is not correct format for error, change it // TODO This is not correct format for error, change it

View File

@ -39,8 +39,9 @@ class RoomHistoryVisibilityItemFactory(private val stringProvider: StringProvide
} }


private fun buildNoticeText(event: Event, senderName: String?): CharSequence? { private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
val content = event.content.toModel<RoomHistoryVisibilityContent>() ?: return null val historyVisibility = event.content.toModel<RoomHistoryVisibilityContent>()?.historyVisibility
val formattedVisibility = when (content.historyVisibility) { ?: return null
val formattedVisibility = when (historyVisibility) {
RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared) RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared)
RoomHistoryVisibility.INVITED -> stringProvider.getString(R.string.notice_room_visibility_invited) RoomHistoryVisibility.INVITED -> stringProvider.getString(R.string.notice_room_visibility_invited)
RoomHistoryVisibility.JOINED -> stringProvider.getString(R.string.notice_room_visibility_joined) RoomHistoryVisibility.JOINED -> stringProvider.getString(R.string.notice_room_visibility_joined)

View File

@ -51,7 +51,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,


EventType.ENCRYPTION -> encryptionItemFactory.create(event) EventType.ENCRYPTION -> encryptionItemFactory.create(event)


EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent, callback) EventType.ENCRYPTED -> encryptedItemFactory.create(event)


EventType.STATE_ROOM_THIRD_PARTY_INVITE, EventType.STATE_ROOM_THIRD_PARTY_INVITE,
EventType.STICKER, EventType.STICKER,