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 android.text.TextUtils
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass 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.session.crypto.MXCryptoError
import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import timber.log.Timber import timber.log.Timber
import java.lang.reflect.ParameterizedType
import java.util.* import java.util.*


typealias Content = JsonDict typealias Content = JsonDict
@ -77,11 +75,7 @@ data class Event(
* @return true if event is state event. * @return true if event is state event.
*/ */
fun isStateEvent(): Boolean { fun isStateEvent(): Boolean {
return EventType.isStateEvent(type) return EventType.isStateEvent(getClearType())
}

companion object {
internal val CONTENT_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)
} }


//============================================================================================================== //==============================================================================================================
@ -138,24 +132,18 @@ data class Event(
* *
* @param decryptionResult the decryption result, including the plaintext and some key info. * @param decryptionResult the decryption result, including the plaintext and some key info.
*/ */
fun setClearData(decryptionResult: MXEventDecryptionResult?) { internal fun setClearData(decryptionResult: MXEventDecryptionResult?) {
mClearEvent = null 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
} }

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

if (null != decryptionResult.mForwardingCurve25519KeyChain) {
mClearEvent!!.mForwardingCurve25519KeyChain = decryptionResult.mForwardingCurve25519KeyChain
} else {
mClearEvent!!.mForwardingCurve25519KeyChain = ArrayList()
}

try { try {
// Add "m.relates_to" data from e2e event to the unencrypted event // Add "m.relates_to" data from e2e event to the unencrypted event
// TODO // TODO
@ -166,11 +154,9 @@ data class Event(
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Unable to restore 'm.relates_to' the clear event") Timber.e(e, "Unable to restore 'm.relates_to' the clear event")
} }

} }

mCryptoError = null
} }
mCryptoError = null
} }


