Crypto: decryption is working (but still a lot to do)

This commit is contained in:
ganfra 2019-05-26 19:21:45 +02:00
parent 3519ad7c8d
commit af338b0607
40 changed files with 233 additions and 351 deletions

View File

@ -19,13 +19,11 @@ package im.vector.matrix.android.api.session.events.model
import android.text.TextUtils
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Types
import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.util.JsonDict
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.*
typealias Content = JsonDict
@ -77,11 +75,7 @@ data class Event(
* @return true if event is state event.
*/
fun isStateEvent(): Boolean {
return EventType.isStateEvent(type)
}
companion object {
internal val CONTENT_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)
return EventType.isStateEvent(getClearType())
}
//==============================================================================================================
@ -138,24 +132,18 @@ data class Event(
*
* @param decryptionResult the decryption result, including the plaintext and some key info.
*/
fun setClearData(decryptionResult: MXEventDecryptionResult?) {
internal fun setClearData(decryptionResult: MXEventDecryptionResult?) {
mClearEvent = null
if (decryptionResult != null) {
if (decryptionResult.mClearEvent != null) {
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
mClearEvent = adapter.fromJsonValue(decryptionResult.mClearEvent)
if (null != decryptionResult) {
if (null != decryptionResult.mClearEvent) {
mClearEvent = decryptionResult.mClearEvent
}
if (null != mClearEvent) {
mClearEvent!!.mSenderCurve25519Key = decryptionResult.mSenderCurve25519Key
mClearEvent!!.mClaimedEd25519Key = decryptionResult.mClaimedEd25519Key
if (null != decryptionResult.mForwardingCurve25519KeyChain) {
mClearEvent!!.mForwardingCurve25519KeyChain = decryptionResult.mForwardingCurve25519KeyChain
} else {
mClearEvent!!.mForwardingCurve25519KeyChain = ArrayList()
}
mClearEvent?.apply {
mSenderCurve25519Key = decryptionResult.mSenderCurve25519Key
mClaimedEd25519Key = decryptionResult.mClaimedEd25519Key
mForwardingCurve25519KeyChain = decryptionResult.mForwardingCurve25519KeyChain
try {
// Add "m.relates_to" data from e2e event to the unencrypted event
// TODO
@ -166,12 +154,10 @@ data class Event(
} 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.
@ -203,11 +189,14 @@ data class Event(
* @return the event type
*/
fun getClearType(): String {
return if (null != mClearEvent) {
mClearEvent!!.type
} else {
type
return mClearEvent?.type ?: type
}
/**
* @return the event type
*/
fun getClearContent(): Content? {
return mClearEvent?.content ?: content
}
/**

View File

@ -149,7 +149,7 @@ class CreateRoomParams {
if (initialStates != null && !initialStates!!.isEmpty()) {
val newInitialStates = ArrayList<Event>()
for (event in initialStates!!) {
if (event.type != EventType.STATE_HISTORY_VISIBILITY) {
if (event.getClearType() != EventType.STATE_HISTORY_VISIBILITY) {
newInitialStates.add(event)
}
}

View File

@ -62,6 +62,6 @@ data class TimelineEvent(
}
fun isEncrypted() : Boolean {
return EventType.ENCRYPTED == root.type
return EventType.ENCRYPTED == root.getClearType()
}
}

View File

@ -16,4 +16,9 @@
package im.vector.matrix.android.api.util
import com.squareup.moshi.Types
import java.lang.reflect.ParameterizedType
typealias JsonDict = Map<String, @JvmSuppressWildcards Any>
internal val JSON_DICT_PARAMETERIZED_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)

View File

@ -21,6 +21,7 @@ package im.vector.matrix.android.internal.crypto
import android.content.Context
import android.os.Handler
import android.text.TextUtils
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.failure.Failure
@ -46,30 +47,25 @@ import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult
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.model.*
import im.vector.matrix.android.internal.crypto.model.event.RoomKeyContent
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
import im.vector.matrix.android.internal.crypto.tasks.DeleteDeviceTask
import im.vector.matrix.android.internal.crypto.tasks.GetDevicesTask
import im.vector.matrix.android.internal.crypto.tasks.GetKeyChangesTask
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.crypto.tasks.SetDeviceNameTask
import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask
import im.vector.matrix.android.internal.crypto.tasks.*
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.members.RoomMembers
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.matrix.olm.OlmManager
import timber.log.Timber
import java.util.*
@ -128,6 +124,9 @@ internal class CryptoManager(
private val mSendToDeviceTask: SendToDeviceTask,
private val mSetDeviceNameTask: SetDeviceNameTask,
private val mUploadKeysTask: UploadKeysTask,
private val loadRoomMembersTask: LoadRoomMembersTask,
private val monarchy: Monarchy,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
// TaskExecutor
private val mTaskExecutor: TaskExecutor
) : CryptoService {
@ -152,22 +151,18 @@ internal class CryptoManager(
//}
fun onStateEvent(roomId: String, event: Event) {
if (event.type == EventType.ENCRYPTION) {
// TODO Remove onRoomEncryptionEvent(roomId, event)
} else if (event.type == EventType.STATE_ROOM_MEMBER) {
onRoomMembershipEvent(roomId, event)
} else if (event.type == EventType.STATE_HISTORY_VISIBILITY) {
onRoomHistoryVisibilityEvent(roomId, event)
when {
event.getClearType() == EventType.ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
event.getClearType() == EventType.STATE_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
}
}
fun onLiveEvent(roomId: String, event: Event) {
if (event.type == EventType.ENCRYPTION) {
// TODO Remove onRoomEncryptionEvent(roomId, event)
} else if (event.type == EventType.STATE_ROOM_MEMBER) {
onRoomMembershipEvent(roomId, event)
} else if (event.type == EventType.STATE_HISTORY_VISIBILITY) {
onRoomHistoryVisibilityEvent(roomId, event)
when {
event.getClearType() == EventType.ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
event.getClearType() == EventType.STATE_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
}
}
@ -728,9 +723,9 @@ internal class CryptoManager(
* @param event the event
*/
fun onToDeviceEvent(event: Event) {
if (event.type == EventType.ROOM_KEY || event.type == EventType.FORWARDED_ROOM_KEY) {
if (event.getClearType() == EventType.ROOM_KEY || event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
onRoomKeyEvent(event)
} else if (event.type == EventType.ROOM_KEY_REQUEST) {
} else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
mIncomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
}
}
@ -742,7 +737,7 @@ internal class CryptoManager(
* @param event the key event.
*/
private fun onRoomKeyEvent(event: Event) {
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!!
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
Timber.e("## onRoomKeyEvent() : missing fields")
@ -764,8 +759,29 @@ internal class CryptoManager(
*
* @param event the encryption event.
*/
fun onRoomEncryptionEvent(event: Event, userIds: List<String>) {
setEncryptionInRoom(event.roomId!!, event.content!!["algorithm"] as String, true, userIds)
private fun onRoomEncryptionEvent(roomId: String, event: Event) {
CoroutineScope(coroutineDispatchers.encryption).launch {
val params = LoadRoomMembersTask.Params(roomId)
loadRoomMembersTask
.execute(params)
.map { allLoaded ->
var userIds: List<String> = emptyList()
monarchy.doWithRealm { realm ->
// Check whether the event content must be encrypted for the invited members.
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser()
&& shouldEncryptForInvitedMembers(roomId)
userIds = if (encryptForInvitedMembers) {
RoomMembers(realm, roomId).getActiveRoomMemberIds()
} else {
RoomMembers(realm, roomId).getJoinedRoomMemberIds()
}
}
setEncryptionInRoom(roomId, event.content!!["algorithm"] as String, true, userIds)
allLoaded
}
}
}
/**

View File

@ -99,7 +99,6 @@ internal class CryptoModule {
scope(DefaultSession.SCOPE) {
// Ensure OlmManager is loaded first
get<OlmManager>()
MXOlmDevice(get())
}
@ -172,31 +171,38 @@ internal class CryptoModule {
// CryptoManager
scope(DefaultSession.SCOPE) {
CryptoManager(
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
get(),
// Actions
get(),
get(),
get(),
// Factory
get(), get(),
mCredentials = get(),
mMyDeviceInfoHolder = get(),
mCryptoStore = get(),
mOlmDevice = get(),
mCryptoConfig = get(),
deviceListManager = get(),
mKeysBackup = get(),
mObjectSigner = get(),
mOneTimeKeysUploader = get(),
roomDecryptorProvider = get(),
mSasVerificationService = get(),
mIncomingRoomKeyRequestManager = get(),
mOutgoingRoomKeyRequestManager = get(),
mOlmManager = get(),
mSetDeviceVerificationAction = get(),
mMegolmSessionDataImporter = get(),
mEnsureOlmSessionsForDevicesAction = get(),
mWarnOnUnknownDevicesRepository = get(),
mMXMegolmEncryptionFactory = get(),
mMXOlmEncryptionFactory = get(),
mClaimOneTimeKeysForUsersDeviceTask = get(),
// Tasks
get(), get(), get(), get(), get(), get(), get(),
// Task executor
get()
mDeleteDeviceTask = get(),
mGetDevicesTask = get(),
mGetKeyChangesTask = get(),
mSendToDeviceTask = get(),
mSetDeviceNameTask = get(),
mUploadKeysTask = get(),
loadRoomMembersTask = get(),
monarchy = get(),
coroutineDispatchers = get(),
mTaskExecutor = get()
)
}

View File

@ -66,8 +66,7 @@ open class IncomingRoomKeyRequest {
*/
constructor(event: Event) {
mUserId = event.sender
val roomKeyShareRequest = event.content.toModel<RoomKeyShareRequest>()!!
val roomKeyShareRequest = event.getClearContent().toModel<RoomKeyShareRequest>()!!
mDeviceId = roomKeyShareRequest.requestingDeviceId
mRequestId = roomKeyShareRequest.requestId
mRequestBody = if (null != roomKeyShareRequest.body) roomKeyShareRequest.body else RoomKeyRequestBody()

View File

@ -51,7 +51,7 @@ internal class IncomingRoomKeyRequestManager(
* @param event the announcement event.
*/
fun onRoomKeyRequestEvent(event: Event) {
val roomKeyShare = event.content.toModel<RoomKeyShare>()
val roomKeyShare = event.getClearContent().toModel<RoomKeyShare>()
when (roomKeyShare?.action) {
RoomKeyShare.ACTION_SHARE_REQUEST -> synchronized(mReceivedRoomKeyRequests) {

View File

@ -17,7 +17,7 @@
package im.vector.matrix.android.internal.crypto
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.util.JsonDict
import java.util.*
/**
@ -28,7 +28,7 @@ data class MXEventDecryptionResult(
/**
* The plaintext payload for the event (typically containing "type" and "content" fields).
*/
var mClearEvent: Event? = null,
var mClearEvent: JsonDict? = null,
/**
* Key owned by the sender of this event.

View File

@ -19,7 +19,8 @@ package im.vector.matrix.android.internal.crypto
import android.text.TextUtils
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.util.JSON_DICT_PARAMETERIZED_TYPE
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
import im.vector.matrix.android.internal.crypto.model.MXOlmInboundGroupSession2
import im.vector.matrix.android.internal.crypto.model.MXOlmSession
@ -677,9 +678,10 @@ internal class MXOlmDevice(
mStore.storeInboundGroupSessions(listOf(session))
try {
val moshi = MoshiProvider.providesMoshi()
val adapter = moshi.adapter(Map::class.java)
result.mPayload = adapter.fromJson(convertFromUTF8(decryptResult.mDecryptedMessage)) as Event?
val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
val payload = adapter.fromJson(payloadString)
result.mPayload = payload
} catch (e: Exception) {
Timber.e(e, "## decryptGroupMessage() : RLEncoder.encode failed " + e.message)
return null

View File

@ -16,7 +16,7 @@
package im.vector.matrix.android.internal.crypto.algorithms
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.util.JsonDict
/**
* This class represents the decryption result.
@ -25,7 +25,7 @@ data class MXDecryptionResult(
/**
* The decrypted payload (with properties 'type', 'content')
*/
var mPayload: Event? = null,
var mPayload: JsonDict? = null,
/**
* keys that the sender of the event claims ownership of:

View File

@ -195,7 +195,7 @@ internal class MXMegolmDecryption(private val mCredentials: Credentials,
*/
override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {
var exportFormat = false
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!!
var senderKey: String? = event.getSenderKey()
var keysClaimed: MutableMap<String, String> = HashMap()
@ -206,10 +206,10 @@ internal class MXMegolmDecryption(private val mCredentials: Credentials,
return
}
if (event.type == EventType.FORWARDED_ROOM_KEY) {
if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
Timber.v("## onRoomKeyEvent(), forward adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId
+ " sessionKey " + roomKeyContent.sessionKey) // from " + event);
val forwardedRoomKeyContent = event.content.toModel<ForwardedRoomKeyContent>()!!
val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()!!
if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) {
forwarding_curve25519_key_chain = ArrayList()
@ -297,7 +297,6 @@ internal class MXMegolmDecryption(private val mCredentials: Credentials,
val fResut = result
CryptoAsyncHelper.getUiHandler().post {
event.setClearData(fResut)
TODO()
//mSession!!.onEventDecrypted(event)
}
Timber.v("## onNewSession() : successful re-decryption of " + event.eventId)

View File

@ -25,7 +25,6 @@ import im.vector.matrix.android.api.failure.Failure
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
@ -422,9 +421,8 @@ internal class MXMegolmEncryption(
payloadJson["content"] = queuedEncryption.mEventContent!!
// Get canonical Json from
val content = payloadJson.toContent()!!
val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, content))
val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson))
val ciphertext = olmDevice.encryptGroupMessage(session.mSessionId, payloadString!!)
val map = HashMap<String, Any>()
@ -437,7 +435,7 @@ internal class MXMegolmEncryption(
// m.new_device message if they don't have our session key.
map["device_id"] = mCredentials.deviceId!!
CryptoAsyncHelper.getUiHandler().post { queuedEncryption.mApiCallback?.onSuccess(map.toContent()!!) }
CryptoAsyncHelper.getUiHandler().post { queuedEncryption.mApiCallback?.onSuccess(map) }
session.mUseCount++
}

View File

@ -18,16 +18,20 @@
package im.vector.matrix.android.internal.crypto.algorithms.olm
import android.text.TextUtils
import com.squareup.moshi.Json
import im.vector.matrix.android.api.auth.data.Credentials
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.toModel
import im.vector.matrix.android.api.util.JSON_DICT_PARAMETERIZED_TYPE
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.crypto.MXDecryptionException
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting
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.di.MoshiProvider
import im.vector.matrix.android.internal.util.convertFromUTF8
import timber.log.Timber
import java.util.*
@ -58,24 +62,30 @@ internal class MXOlmDecryption(
}
// The message for myUser
val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as Map<String, Any>
val payloadString = decryptMessage(message, olmEventContent.senderKey!!)
val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as JsonDict
val decryptedPayload = decryptMessage(message, olmEventContent.senderKey!!)
if (null == payloadString) {
if (decryptedPayload == null) {
Timber.e("## decryptEvent() Failed to decrypt Olm event (id= " + event.eventId + " ) from " + olmEventContent.senderKey)
throw MXDecryptionException(MXCryptoError(MXCryptoError.BAD_ENCRYPTED_MESSAGE_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON))
}
val payloadString = convertFromUTF8(decryptedPayload)
if (payloadString == null) {
Timber.e("## decryptEvent() Failed to decrypt Olm event (id= " + event.eventId + " ) from " + olmEventContent.senderKey)
throw MXDecryptionException(MXCryptoError(MXCryptoError.BAD_ENCRYPTED_MESSAGE_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON))
}
val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
val payload = adapter.fromJson(payloadString)
val payload = convertFromUTF8(payloadString)
if (null == payload) {
if (payload == null) {
Timber.e("## decryptEvent failed : null payload")
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON))
}
val olmPayloadContent = OlmPayloadContent.fromJsonString(payload)
val olmPayloadContent = OlmPayloadContent.fromJsonString(payloadString)
if (TextUtils.isEmpty(olmPayloadContent.recipient)) {
val reason = String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient")
@ -134,7 +144,7 @@ internal class MXOlmDecryption(
}
val result = MXEventDecryptionResult()
// FIXME result.mClearEvent = payload
result.mClearEvent = payload
result.mSenderCurve25519Key = olmEventContent.senderKey
result.mClaimedEd25519Key = olmPayloadContent.keys!!.get("ed25519")
@ -148,7 +158,7 @@ internal class MXOlmDecryption(
* @param message message object, with 'type' and 'body' fields.
* @return payload, if decrypted successfully.
*/
private fun decryptMessage(message: Map<String, Any>, theirDeviceIdentityKey: String): String? {
private fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
val sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey)
val sessionIds: List<String>

View File

@ -1,102 +0,0 @@
/*
* 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.crypto.live
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.internal.crypto.CryptoManager
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 im.vector.matrix.android.internal.di.MatrixKoinComponent
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.members.RoomMembers
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.WorkerParamsFactory
import org.koin.standalone.inject
internal class EnableEncryptionWorker(context: Context,
workerParameters: WorkerParameters
) : Worker(context, workerParameters), MatrixKoinComponent {
private val monarchy by inject<Monarchy>()
private val cryptoManager by inject<CryptoManager>()
private val loadRoomMembersTask by inject<LoadRoomMembersTask>()
private val taskExecutor by inject<TaskExecutor>()
@JsonClass(generateAdapter = true)
internal class Params(
val eventIds: List<String>
)
override fun doWork(): Result {
val params = WorkerParamsFactory.fromData<Params>(inputData)
?: return Result.failure()
val events = monarchy.fetchAllMappedSync(
{ EventEntity.where(it, params.eventIds) },
{ it.asDomain() }
)
events.forEach {
val roomId = it.roomId!!
val callback = object : MatrixCallback<Boolean> {
override fun onSuccess(data: Boolean) {
super.onSuccess(data)
}
}
loadRoomMembersTask
.configureWith(LoadRoomMembersTask.Params(roomId))
.executeOn(TaskThread.ENCRYPTION)
.dispatchTo(callback)
.executeBy(taskExecutor)
var userIds: List<String> = emptyList()
monarchy.doWithRealm { realm ->
// Check whether the event content must be encrypted for the invited members.
val encryptForInvitedMembers = cryptoManager.isEncryptionEnabledForInvitedUser()
&& cryptoManager.shouldEncryptForInvitedMembers(roomId)
userIds = if (encryptForInvitedMembers) {
RoomMembers(realm, roomId).getActiveRoomMemberIds()
} else {
RoomMembers(realm, roomId).getJoinedRoomMemberIds()
}
}
cryptoManager.onRoomEncryptionEvent(it, userIds)
}
return Result.success()
}
}

View File

@ -1,59 +0,0 @@
/*
* 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.crypto.live
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
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 im.vector.matrix.android.internal.util.WorkerParamsFactory
import timber.log.Timber
private const val ENABLE_ENCRYPTION_EVENT_WORKER = "ENABLE_ENCRYPTION_EVENT_WORKER"
internal class RoomEncryptionEnabler(monarchy: Monarchy) : RealmLiveEntityObserver<EventEntity>(monarchy) {
override val query: Monarchy.Query<EventEntity>
get() = Monarchy.Query<EventEntity> { EventEntity.where(it, type = EventType.ENCRYPTION) }
override fun processChanges(inserted: List<EventEntity>, updated: List<EventEntity>, deleted: List<EventEntity>) {
Timber.v("RoomEncryption received")
val eventIds = inserted.mapNotNull { it.asDomain().eventId }
if (eventIds.isEmpty()) {
return
}
val workParam = EnableEncryptionWorker.Params(eventIds)
val workData = WorkerParamsFactory.toData(workParam)
val work = OneTimeWorkRequestBuilder<EnableEncryptionWorker>()
.setInputData(workData)
.build()
WorkManager.getInstance()
.beginUniqueWork(ENABLE_ENCRYPTION_EVENT_WORKER, ExistingWorkPolicy.APPEND, work)
.enqueue()
}
}

View File

@ -22,13 +22,14 @@ import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.crypto.MegolmSessionData
import org.matrix.olm.OlmInboundGroupSession
import timber.log.Timber
import java.io.Serializable
import java.util.*
/**
* This class adds more context to a OLMInboundGroupSession object.
* This allows additional checks. The class implements NSCoding so that the context can be stored.
* This allows additional checks. The class implements Serializable so that the context can be stored.
*/
class MXOlmInboundGroupSession2 {
class MXOlmInboundGroupSession2 : Serializable {
// The associated olm inbound group session.
var mSession: OlmInboundGroupSession? = null

View File

@ -65,7 +65,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
fun onToDeviceEvent(event: Event) {
CryptoAsyncHelper.getDecryptBackgroundHandler().post {
// TODO We are already in a BG thread
when (event.type) {
when (event.getClearType()) {
EventType.KEY_VERIFICATION_START -> {
onStartRequestReceived(event)
}
@ -144,7 +144,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
}
private fun onStartRequestReceived(event: Event) {
val startReq = event.content.toModel<KeyVerificationStart>()!!
val startReq = event.getClearContent().toModel<KeyVerificationStart>()!!
val otherUserId = event.sender
if (!startReq.isValid()) {
@ -233,7 +233,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
private fun onCancelReceived(event: Event) {
Timber.v("## SAS onCancelReceived")
val cancelReq = event.content.toModel<KeyVerificationCancel>()!!
val cancelReq = event.getClearContent().toModel<KeyVerificationCancel>()!!
if (!cancelReq.isValid()) {
//ignore
@ -255,7 +255,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
}
private fun onAcceptReceived(event: Event) {
val acceptReq = event.content.toModel<KeyVerificationAccept>()!!
val acceptReq = event.getClearContent().toModel<KeyVerificationAccept>()!!
if (!acceptReq.isValid()) {
//ignore
@ -279,7 +279,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
private fun onKeyReceived(event: Event) {
val keyReq = event.content.toModel<KeyVerificationKey>()!!
val keyReq = event.getClearContent().toModel<KeyVerificationKey>()!!
if (!keyReq.isValid()) {
//ignore
@ -300,7 +300,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
}
private fun onMacReceived(event: Event) {
val macReq = event.content.toModel<KeyVerificationMac>()!!
val macReq = event.getClearContent().toModel<KeyVerificationMac>()!!
if (!macReq.isValid()) {
//ignore

View File

@ -99,7 +99,7 @@ internal fun ChunkEntity.add(roomId: String,
backwardsDisplayIndex = currentDisplayIndex
}
var currentStateIndex = lastStateIndex(direction, defaultValue = stateIndexOffset)
if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.type)) {
if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.getClearType())) {
currentStateIndex += 1
forwardsStateIndex = currentStateIndex
} else if (direction == PaginationDirection.BACKWARDS && events.isNotEmpty()) {

View File

@ -17,13 +17,13 @@
package im.vector.matrix.android.internal.database.mapper
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.util.JSON_DICT_PARAMETERIZED_TYPE
import im.vector.matrix.android.internal.di.MoshiProvider
internal object ContentMapper {
private val moshi = MoshiProvider.providesMoshi()
private val adapter = moshi.adapter<Content>(Event.CONTENT_TYPE)
private val adapter = moshi.adapter<Content>(JSON_DICT_PARAMETERIZED_TYPE)
fun map(content: String?): Content? {
return content?.let {

View File

@ -32,7 +32,7 @@ internal object EventMapper {
val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent
eventEntity.prevContent = ContentMapper.map(resolvedPrevContent)
eventEntity.stateKey = event.stateKey
eventEntity.type = event.type
eventEntity.type = event.getClearType()
eventEntity.sender = event.sender
eventEntity.originServerTs = event.originServerTs
eventEntity.redacts = event.redacts

View File

@ -25,7 +25,6 @@ import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.internal.crypto.live.RoomEncryptionEnabler
import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.database.model.SessionRealmModule
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
@ -152,8 +151,7 @@ internal class SessionModule(private val sessionParams: SessionParams) {
val groupSummaryUpdater = GroupSummaryUpdater(get())
val eventsPruner = EventsPruner(get())
val userEntityUpdater = UserEntityUpdater(get(), get(), get())
val roomEncryptionEnabler = RoomEncryptionEnabler(get())
listOf<LiveEntityObserver>(groupSummaryUpdater, eventsPruner, userEntityUpdater, roomEncryptionEnabler)
listOf<LiveEntityObserver>(groupSummaryUpdater, eventsPruner, userEntityUpdater)
}

View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.session.room.invite.InviteTask
import im.vector.matrix.android.internal.session.room.members.DefaultRoomMembersService
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
@ -48,7 +49,7 @@ internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask,
fun instantiate(roomId: String): Room {
val roomMemberExtractor = SenderRoomMemberExtractor(roomId)
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor)
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, cryptoService)
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask)
val sendService = DefaultSendService(roomId, eventFactory, cryptoService, monarchy)
val stateService = DefaultStateService(roomId, sendStateTask, taskExecutor)

View File

@ -131,8 +131,8 @@ internal class DefaultSendService(private val roomId: String,
private fun createEncryptEventWork(event: Event): OneTimeWorkRequest {
// Same parameter
val sendContentWorkerParams = SendEventWorker.Params(roomId, event)
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
val params = EncryptEventWorker.Params(roomId, event)
val sendWorkData = WorkerParamsFactory.toData(params)
return OneTimeWorkRequestBuilder<EncryptEventWorker>()
.setConstraints(WORK_CONSTRAINTS)

View File

@ -59,7 +59,8 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
var result: MXEncryptEventContentResult? = null
var error: Throwable? = null
crypto.encryptEventContent(localEvent.content!!, localEvent.type, roomService.getRoom(params.roomId)!!, object : MatrixCallback<MXEncryptEventContentResult> {
try {
crypto.encryptEventContent(localEvent.content!!, localEvent.getClearType(), roomService.getRoom(params.roomId)!!, object : MatrixCallback<MXEncryptEventContentResult> {
override fun onSuccess(data: MXEncryptEventContentResult) {
result = data
latch.countDown()
@ -70,7 +71,10 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
latch.countDown()
}
})
} catch (e: Throwable) {
error = e
latch.countDown()
}
latch.await()
// TODO Update local echo

View File

@ -53,10 +53,10 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
apiCall = roomAPI.send(
localEvent.eventId,
params.roomId,
localEvent.type,
localEvent.getClearType(),
localEvent.content
)
}
return result.fold({ Result.retry() }, { Result.success() })
return result.fold({ Result.failure() }, { Result.success() })
}
}

View File

@ -16,13 +16,17 @@
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.events.model.EventType
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor
import io.realm.Realm
import timber.log.Timber
internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomMemberExtractor) {
internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomMemberExtractor,
private val cryptoService: CryptoService) {
private val cached = mutableMapOf<String, SenderData>()
@ -33,8 +37,17 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm)
SenderData(senderRoomMember?.displayName, senderRoomMember?.avatarUrl)
}
val event = eventEntity.asDomain()
if (event.getClearType() == EventType.ENCRYPTED) {
try {
val result = cryptoService.decryptEvent(event, "TODO")
event.setClearData(result)
} catch (e: Exception) {
Timber.e(e)
}
}
return TimelineEvent(
eventEntity.asDomain(),
event,
eventEntity.localId,
eventEntity.displayIndex,
senderData.senderName,

View File

@ -61,7 +61,7 @@ internal class CryptoSyncHandler(private val cryptoManager: CryptoManager,
* @return true if the event has been decrypted
*/
private fun decryptEvent(event: Event, timelineId: String?): Boolean {
if (event.type == EventType.ENCRYPTED) {
if (event.getClearType() == EventType.ENCRYPTED) {
var result: MXEventDecryptionResult? = null
try {
result = cryptoManager.decryptEvent(event, timelineId ?: "")

View File

@ -191,14 +191,14 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
roomId: String,
ephemeral: RoomSyncEphemeral) {
ephemeral.events
.filter { it.type == EventType.RECEIPT }
.filter { it.getClearType() == EventType.RECEIPT }
.map { it.content.toModel<ReadReceiptContent>() }
.forEach { readReceiptHandler.handle(realm, roomId, it) }
}
private fun handleRoomAccountDataEvents(realm: Realm, roomId: String, accountData: RoomSyncAccountData) {
accountData.events
.filter { it.type == EventType.TAG }
.filter { it.getClearType() == EventType.TAG }
.map { it.content.toModel<RoomTagContent>() }
.forEach { roomTagHandler.handle(realm, roomId, it) }
}

View File

@ -87,7 +87,7 @@ class EventStreamServiceX : VectorService() {
return
}
if (EventType.CALL_INVITE == event.type) {
if (EventType.CALL_INVITE == event.getClearType()) {
handleCallInviteEvent(event)
return
}

View File

@ -215,7 +215,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
items: List<TimelineEvent>,
addDaySeparator: Boolean,
currentPosition: Int): MergedHeaderItem? {
return if (!event.canBeMerged() || (nextEvent?.root?.type == event.root.type && !addDaySeparator)) {
return if (!event.canBeMerged() || (nextEvent?.root?.getClearType() == event.root.getClearType() && !addDaySeparator)) {
null
} else {
val prevSameTypeEvents = items.prevSameTypeEvents(currentPosition, 2)

View File

@ -120,7 +120,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
private fun canReply(event: TimelineEvent, messageContent: MessageContent): Boolean {
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
if (event.root.type != EventType.MESSAGE) return false
if (event.root.getClearType() != EventType.MESSAGE) return false
return when (messageContent.type) {
MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_NOTICE,
@ -135,7 +135,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
private fun canQuote(event: TimelineEvent, messageContent: MessageContent): Boolean {
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
if (event.root.type != EventType.MESSAGE) return false
if (event.root.getClearType() != EventType.MESSAGE) return false
return when (messageContent.type) {
MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_NOTICE,

View File

@ -39,7 +39,7 @@ class CallItemFactory(private val stringProvider: StringProvider) {
private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
return when {
EventType.CALL_INVITE == event.type -> {
EventType.CALL_INVITE == event.getClearType() -> {
val content = event.content.toModel<CallInviteContent>() ?: return null
val isVideoCall = content.offer.sdp == CallInviteContent.Offer.SDP_VIDEO
return if (isVideoCall) {
@ -48,8 +48,8 @@ class CallItemFactory(private val stringProvider: StringProvider) {
stringProvider.getString(R.string.notice_placed_voice_call, senderName)
}
}
EventType.CALL_ANSWER == event.type -> stringProvider.getString(R.string.notice_answered_call, senderName)
EventType.CALL_HANGUP == event.type -> stringProvider.getString(R.string.notice_ended_call, senderName)
EventType.CALL_ANSWER == event.getClearType() -> stringProvider.getString(R.string.notice_answered_call, senderName)
EventType.CALL_HANGUP == event.getClearType() -> stringProvider.getString(R.string.notice_ended_call, senderName)
else -> null
}

View File

@ -24,7 +24,7 @@ class DefaultItemFactory {
fun create(event: TimelineEvent, exception: Exception? = null): DefaultItem? {
val text = if (exception == null) {
"${event.root.type} events are not yet handled"
"${event.root.getClearType()} events are not yet handled"
} else {
"an exception occurred when rendering the event ${event.root.eventId}"
}

View File

@ -22,10 +22,12 @@ import android.text.SpannableString
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.events.model.Event
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.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.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.core.resources.StringProvider
@ -42,7 +44,7 @@ class EncryptedItemFactory(
callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {
return when {
EventType.ENCRYPTED == timelineEvent.root.type -> {
EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
val decrypted: MXEventDecryptionResult?
try {
decrypted = session.decryptEvent(timelineEvent.root, "TODO")
@ -68,12 +70,12 @@ class EncryptedItemFactory(
if (decrypted == null) {
return null
}
if (decrypted.mClearEvent == null) {
return null
}
val decryptedTimelineEvent = timelineEvent.copy(root = decrypted.mClearEvent!!)
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
val clearEvent = adapter.fromJsonValue(decrypted.mClearEvent) ?: return null
val decryptedTimelineEvent = timelineEvent.copy(root = clearEvent)
// Success
return messageItemFactory.create(decryptedTimelineEvent, nextEvent, callback)

View File

@ -38,7 +38,7 @@ class EncryptionItemFactory(private val stringProvider: StringProvider) {
private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
return when {
EventType.ENCRYPTION == event.type -> {
EventType.ENCRYPTION == event.getClearType() -> {
val content = event.content.toModel<EncryptionEventContent>() ?: return null
stringProvider.getString(R.string.notice_end_to_end, senderName, content.algorithm)
}

View File

@ -63,10 +63,10 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
val showInformation = addDaySeparator
|| event.senderAvatar != nextEvent?.senderAvatar
|| event.senderName != nextEvent?.senderName
|| nextEvent?.root?.type != EventType.MESSAGE
|| nextEvent?.root?.getClearType() != EventType.MESSAGE
|| isNextMessageReceivedMoreThanOneHourAgo
val messageContent: MessageContent = event.root.content.toModel() ?: return null
val messageContent: MessageContent = event.root.getClearContent().toModel() ?: return null
val time = timelineDateFormatter.formatMessageHour(date)
val avatarUrl = event.senderAvatar
val memberName = event.senderName ?: event.root.sender ?: ""

View File

@ -38,7 +38,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
callback: TimelineEventController.Callback?): VectorEpoxyModel<*> {
val computedModel = try {
when (event.root.type) {
when (event.root.getClearType()) {
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback)
EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event)
EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event)

View File

@ -40,7 +40,7 @@ object TimelineDisplayableEvents {
}
fun TimelineEvent.isDisplayable(): Boolean {
return TimelineDisplayableEvents.DISPLAYABLE_TYPES.contains(root.type) && !root.content.isNullOrEmpty()
return TimelineDisplayableEvents.DISPLAYABLE_TYPES.contains(root.getClearType()) && !root.content.isNullOrEmpty()
}
fun List<TimelineEvent>.filterDisplayableEvents(): List<TimelineEvent> {
@ -50,7 +50,7 @@ fun List<TimelineEvent>.filterDisplayableEvents(): List<TimelineEvent> {
}
fun TimelineEvent.canBeMerged(): Boolean {
return root.type == EventType.STATE_ROOM_MEMBER
return root.getClearType() == EventType.STATE_ROOM_MEMBER
}
fun List<TimelineEvent>.nextSameTypeEvents(index: Int, minSize: Int): List<TimelineEvent> {
@ -69,7 +69,7 @@ fun List<TimelineEvent>.nextSameTypeEvents(index: Int, minSize: Int): List<Timel
} else {
nextSubList.subList(0, indexOfNextDay)
}
val indexOfFirstDifferentEventType = nextSameDayEvents.indexOfFirst { it.root.type != timelineEvent.root.type }
val indexOfFirstDifferentEventType = nextSameDayEvents.indexOfFirst { it.root.getClearType() != timelineEvent.root.getClearType() }
val sameTypeEvents = if (indexOfFirstDifferentEventType == -1) {
nextSameDayEvents
} else {

View File

@ -47,7 +47,7 @@ class NotifiableEventResolver(val context: Context) {
return null
}
when (event.type) {
when (event.getClearType()) {
EventType.MESSAGE -> {
return resolveMessageEvent(event, bingRule, session, store)
}
@ -71,7 +71,7 @@ class NotifiableEventResolver(val context: Context) {
description = body,
soundName = bingRule?.notificationSound,
title = context.getString(R.string.notification_unknown_new_event),
type = event.type)
type = event.getClearType())
}
//Unsupported event
@ -172,7 +172,7 @@ class NotifiableEventResolver(val context: Context) {
title = context.getString(R.string.notification_new_invitation),
description = body,
soundName = bingRule?.notificationSound,
type = event.type,
type = event.getClearType(),
isPushGatewayEvent = false)
} else {
Timber.e("## unsupported notifiable event for eventId [${event.eventId}]")