mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Crypto: decryption is working (but still a lot to do)
This commit is contained in:
parent
3519ad7c8d
commit
af338b0607
40 changed files with 233 additions and 351 deletions
|
@ -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,11 +154,9 @@ data class Event(
|
|||
} catch (e: Exception) {
|
||||
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
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,6 @@ data class TimelineEvent(
|
|||
}
|
||||
|
||||
fun isEncrypted() : Boolean {
|
||||
return EventType.ENCRYPTED == root.type
|
||||
return EventType.ENCRYPTED == root.getClearType()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,11 +260,11 @@ internal class CryptoManager(
|
|||
uploadDeviceKeys(object : MatrixCallback<KeysUploadResponse> {
|
||||
private fun onError() {
|
||||
Handler().postDelayed({
|
||||
if (!isStarted()) {
|
||||
mIsStarting = false
|
||||
start(isInitialSync)
|
||||
}
|
||||
}, 1000)
|
||||
if (!isStarted()) {
|
||||
mIsStarting = false
|
||||
start(isInitialSync)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
override fun onSuccess(data: KeysUploadResponse) {
|
||||
|
@ -657,11 +652,11 @@ internal class CryptoManager(
|
|||
} else {
|
||||
val algorithm = room.encryptionAlgorithm()
|
||||
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")
|
||||
|
||||
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)
|
||||
Timber.e("## decryptEvent() : $reason")
|
||||
exceptions.add(MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_DECRYPT, reason)))
|
||||
MXCryptoError.UNABLE_TO_DECRYPT, reason)))
|
||||
} else {
|
||||
try {
|
||||
result = alg.decryptEvent(event, timeline)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -791,8 +807,8 @@ internal class CryptoManager(
|
|||
// make sure we are tracking the deviceList for this user.
|
||||
deviceListManager.startTrackingDeviceList(Arrays.asList(userId))
|
||||
} else if (membership == Membership.INVITE
|
||||
&& shouldEncryptForInvitedMembers(roomId)
|
||||
&& mCryptoConfig.mEnableEncryptionForInvitedMembers) {
|
||||
&& shouldEncryptForInvitedMembers(roomId)
|
||||
&& mCryptoConfig.mEnableEncryptionForInvitedMembers) {
|
||||
// track the deviceList for this invited user.
|
||||
// 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.
|
||||
|
@ -960,7 +976,7 @@ internal class CryptoManager(
|
|||
// trigger an an unknown devices exception
|
||||
callback.onFailure(
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
@ -62,7 +61,7 @@ internal class MXMegolmEncryption(
|
|||
private val mTaskExecutor: TaskExecutor,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mWarnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository
|
||||
) : IMXEncrypting {
|
||||
) : IMXEncrypting {
|
||||
|
||||
|
||||
// OutboundSessionInfo. Null if we haven't yet started setting one up. Note
|
||||
|
@ -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++
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -59,18 +59,22 @@ 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> {
|
||||
override fun onSuccess(data: MXEncryptEventContentResult) {
|
||||
result = data
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
error = failure
|
||||
latch.countDown()
|
||||
}
|
||||
})
|
||||
try {
|
||||
crypto.encryptEventContent(localEvent.content!!, localEvent.getClearType(), roomService.getRoom(params.roomId)!!, object : MatrixCallback<MXEncryptEventContentResult> {
|
||||
override fun onSuccess(data: MXEncryptEventContentResult) {
|
||||
result = data
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
error = failure
|
||||
latch.countDown()
|
||||
}
|
||||
})
|
||||
} catch (e: Throwable) {
|
||||
error = e
|
||||
latch.countDown()
|
||||
}
|
||||
latch.await()
|
||||
|
||||
// TODO Update local echo
|
||||
|
|
|
@ -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() })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>()
|
||||
|
||||
|
@ -30,11 +34,20 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
|
|||
val sender = eventEntity.sender
|
||||
val cacheKey = sender + eventEntity.stateIndex
|
||||
val senderData = cached.getOrPut(cacheKey) {
|
||||
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity,realm)
|
||||
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,
|
||||
|
@ -43,7 +56,7 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
|
|||
)
|
||||
}
|
||||
|
||||
fun clear(){
|
||||
fun clear() {
|
||||
cached.clear()
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ?: "")
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ class EventStreamServiceX : VectorService() {
|
|||
return
|
||||
}
|
||||
|
||||
if (EventType.CALL_INVITE == event.type) {
|
||||
if (EventType.CALL_INVITE == event.getClearType()) {
|
||||
handleCallInviteEvent(event)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
@ -129,13 +129,13 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||
MessageType.MSGTYPE_VIDEO,
|
||||
MessageType.MSGTYPE_AUDIO,
|
||||
MessageType.MSGTYPE_FILE -> true
|
||||
else -> false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -144,7 +144,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||
MessageType.MSGTYPE_LOCATION -> {
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||
MessageType.MSGTYPE_LOCATION -> {
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||
MessageType.MSGTYPE_VIDEO -> {
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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}"
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 ?: ""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}]")
|
||||
|
|
Loading…
Reference in a new issue