/** /**
@ -203,11 +189,14 @@ data class Event(
* @return the event type * @return the event type
*/ */
fun getClearType(): String { fun getClearType(): String {
return if (null != mClearEvent) { return mClearEvent?.type ?: type
mClearEvent!!.type }
} else {
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()) { if (initialStates != null && !initialStates!!.isEmpty()) {
val newInitialStates = ArrayList<Event>() val newInitialStates = ArrayList<Event>()
for (event in initialStates!!) { for (event in initialStates!!) {
if (event.type != EventType.STATE_HISTORY_VISIBILITY) { if (event.getClearType() != EventType.STATE_HISTORY_VISIBILITY) {
newInitialStates.add(event) newInitialStates.add(event)
} }
} }

View File

@ -62,6 +62,6 @@ data class TimelineEvent(
} }


fun isEncrypted() : Boolean { 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 package im.vector.matrix.android.api.util


import com.squareup.moshi.Types
import java.lang.reflect.ParameterizedType

typealias JsonDict = Map<String, @JvmSuppressWildcards Any> 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.content.Context
import android.os.Handler import android.os.Handler
import android.text.TextUtils import android.text.TextUtils
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.failure.Failure 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.megolm.MXMegolmEncryptionFactory
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory 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.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.*
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.event.RoomKeyContent 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.DevicesListResponse
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse 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.model.rest.RoomKeyRequestBody
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository 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.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask import im.vector.matrix.android.internal.crypto.tasks.*
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.verification.DefaultSasVerificationService import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
import im.vector.matrix.android.internal.di.MoshiProvider 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.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith 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 org.matrix.olm.OlmManager
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -128,6 +124,9 @@ internal class CryptoManager(
private val mSendToDeviceTask: SendToDeviceTask, private val mSendToDeviceTask: SendToDeviceTask,
private val mSetDeviceNameTask: SetDeviceNameTask, private val mSetDeviceNameTask: SetDeviceNameTask,
private val mUploadKeysTask: UploadKeysTask, private val mUploadKeysTask: UploadKeysTask,
private val loadRoomMembersTask: LoadRoomMembersTask,
private val monarchy: Monarchy,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
// TaskExecutor // TaskExecutor
private val mTaskExecutor: TaskExecutor private val mTaskExecutor: TaskExecutor
) : CryptoService { ) : CryptoService {
@ -152,22 +151,18 @@ internal class CryptoManager(
//} //}


fun onStateEvent(roomId: String, event: Event) { fun onStateEvent(roomId: String, event: Event) {
if (event.type == EventType.ENCRYPTION) { when {
// TODO Remove onRoomEncryptionEvent(roomId, event) event.getClearType() == EventType.ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
} else if (event.type == EventType.STATE_ROOM_MEMBER) { event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
onRoomMembershipEvent(roomId, event) event.getClearType() == EventType.STATE_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
} else if (event.type == EventType.STATE_HISTORY_VISIBILITY) {
onRoomHistoryVisibilityEvent(roomId, event)
} }
} }


fun onLiveEvent(roomId: String, event: Event) { fun onLiveEvent(roomId: String, event: Event) {
if (event.type == EventType.ENCRYPTION) { when {
// TODO Remove onRoomEncryptionEvent(roomId, event) event.getClearType() == EventType.ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
} else if (event.type == EventType.STATE_ROOM_MEMBER) { event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
onRoomMembershipEvent(roomId, event) event.getClearType() == EventType.STATE_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
} else if (event.type == EventType.STATE_HISTORY_VISIBILITY) {
onRoomHistoryVisibilityEvent(roomId, event)
} }
} }


@ -265,11 +260,11 @@ internal class CryptoManager(
uploadDeviceKeys(object : MatrixCallback<KeysUploadResponse> { uploadDeviceKeys(object : MatrixCallback<KeysUploadResponse> {
private fun onError() { private fun onError() {
Handler().postDelayed({ Handler().postDelayed({
if (!isStarted()) { if (!isStarted()) {
mIsStarting = false mIsStarting = false
start(isInitialSync) start(isInitialSync)
} }
}, 1000) }, 1000)
} }


override fun onSuccess(data: KeysUploadResponse) { override fun onSuccess(data: KeysUploadResponse) {
@ -657,11 +652,11 @@ internal class CryptoManager(
} else { } else {
val algorithm = room.encryptionAlgorithm() val algorithm = room.encryptionAlgorithm()
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON) algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
Timber.e("## encryptEventContent() : $reason") Timber.e("## encryptEventContent() : $reason")


callback.onFailure(Failure.CryptoError(MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE, callback.onFailure(Failure.CryptoError(MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE,
MXCryptoError.UNABLE_TO_ENCRYPT, reason))) MXCryptoError.UNABLE_TO_ENCRYPT, reason)))
} }
} }


@ -691,7 +686,7 @@ internal class CryptoManager(
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, eventContent["algorithm"] as String)
Timber.e("## decryptEvent() : $reason") Timber.e("## decryptEvent() : $reason")
exceptions.add(MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, exceptions.add(MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, reason))) MXCryptoError.UNABLE_TO_DECRYPT, reason)))
} else { } else {
try { try {
result = alg.decryptEvent(event, timeline) result = alg.decryptEvent(event, timeline)
@ -728,9 +723,9 @@ internal class CryptoManager(
* @param event the event * @param event the event
*/ */
fun onToDeviceEvent(event: 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) onRoomKeyEvent(event)
} else if (event.type == EventType.ROOM_KEY_REQUEST) { } else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
mIncomingRoomKeyRequestManager.onRoomKeyRequestEvent(event) mIncomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
} }
} }
@ -742,7 +737,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.content.toModel<RoomKeyContent>()!! val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!!


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")
@ -764,8 +759,29 @@ internal class CryptoManager(
* *
* @param event the encryption event. * @param event the encryption event.
*/ */
fun onRoomEncryptionEvent(event: Event, userIds: List<String>) { private fun onRoomEncryptionEvent(roomId: String, event: Event) {
setEncryptionInRoom(event.roomId!!, event.content!!["algorithm"] as String, true, userIds) 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
}
}
} }


/** /**
@ -791,8 +807,8 @@ internal class CryptoManager(
// make sure we are tracking the deviceList for this user. // make sure we are tracking the deviceList for this user.
deviceListManager.startTrackingDeviceList(Arrays.asList(userId)) deviceListManager.startTrackingDeviceList(Arrays.asList(userId))
} else if (membership == Membership.INVITE } else if (membership == Membership.INVITE
&& shouldEncryptForInvitedMembers(roomId) && shouldEncryptForInvitedMembers(roomId)
&& mCryptoConfig.mEnableEncryptionForInvitedMembers) { && mCryptoConfig.mEnableEncryptionForInvitedMembers) {
// track the deviceList for this invited user. // track the deviceList for this invited user.
// Caution: there's a big edge case here in that federated servers do not // Caution: there's a big edge case here in that federated servers do not
// know what other servers are in the room at the time they've been invited. // know what other servers are in the room at the time they've been invited.
@ -960,7 +976,7 @@ internal class CryptoManager(
// trigger an an unknown devices exception // trigger an an unknown devices exception
callback.onFailure( callback.onFailure(
Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE, Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices))) MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
} }
} }



View File

@ -99,7 +99,6 @@ internal class CryptoModule {
scope(DefaultSession.SCOPE) { scope(DefaultSession.SCOPE) {
// Ensure OlmManager is loaded first // Ensure OlmManager is loaded first
get<OlmManager>() get<OlmManager>()

MXOlmDevice(get()) MXOlmDevice(get())
} }


@ -172,31 +171,38 @@ internal class CryptoModule {
// CryptoManager // CryptoManager
scope(DefaultSession.SCOPE) { scope(DefaultSession.SCOPE) {
CryptoManager( CryptoManager(
get(), mCredentials = get(),
get(), mMyDeviceInfoHolder = get(),
get(), mCryptoStore = get(),
get(), mOlmDevice = get(),
get(), mCryptoConfig = get(),
get(), deviceListManager = get(),
get(), mKeysBackup = get(),
get(), mObjectSigner = get(),
get(), mOneTimeKeysUploader = get(),
get(), roomDecryptorProvider = get(),
get(), mSasVerificationService = get(),
get(), mIncomingRoomKeyRequestManager = get(),
get(), mOutgoingRoomKeyRequestManager = get(),
get(), mOlmManager = get(),
get(), mSetDeviceVerificationAction = get(),
// Actions mMegolmSessionDataImporter = get(),
get(), mEnsureOlmSessionsForDevicesAction = get(),
get(), mWarnOnUnknownDevicesRepository = get(),
get(), mMXMegolmEncryptionFactory = get(),
// Factory mMXOlmEncryptionFactory = get(),
get(), get(), mClaimOneTimeKeysForUsersDeviceTask = get(),
// Tasks // Tasks
get(), get(), get(), get(), get(), get(), get(), mDeleteDeviceTask = get(),
// Task executor mGetDevicesTask = get(),
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) { constructor(event: Event) {
mUserId = event.sender mUserId = event.sender

val roomKeyShareRequest = event.getClearContent().toModel<RoomKeyShareRequest>()!!
val roomKeyShareRequest = event.content.toModel<RoomKeyShareRequest>()!!
mDeviceId = roomKeyShareRequest.requestingDeviceId mDeviceId = roomKeyShareRequest.requestingDeviceId
mRequestId = roomKeyShareRequest.requestId mRequestId = roomKeyShareRequest.requestId
mRequestBody = if (null != roomKeyShareRequest.body) roomKeyShareRequest.body else RoomKeyRequestBody() mRequestBody = if (null != roomKeyShareRequest.body) roomKeyShareRequest.body else RoomKeyRequestBody()

View File

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


when (roomKeyShare?.action) { when (roomKeyShare?.action) {
RoomKeyShare.ACTION_SHARE_REQUEST -> synchronized(mReceivedRoomKeyRequests) { RoomKeyShare.ACTION_SHARE_REQUEST -> synchronized(mReceivedRoomKeyRequests) {

View File

@ -17,7 +17,7 @@


package im.vector.matrix.android.internal.crypto 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.* import java.util.*


/** /**
@ -28,7 +28,7 @@ data class MXEventDecryptionResult(
/** /**
* The plaintext payload for the event (typically containing "type" and "content" fields). * 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. * 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 android.text.TextUtils
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.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.algorithms.MXDecryptionResult
import im.vector.matrix.android.internal.crypto.model.MXOlmInboundGroupSession2 import im.vector.matrix.android.internal.crypto.model.MXOlmInboundGroupSession2
import im.vector.matrix.android.internal.crypto.model.MXOlmSession import im.vector.matrix.android.internal.crypto.model.MXOlmSession
@ -677,9 +678,10 @@ internal class MXOlmDevice(


mStore.storeInboundGroupSessions(listOf(session)) mStore.storeInboundGroupSessions(listOf(session))
try { try {
val moshi = MoshiProvider.providesMoshi() val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
val adapter = moshi.adapter(Map::class.java) val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
result.mPayload = adapter.fromJson(convertFromUTF8(decryptResult.mDecryptedMessage)) as Event? val payload = adapter.fromJson(payloadString)
result.mPayload = payload
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "## decryptGroupMessage() : RLEncoder.encode failed " + e.message) Timber.e(e, "## decryptGroupMessage() : RLEncoder.encode failed " + e.message)
return null return null

View File

@ -16,7 +16,7 @@


package im.vector.matrix.android.internal.crypto.algorithms 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. * This class represents the decryption result.
@ -25,7 +25,7 @@ data class MXDecryptionResult(
/** /**
* The decrypted payload (with properties 'type', 'content') * 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: * 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) { override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {
var exportFormat = false var exportFormat = false
val roomKeyContent = event.content.toModel<RoomKeyContent>()!! val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!!


var senderKey: String? = event.getSenderKey() var senderKey: String? = event.getSenderKey()
var keysClaimed: MutableMap<String, String> = HashMap() var keysClaimed: MutableMap<String, String> = HashMap()
@ -206,10 +206,10 @@ internal class MXMegolmDecryption(private val mCredentials: Credentials,
return 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 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.content.toModel<ForwardedRoomKeyContent>()!! val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()!!


if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) { if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) {
forwarding_curve25519_key_chain = ArrayList() forwarding_curve25519_key_chain = ArrayList()
@ -297,7 +297,6 @@ internal class MXMegolmDecryption(private val mCredentials: Credentials,
val fResut = result val fResut = result
CryptoAsyncHelper.getUiHandler().post { CryptoAsyncHelper.getUiHandler().post {
event.setClearData(fResut) event.setClearData(fResut)
TODO()
//mSession!!.onEventDecrypted(event) //mSession!!.onEventDecrypted(event)
} }
Timber.v("## onNewSession() : successful re-decryption of " + event.eventId) 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.crypto.MXCryptoError
import im.vector.matrix.android.api.session.events.model.Content 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.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.CryptoAsyncHelper
import im.vector.matrix.android.internal.crypto.DeviceListManager import im.vector.matrix.android.internal.crypto.DeviceListManager
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
@ -62,7 +61,7 @@ internal class MXMegolmEncryption(
private val mTaskExecutor: TaskExecutor, private val mTaskExecutor: TaskExecutor,
private val mMessageEncrypter: MessageEncrypter, private val mMessageEncrypter: MessageEncrypter,
private val mWarnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository private val mWarnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository
) : IMXEncrypting { ) : IMXEncrypting {




// OutboundSessionInfo. Null if we haven't yet started setting one up. Note // OutboundSessionInfo. Null if we haven't yet started setting one up. Note
@ -422,9 +421,8 @@ internal class MXMegolmEncryption(
payloadJson["content"] = queuedEncryption.mEventContent!! payloadJson["content"] = queuedEncryption.mEventContent!!


// Get canonical Json from // 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 ciphertext = olmDevice.encryptGroupMessage(session.mSessionId, payloadString!!)


val map = HashMap<String, Any>() val map = HashMap<String, Any>()
@ -437,7 +435,7 @@ internal class MXMegolmEncryption(
// m.new_device message if they don't have our session key. // m.new_device message if they don't have our session key.
map["device_id"] = mCredentials.deviceId!! map["device_id"] = mCredentials.deviceId!!


CryptoAsyncHelper.getUiHandler().post { queuedEncryption.mApiCallback?.onSuccess(map.toContent()!!) } CryptoAsyncHelper.getUiHandler().post { queuedEncryption.mApiCallback?.onSuccess(map) }


session.mUseCount++ session.mUseCount++
} }

View File

@ -18,16 +18,20 @@
package im.vector.matrix.android.internal.crypto.algorithms.olm package im.vector.matrix.android.internal.crypto.algorithms.olm


import android.text.TextUtils import android.text.TextUtils
import com.squareup.moshi.Json
import im.vector.matrix.android.api.auth.data.Credentials 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.crypto.MXCryptoError
import im.vector.matrix.android.api.session.events.model.Event 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.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.MXDecryptionException
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting 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.OlmEventContent
import im.vector.matrix.android.internal.crypto.model.event.OlmPayloadContent 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 im.vector.matrix.android.internal.util.convertFromUTF8
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -58,24 +62,30 @@ internal class MXOlmDecryption(
} }


// The message for myUser // The message for myUser
val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as Map<String, Any> val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as JsonDict
val payloadString = decryptMessage(message, olmEventContent.senderKey!!) 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) Timber.e("## decryptEvent() Failed to decrypt Olm event (id= " + event.eventId + " ) from " + olmEventContent.senderKey)
throw MXDecryptionException(MXCryptoError(MXCryptoError.BAD_ENCRYPTED_MESSAGE_ERROR_CODE, throw MXDecryptionException(MXCryptoError(MXCryptoError.BAD_ENCRYPTED_MESSAGE_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)) 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 (payload == null) {

if (null == payload) {
Timber.e("## decryptEvent failed : null payload") Timber.e("## decryptEvent failed : null payload")
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE,
MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON)) MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON))
} }


val olmPayloadContent = OlmPayloadContent.fromJsonString(payload) val olmPayloadContent = OlmPayloadContent.fromJsonString(payloadString)


if (TextUtils.isEmpty(olmPayloadContent.recipient)) { if (TextUtils.isEmpty(olmPayloadContent.recipient)) {
val reason = String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient") val reason = String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient")
@ -134,7 +144,7 @@ internal class MXOlmDecryption(
} }


val result = MXEventDecryptionResult() val result = MXEventDecryptionResult()
// FIXME result.mClearEvent = payload result.mClearEvent = payload
result.mSenderCurve25519Key = olmEventContent.senderKey result.mSenderCurve25519Key = olmEventContent.senderKey
result.mClaimedEd25519Key = olmPayloadContent.keys!!.get("ed25519") result.mClaimedEd25519Key = olmPayloadContent.keys!!.get("ed25519")


@ -148,7 +158,7 @@ internal class MXOlmDecryption(
* @param message message object, with 'type' and 'body' fields. * @param message message object, with 'type' and 'body' fields.
* @return payload, if decrypted successfully. * @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 sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey)


val sessionIds: List<String> 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 im.vector.matrix.android.internal.crypto.MegolmSessionData
import org.matrix.olm.OlmInboundGroupSession import org.matrix.olm.OlmInboundGroupSession
import timber.log.Timber import timber.log.Timber
import java.io.Serializable
import java.util.* import java.util.*


/** /**
* This class adds more context to a OLMInboundGroupSession object. * 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. // The associated olm inbound group session.
var mSession: OlmInboundGroupSession? = null var mSession: OlmInboundGroupSession? = null

View File

@ -65,7 +65,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
fun onToDeviceEvent(event: Event) { fun onToDeviceEvent(event: Event) {
CryptoAsyncHelper.getDecryptBackgroundHandler().post { CryptoAsyncHelper.getDecryptBackgroundHandler().post {
// TODO We are already in a BG thread // TODO We are already in a BG thread
when (event.type) { when (event.getClearType()) {
EventType.KEY_VERIFICATION_START -> { EventType.KEY_VERIFICATION_START -> {
onStartRequestReceived(event) onStartRequestReceived(event)
} }
@ -144,7 +144,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
} }


private fun onStartRequestReceived(event: Event) { private fun onStartRequestReceived(event: Event) {
val startReq = event.content.toModel<KeyVerificationStart>()!! val startReq = event.getClearContent().toModel<KeyVerificationStart>()!!


val otherUserId = event.sender val otherUserId = event.sender
if (!startReq.isValid()) { if (!startReq.isValid()) {
@ -233,7 +233,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia


private fun onCancelReceived(event: Event) { private fun onCancelReceived(event: Event) {
Timber.v("## SAS onCancelReceived") Timber.v("## SAS onCancelReceived")
val cancelReq = event.content.toModel<KeyVerificationCancel>()!! val cancelReq = event.getClearContent().toModel<KeyVerificationCancel>()!!


if (!cancelReq.isValid()) { if (!cancelReq.isValid()) {
//ignore //ignore
@ -255,7 +255,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
} }


private fun onAcceptReceived(event: Event) { private fun onAcceptReceived(event: Event) {
val acceptReq = event.content.toModel<KeyVerificationAccept>()!! val acceptReq = event.getClearContent().toModel<KeyVerificationAccept>()!!


if (!acceptReq.isValid()) { if (!acceptReq.isValid()) {
//ignore //ignore
@ -279,7 +279,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia




private fun onKeyReceived(event: Event) { private fun onKeyReceived(event: Event) {
val keyReq = event.content.toModel<KeyVerificationKey>()!! val keyReq = event.getClearContent().toModel<KeyVerificationKey>()!!


if (!keyReq.isValid()) { if (!keyReq.isValid()) {
//ignore //ignore
@ -300,7 +300,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
} }


private fun onMacReceived(event: Event) { private fun onMacReceived(event: Event) {
val macReq = event.content.toModel<KeyVerificationMac>()!! val macReq = event.getClearContent().toModel<KeyVerificationMac>()!!


if (!macReq.isValid()) { if (!macReq.isValid()) {
//ignore //ignore

View File

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

View File

@ -17,13 +17,13 @@
package im.vector.matrix.android.internal.database.mapper 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.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 import im.vector.matrix.android.internal.di.MoshiProvider


internal object ContentMapper { internal object ContentMapper {


private val moshi = MoshiProvider.providesMoshi() 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? { fun map(content: String?): Content? {
return content?.let { return content?.let {

View File

@ -32,7 +32,7 @@ internal object EventMapper {
val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent
eventEntity.prevContent = ContentMapper.map(resolvedPrevContent) eventEntity.prevContent = ContentMapper.map(resolvedPrevContent)
eventEntity.stateKey = event.stateKey eventEntity.stateKey = event.stateKey
eventEntity.type = event.type eventEntity.type = event.getClearType()
eventEntity.sender = event.sender eventEntity.sender = event.sender
eventEntity.originServerTs = event.originServerTs eventEntity.originServerTs = event.originServerTs
eventEntity.redacts = event.redacts 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.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.user.UserService 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.LiveEntityObserver
import im.vector.matrix.android.internal.database.model.SessionRealmModule import im.vector.matrix.android.internal.database.model.SessionRealmModule
import im.vector.matrix.android.internal.session.cache.ClearCacheTask 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 groupSummaryUpdater = GroupSummaryUpdater(get())
val eventsPruner = EventsPruner(get()) val eventsPruner = EventsPruner(get())
val userEntityUpdater = UserEntityUpdater(get(), get(), get()) val userEntityUpdater = UserEntityUpdater(get(), get(), get())
val roomEncryptionEnabler = RoomEncryptionEnabler(get()) listOf<LiveEntityObserver>(groupSummaryUpdater, eventsPruner, userEntityUpdater)
listOf<LiveEntityObserver>(groupSummaryUpdater, eventsPruner, userEntityUpdater, roomEncryptionEnabler)
} }





View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
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.room.Room 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.invite.InviteTask
import im.vector.matrix.android.internal.session.room.members.DefaultRoomMembersService import im.vector.matrix.android.internal.session.room.members.DefaultRoomMembersService
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask 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 { fun instantiate(roomId: String): Room {
val roomMemberExtractor = SenderRoomMemberExtractor(roomId) val roomMemberExtractor = SenderRoomMemberExtractor(roomId)
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor) val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, cryptoService)
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask) val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask)
val sendService = DefaultSendService(roomId, eventFactory, cryptoService, monarchy) val sendService = DefaultSendService(roomId, eventFactory, cryptoService, monarchy)
val stateService = DefaultStateService(roomId, sendStateTask, taskExecutor) 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 { private fun createEncryptEventWork(event: Event): OneTimeWorkRequest {
// Same parameter // Same parameter
val sendContentWorkerParams = SendEventWorker.Params(roomId, event) val params = EncryptEventWorker.Params(roomId, event)
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) val sendWorkData = WorkerParamsFactory.toData(params)


return OneTimeWorkRequestBuilder<EncryptEventWorker>() return OneTimeWorkRequestBuilder<EncryptEventWorker>()
.setConstraints(WORK_CONSTRAINTS) .setConstraints(WORK_CONSTRAINTS)

View File

@ -59,18 +59,22 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
var result: MXEncryptEventContentResult? = null var result: MXEncryptEventContentResult? = null
var error: Throwable? = null var error: Throwable? = null


crypto.encryptEventContent(localEvent.content!!, localEvent.type, roomService.getRoom(params.roomId)!!, object : MatrixCallback<MXEncryptEventContentResult> { try {
override fun onSuccess(data: MXEncryptEventContentResult) { crypto.encryptEventContent(localEvent.content!!, localEvent.getClearType(), roomService.getRoom(params.roomId)!!, object : MatrixCallback<MXEncryptEventContentResult> {
result = data override fun onSuccess(data: MXEncryptEventContentResult) {
latch.countDown() result = data
} latch.countDown()

}
override fun onFailure(failure: Throwable) {
error = failure
latch.countDown()
}
})


override fun onFailure(failure: Throwable) {
error = failure
latch.countDown()
}
})
} catch (e: Throwable) {
error = e
latch.countDown()
}
latch.await() latch.await()


// TODO Update local echo // TODO Update local echo

View File

@ -53,10 +53,10 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
apiCall = roomAPI.send( apiCall = roomAPI.send(
localEvent.eventId, localEvent.eventId,
params.roomId, params.roomId,
localEvent.type, localEvent.getClearType(),
localEvent.content 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 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.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.database.mapper.asDomain 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.model.EventEntity
import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor
import io.realm.Realm 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>() private val cached = mutableMapOf<String, SenderData>()


@ -30,11 +34,20 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
val sender = eventEntity.sender val sender = eventEntity.sender
val cacheKey = sender + eventEntity.stateIndex val cacheKey = sender + eventEntity.stateIndex
val senderData = cached.getOrPut(cacheKey) { val senderData = cached.getOrPut(cacheKey) {
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity,realm) val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm)
SenderData(senderRoomMember?.displayName, senderRoomMember?.avatarUrl) 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( return TimelineEvent(
eventEntity.asDomain(), event,
eventEntity.localId, eventEntity.localId,
eventEntity.displayIndex, eventEntity.displayIndex,
senderData.senderName, senderData.senderName,
@ -43,7 +56,7 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
) )
} }


fun clear(){ fun clear() {
cached.clear() cached.clear()
} }



View File

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

View File

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


private fun handleRoomAccountDataEvents(realm: Realm, roomId: String, accountData: RoomSyncAccountData) { private fun handleRoomAccountDataEvents(realm: Realm, roomId: String, accountData: RoomSyncAccountData) {
accountData.events accountData.events
.filter { it.type == EventType.TAG } .filter { it.getClearType() == EventType.TAG }
.map { it.content.toModel<RoomTagContent>() } .map { it.content.toModel<RoomTagContent>() }
.forEach { roomTagHandler.handle(realm, roomId, it) } .forEach { roomTagHandler.handle(realm, roomId, it) }
} }

View File

@ -87,7 +87,7 @@ class EventStreamServiceX : VectorService() {
return return
} }


if (EventType.CALL_INVITE == event.type) { if (EventType.CALL_INVITE == event.getClearType()) {
handleCallInviteEvent(event) handleCallInviteEvent(event)
return return
} }

View File

@ -215,7 +215,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
items: List<TimelineEvent>, items: List<TimelineEvent>,
addDaySeparator: Boolean, addDaySeparator: Boolean,
currentPosition: Int): MergedHeaderItem? { 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 null
} else { } else {
val prevSameTypeEvents = items.prevSameTypeEvents(currentPosition, 2) 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 { private fun canReply(event: TimelineEvent, messageContent: MessageContent): Boolean {
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment //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) { return when (messageContent.type) {
MessageType.MSGTYPE_TEXT, MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_NOTICE, MessageType.MSGTYPE_NOTICE,
@ -129,13 +129,13 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_AUDIO, MessageType.MSGTYPE_AUDIO,
MessageType.MSGTYPE_FILE -> true MessageType.MSGTYPE_FILE -> true
else -> false else -> false
} }
} }


private fun canQuote(event: TimelineEvent, messageContent: MessageContent): Boolean { private fun canQuote(event: TimelineEvent, messageContent: MessageContent): Boolean {
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment //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) { return when (messageContent.type) {
MessageType.MSGTYPE_TEXT, MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_NOTICE, MessageType.MSGTYPE_NOTICE,
@ -144,7 +144,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
MessageType.MSGTYPE_LOCATION -> { MessageType.MSGTYPE_LOCATION -> {
true true
} }
else -> false else -> false
} }
} }


@ -157,7 +157,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
MessageType.MSGTYPE_LOCATION -> { MessageType.MSGTYPE_LOCATION -> {
true true
} }
else -> false else -> false
} }
} }


@ -169,7 +169,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
MessageType.MSGTYPE_VIDEO -> { MessageType.MSGTYPE_VIDEO -> {
true true
} }
else -> false else -> false
} }
} }



View File

@ -39,7 +39,7 @@ class CallItemFactory(private val stringProvider: StringProvider) {


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



View File

@ -24,7 +24,7 @@ class DefaultItemFactory {


fun create(event: TimelineEvent, exception: Exception? = null): DefaultItem? { fun create(event: TimelineEvent, exception: Exception? = null): DefaultItem? {
val text = if (exception == null) { val text = if (exception == null) {
"${event.root.type} events are not yet handled" "${event.root.getClearType()} events are not yet handled"
} else { } else {
"an exception occurred when rendering the event ${event.root.eventId}" "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 android.text.style.StyleSpan
import im.vector.matrix.android.api.session.Session 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.MXDecryptionException
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult 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
@ -42,7 +44,7 @@ class EncryptedItemFactory(
callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? { callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {


return when { return when {
EventType.ENCRYPTED == timelineEvent.root.type -> { EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
val decrypted: MXEventDecryptionResult? val decrypted: MXEventDecryptionResult?
try { try {
decrypted = session.decryptEvent(timelineEvent.root, "TODO") decrypted = session.decryptEvent(timelineEvent.root, "TODO")
@ -68,12 +70,12 @@ class EncryptedItemFactory(
if (decrypted == null) { if (decrypted == null) {
return null return null
} }

if (decrypted.mClearEvent == null) { if (decrypted.mClearEvent == null) {
return null return null
} }

val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
val decryptedTimelineEvent = timelineEvent.copy(root = decrypted.mClearEvent!!) val clearEvent = adapter.fromJsonValue(decrypted.mClearEvent) ?: return null
val decryptedTimelineEvent = timelineEvent.copy(root = clearEvent)


// Success // Success
return messageItemFactory.create(decryptedTimelineEvent, nextEvent, callback) 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? { private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
return when { return when {
EventType.ENCRYPTION == event.type -> { EventType.ENCRYPTION == event.getClearType() -> {
val content = event.content.toModel<EncryptionEventContent>() ?: return null val content = event.content.toModel<EncryptionEventContent>() ?: return null
stringProvider.getString(R.string.notice_end_to_end, senderName, content.algorithm) 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 val showInformation = addDaySeparator
|| event.senderAvatar != nextEvent?.senderAvatar || event.senderAvatar != nextEvent?.senderAvatar
|| event.senderName != nextEvent?.senderName || event.senderName != nextEvent?.senderName
|| nextEvent?.root?.type != EventType.MESSAGE || nextEvent?.root?.getClearType() != EventType.MESSAGE
|| isNextMessageReceivedMoreThanOneHourAgo || 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 time = timelineDateFormatter.formatMessageHour(date)
val avatarUrl = event.senderAvatar val avatarUrl = event.senderAvatar
val memberName = event.senderName ?: event.root.sender ?: "" val memberName = event.senderName ?: event.root.sender ?: ""

View File

@ -38,7 +38,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
callback: TimelineEventController.Callback?): VectorEpoxyModel<*> { callback: TimelineEventController.Callback?): VectorEpoxyModel<*> {


val computedModel = try { val computedModel = try {
when (event.root.type) { when (event.root.getClearType()) {
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback) EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback)
EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event) EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event)
EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event) EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event)

View File

@ -40,7 +40,7 @@ object TimelineDisplayableEvents {
} }


fun TimelineEvent.isDisplayable(): Boolean { 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> { fun List<TimelineEvent>.filterDisplayableEvents(): List<TimelineEvent> {
@ -50,7 +50,7 @@ fun List<TimelineEvent>.filterDisplayableEvents(): List<TimelineEvent> {
} }


fun TimelineEvent.canBeMerged(): Boolean { 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> { 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 { } else {
nextSubList.subList(0, indexOfNextDay) 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) { val sameTypeEvents = if (indexOfFirstDifferentEventType == -1) {
nextSameDayEvents nextSameDayEvents
} else { } else {

View File

@ -47,7 +47,7 @@ class NotifiableEventResolver(val context: Context) {
return null return null
} }


when (event.type) { when (event.getClearType()) {
EventType.MESSAGE -> { EventType.MESSAGE -> {
return resolveMessageEvent(event, bingRule, session, store) return resolveMessageEvent(event, bingRule, session, store)
} }
@ -71,7 +71,7 @@ class NotifiableEventResolver(val context: Context) {
description = body, description = body,
soundName = bingRule?.notificationSound, soundName = bingRule?.notificationSound,
title = context.getString(R.string.notification_unknown_new_event), title = context.getString(R.string.notification_unknown_new_event),
type = event.type) type = event.getClearType())
} }


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