forked from GitHub-Mirror/riotX-android
Crypto: continue cleaning + fix some issues.
This commit is contained in:
parent
c4d7711d2f
commit
664e5354d3
@ -92,34 +92,10 @@ interface CryptoService {
|
|||||||
roomId: String,
|
roomId: String,
|
||||||
callback: MatrixCallback<MXEncryptEventContentResult>)
|
callback: MatrixCallback<MXEncryptEventContentResult>)
|
||||||
|
|
||||||
/*
|
|
||||||
fun start(isInitialSync: Boolean, aCallback: MatrixCallback<Unit>?)
|
|
||||||
|
|
||||||
fun isStarted(): Boolean
|
|
||||||
|
|
||||||
fun isStarting(): Boolean
|
|
||||||
|
|
||||||
fun close()
|
|
||||||
|
|
||||||
|
|
||||||
fun getOlmDevice(): MXOlmDevice?
|
|
||||||
|
|
||||||
fun checkUnknownDevices(userIds: List<String>, callback: MatrixCallback<Unit>)
|
|
||||||
|
|
||||||
fun warnOnUnknownDevices(): Boolean
|
|
||||||
|
|
||||||
@Throws(MXDecryptionException::class)
|
|
||||||
fun decryptEvent(event: Event, timelineId: String?): MXEventDecryptionResult?
|
|
||||||
|
|
||||||
fun resetReplayAttackCheckInTimeline(timelineId: String)
|
|
||||||
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
fun ensureOlmSessionsForUsers(users: List<String>, callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>)
|
|
||||||
*/
|
|
||||||
|
|
||||||
fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult?
|
fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult?
|
||||||
|
|
||||||
|
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>)
|
||||||
|
|
||||||
fun getEncryptionAlgorithm(roomId: String): String?
|
fun getEncryptionAlgorithm(roomId: String): String?
|
||||||
|
|
||||||
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
|
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
|
||||||
|
@ -23,5 +23,5 @@ import com.squareup.moshi.JsonClass
|
|||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class RoomHistoryVisibilityContent(
|
data class RoomHistoryVisibilityContent(
|
||||||
@Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility
|
@Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility? = null
|
||||||
)
|
)
|
@ -73,6 +73,7 @@ import org.matrix.olm.OlmManager
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `CryptoService` class instance manages the end-to-end crypto for a session.
|
* A `CryptoService` class instance manages the end-to-end crypto for a session.
|
||||||
@ -134,22 +135,8 @@ internal class CryptoManager(
|
|||||||
|
|
||||||
// MXEncrypting instance for each room.
|
// MXEncrypting instance for each room.
|
||||||
private val roomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()
|
private val roomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()
|
||||||
|
private val isStarting = AtomicBoolean(false)
|
||||||
// the encryption is starting
|
private val isStarted = AtomicBoolean(false)
|
||||||
private var isStarting = AtomicBoolean(false)
|
|
||||||
|
|
||||||
// tell if the crypto is started
|
|
||||||
private var isStarted = AtomicBoolean(false)
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
//private val mNetworkListener = object : IMXNetworkEventListener {
|
|
||||||
// override fun onNetworkConnectionUpdate(isConnected: Boolean) {
|
|
||||||
// if (isConnected && !isStarted()) {
|
|
||||||
// Timber.v("Start MXCrypto because a network connection has been retrieved ")
|
|
||||||
// start(false, null)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
fun onStateEvent(roomId: String, event: Event) {
|
fun onStateEvent(roomId: String, event: Event) {
|
||||||
when {
|
when {
|
||||||
@ -262,8 +249,6 @@ internal class CryptoManager(
|
|||||||
internalStart(isInitialSync)
|
internalStart(isInitialSync)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isStarting.set(false)
|
|
||||||
isStarted.set(true)
|
|
||||||
outgoingRoomKeyRequestManager.start()
|
outgoingRoomKeyRequestManager.start()
|
||||||
keysBackup.checkAndStartKeysBackup()
|
keysBackup.checkAndStartKeysBackup()
|
||||||
if (isInitialSync) {
|
if (isInitialSync) {
|
||||||
@ -273,6 +258,8 @@ internal class CryptoManager(
|
|||||||
} else {
|
} else {
|
||||||
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
|
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
|
||||||
}
|
}
|
||||||
|
isStarting.set(false)
|
||||||
|
isStarted.set(true)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -589,21 +576,54 @@ internal class CryptoManager(
|
|||||||
*/
|
*/
|
||||||
@Throws(MXDecryptionException::class)
|
@Throws(MXDecryptionException::class)
|
||||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
||||||
val eventContent = event.content
|
|
||||||
if (eventContent == null) {
|
|
||||||
Timber.e("## decryptEvent : empty event content")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
withContext(coroutineDispatchers.crypto) {
|
internalDecryptEvent(event, timeline).fold(
|
||||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String)
|
{ throw it },
|
||||||
if (alg == null) {
|
{ it }
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
|
)
|
||||||
Timber.e("## decryptEvent() : $reason")
|
}
|
||||||
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason))
|
}
|
||||||
} else {
|
|
||||||
alg.decryptEvent(event, timeline)
|
/**
|
||||||
}
|
* Decrypt an event asynchronously
|
||||||
|
*
|
||||||
|
* @param event the raw event.
|
||||||
|
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
|
||||||
|
* @param callback the callback to return data or null
|
||||||
|
*/
|
||||||
|
override fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>) {
|
||||||
|
GlobalScope.launch(EmptyCoroutineContext) {
|
||||||
|
val result = withContext(coroutineDispatchers.crypto) {
|
||||||
|
internalDecryptEvent(event, timeline)
|
||||||
|
}
|
||||||
|
result.fold(
|
||||||
|
{ callback.onFailure(it) },
|
||||||
|
{ callback.onSuccess(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt an event
|
||||||
|
*
|
||||||
|
* @param event the raw event.
|
||||||
|
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
|
||||||
|
* @return the MXEventDecryptionResult data, or null in case of error wrapped into [Try]
|
||||||
|
*/
|
||||||
|
private suspend fun internalDecryptEvent(event: Event, timeline: String): Try<MXEventDecryptionResult?> {
|
||||||
|
return Try {
|
||||||
|
val eventContent = event.content
|
||||||
|
if (eventContent == null) {
|
||||||
|
Timber.e("## decryptEvent : empty event content")
|
||||||
|
return@Try null
|
||||||
|
}
|
||||||
|
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String)
|
||||||
|
if (alg == null) {
|
||||||
|
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
|
||||||
|
Timber.e("## decryptEvent() : $reason")
|
||||||
|
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason))
|
||||||
|
} else {
|
||||||
|
alg.decryptEvent(event, timeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -624,10 +644,16 @@ internal class CryptoManager(
|
|||||||
*/
|
*/
|
||||||
fun onToDeviceEvent(event: Event) {
|
fun onToDeviceEvent(event: Event) {
|
||||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||||
if (event.getClearType() == EventType.ROOM_KEY || event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
|
when (event.getClearType()) {
|
||||||
onRoomKeyEvent(event)
|
EventType.ROOM_KEY, EventType.FORWARDED_ROOM_KEY -> {
|
||||||
} else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
|
onRoomKeyEvent(event)
|
||||||
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
|
}
|
||||||
|
EventType.ROOM_KEY_REQUEST -> {
|
||||||
|
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,7 +664,7 @@ internal class CryptoManager(
|
|||||||
* @param event the key event.
|
* @param event the key event.
|
||||||
*/
|
*/
|
||||||
private fun onRoomKeyEvent(event: Event) {
|
private fun onRoomKeyEvent(event: Event) {
|
||||||
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!!
|
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return
|
||||||
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
|
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
|
||||||
Timber.e("## onRoomKeyEvent() : missing fields")
|
Timber.e("## onRoomKeyEvent() : missing fields")
|
||||||
return
|
return
|
||||||
@ -722,7 +748,6 @@ internal class CryptoManager(
|
|||||||
|
|
||||||
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
|
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
|
||||||
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()
|
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()
|
||||||
|
|
||||||
eventContent?.historyVisibility?.let {
|
eventContent?.historyVisibility?.let {
|
||||||
cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED)
|
cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED)
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
|||||||
* @param timelineId the timeline identifier
|
* @param timelineId the timeline identifier
|
||||||
*/
|
*/
|
||||||
private fun addEventToPendingList(event: Event, timelineId: String) {
|
private fun addEventToPendingList(event: Event, timelineId: String) {
|
||||||
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!!
|
val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return
|
||||||
val pendingEventsKey = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}"
|
val pendingEventsKey = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}"
|
||||||
|
|
||||||
if (!pendingEvents.containsKey(pendingEventsKey)) {
|
if (!pendingEvents.containsKey(pendingEventsKey)) {
|
||||||
@ -190,7 +190,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
|||||||
*/
|
*/
|
||||||
override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {
|
override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {
|
||||||
var exportFormat = false
|
var exportFormat = false
|
||||||
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>()!!
|
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return
|
||||||
|
|
||||||
var senderKey: String? = event.getSenderKey()
|
var senderKey: String? = event.getSenderKey()
|
||||||
var keysClaimed: MutableMap<String, String> = HashMap()
|
var keysClaimed: MutableMap<String, String> = HashMap()
|
||||||
@ -203,11 +203,11 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
|||||||
if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
|
if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
|
||||||
Timber.v("## onRoomKeyEvent(), forward adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId
|
Timber.v("## onRoomKeyEvent(), forward adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId
|
||||||
+ " sessionKey " + roomKeyContent.sessionKey) // from " + event);
|
+ " sessionKey " + roomKeyContent.sessionKey) // from " + event);
|
||||||
val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()!!
|
val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>() ?: return
|
||||||
forwardingCurve25519KeyChain = if (null == forwardedRoomKeyContent.forwardingCurve25519KeyChain) {
|
forwardingCurve25519KeyChain = if (forwardedRoomKeyContent.forwardingCurve25519KeyChain == null) {
|
||||||
ArrayList()
|
ArrayList()
|
||||||
} else {
|
} else {
|
||||||
ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain!!)
|
ArrayList(forwardedRoomKeyContent.forwardingCurve25519KeyChain)
|
||||||
}
|
}
|
||||||
forwardingCurve25519KeyChain.add(senderKey!!)
|
forwardingCurve25519KeyChain.add(senderKey!!)
|
||||||
|
|
||||||
@ -262,6 +262,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
|||||||
*/
|
*/
|
||||||
override fun onNewSession(senderKey: String, sessionId: String) {
|
override fun onNewSession(senderKey: String, sessionId: String) {
|
||||||
//TODO see how to handle this
|
//TODO see how to handle this
|
||||||
|
Timber.v("ON NEW SESSION $sessionId - $senderKey")
|
||||||
/*val k = "$senderKey|$sessionId"
|
/*val k = "$senderKey|$sessionId"
|
||||||
|
|
||||||
val pending = pendingEvents[k]
|
val pending = pendingEvents[k]
|
||||||
|
@ -28,29 +28,29 @@ data class EncryptedEventContent(
|
|||||||
* the used algorithm
|
* the used algorithm
|
||||||
*/
|
*/
|
||||||
@Json(name = "algorithm")
|
@Json(name = "algorithm")
|
||||||
var algorithm: String? = null,
|
val algorithm: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The encrypted event
|
* The encrypted event
|
||||||
*/
|
*/
|
||||||
@Json(name = "ciphertext")
|
@Json(name = "ciphertext")
|
||||||
var ciphertext: String? = null,
|
val ciphertext: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The device id
|
* The device id
|
||||||
*/
|
*/
|
||||||
@Json(name = "device_id")
|
@Json(name = "device_id")
|
||||||
var deviceId: String? = null,
|
val deviceId: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the sender key
|
* the sender key
|
||||||
*/
|
*/
|
||||||
@Json(name = "sender_key")
|
@Json(name = "sender_key")
|
||||||
var senderKey: String? = null,
|
val senderKey: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The session id
|
* The session id
|
||||||
*/
|
*/
|
||||||
@Json(name = "session_id")
|
@Json(name = "session_id")
|
||||||
var sessionId: String? = null
|
val sessionId: String? = null
|
||||||
)
|
)
|
@ -25,18 +25,18 @@ import com.squareup.moshi.JsonClass
|
|||||||
data class RoomKeyContent(
|
data class RoomKeyContent(
|
||||||
|
|
||||||
@Json(name = "algorithm")
|
@Json(name = "algorithm")
|
||||||
var algorithm: String? = null,
|
val algorithm: String? = null,
|
||||||
|
|
||||||
@Json(name = "room_id")
|
@Json(name = "room_id")
|
||||||
var roomId: String? = null,
|
val roomId: String? = null,
|
||||||
|
|
||||||
@Json(name = "session_id")
|
@Json(name = "session_id")
|
||||||
var sessionId: String? = null,
|
val sessionId: String? = null,
|
||||||
|
|
||||||
@Json(name = "session_key")
|
@Json(name = "session_key")
|
||||||
var sessionKey: String? = null,
|
val sessionKey: String? = null,
|
||||||
|
|
||||||
// should be a Long but it is sometimes a double
|
// should be a Long but it is sometimes a double
|
||||||
@Json(name = "chain_index")
|
@Json(name = "chain_index")
|
||||||
var chainIndex: Any? = null
|
val chainIndex: Any? = null
|
||||||
)
|
)
|
||||||
|
@ -25,23 +25,23 @@ import com.squareup.moshi.JsonClass
|
|||||||
data class ForwardedRoomKeyContent(
|
data class ForwardedRoomKeyContent(
|
||||||
|
|
||||||
@Json(name = "algorithm")
|
@Json(name = "algorithm")
|
||||||
var algorithm: String? = null,
|
val algorithm: String? = null,
|
||||||
|
|
||||||
@Json(name = "room_id")
|
@Json(name = "room_id")
|
||||||
var roomId: String? = null,
|
val roomId: String? = null,
|
||||||
|
|
||||||
@Json(name = "sender_key")
|
@Json(name = "sender_key")
|
||||||
var senderKey: String? = null,
|
val senderKey: String? = null,
|
||||||
|
|
||||||
@Json(name = "session_id")
|
@Json(name = "session_id")
|
||||||
var sessionId: String? = null,
|
val sessionId: String? = null,
|
||||||
|
|
||||||
@Json(name = "session_key")
|
@Json(name = "session_key")
|
||||||
var sessionKey: String? = null,
|
val sessionKey: String? = null,
|
||||||
|
|
||||||
@Json(name = "forwarding_curve25519_key_chain")
|
@Json(name = "forwarding_curve25519_key_chain")
|
||||||
var forwardingCurve25519KeyChain: List<String>? = null,
|
val forwardingCurve25519KeyChain: List<String>? = null,
|
||||||
|
|
||||||
@Json(name = "sender_claimed_ed25519_key")
|
@Json(name = "sender_claimed_ed25519_key")
|
||||||
var senderClaimedEd25519Key: String? = null
|
val senderClaimedEd25519Key: String? = null
|
||||||
)
|
)
|
@ -54,14 +54,14 @@ import kotlin.collections.HashMap
|
|||||||
* Short codes interactive verification is a more user friendly way of verifying devices
|
* Short codes interactive verification is a more user friendly way of verifying devices
|
||||||
* that is still maintaining a good level of security (alternative to the 43-character strings compare method).
|
* that is still maintaining a good level of security (alternative to the 43-character strings compare method).
|
||||||
*/
|
*/
|
||||||
internal class DefaultSasVerificationService(private val mCredentials: Credentials,
|
internal class DefaultSasVerificationService(private val credentials: Credentials,
|
||||||
private val mCryptoStore: IMXCryptoStore,
|
private val cryptoStore: IMXCryptoStore,
|
||||||
private val mMyDeviceInfoHolder: MyDeviceInfoHolder,
|
private val myDeviceInfoHolder: MyDeviceInfoHolder,
|
||||||
private val deviceListManager: DeviceListManager,
|
private val deviceListManager: DeviceListManager,
|
||||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val mSendToDeviceTask: SendToDeviceTask,
|
private val sendToDeviceTask: SendToDeviceTask,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
private val mTaskExecutor: TaskExecutor)
|
private val taskExecutor: TaskExecutor)
|
||||||
: VerificationTransaction.Listener, SasVerificationService {
|
: VerificationTransaction.Listener, SasVerificationService {
|
||||||
|
|
||||||
private val uiHandler = Handler(Looper.getMainLooper())
|
private val uiHandler = Handler(Looper.getMainLooper())
|
||||||
@ -194,11 +194,11 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
val tx = IncomingSASVerificationTransaction(
|
val tx = IncomingSASVerificationTransaction(
|
||||||
this,
|
this,
|
||||||
setDeviceVerificationAction,
|
setDeviceVerificationAction,
|
||||||
mCredentials,
|
credentials,
|
||||||
mCryptoStore,
|
cryptoStore,
|
||||||
mSendToDeviceTask,
|
sendToDeviceTask,
|
||||||
mTaskExecutor,
|
taskExecutor,
|
||||||
mMyDeviceInfoHolder.myDevice.fingerprint()!!,
|
myDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||||
startReq.transactionID!!,
|
startReq.transactionID!!,
|
||||||
otherUserId)
|
otherUserId)
|
||||||
addTransaction(tx)
|
addTransaction(tx)
|
||||||
@ -363,11 +363,11 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
val tx = OutgoingSASVerificationRequest(
|
val tx = OutgoingSASVerificationRequest(
|
||||||
this,
|
this,
|
||||||
setDeviceVerificationAction,
|
setDeviceVerificationAction,
|
||||||
mCredentials,
|
credentials,
|
||||||
mCryptoStore,
|
cryptoStore,
|
||||||
mSendToDeviceTask,
|
sendToDeviceTask,
|
||||||
mTaskExecutor,
|
taskExecutor,
|
||||||
mMyDeviceInfoHolder.myDevice.fingerprint()!!,
|
myDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||||
txID,
|
txID,
|
||||||
userId,
|
userId,
|
||||||
deviceID)
|
deviceID)
|
||||||
@ -387,8 +387,8 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
private fun createUniqueIDForTransaction(userId: String, deviceID: String): String {
|
private fun createUniqueIDForTransaction(userId: String, deviceID: String): String {
|
||||||
val buff = StringBuffer()
|
val buff = StringBuffer()
|
||||||
buff
|
buff
|
||||||
.append(mCredentials.userId).append("|")
|
.append(credentials.userId).append("|")
|
||||||
.append(mCredentials.deviceId).append("|")
|
.append(credentials.deviceId).append("|")
|
||||||
.append(userId).append("|")
|
.append(userId).append("|")
|
||||||
.append(deviceID).append("|")
|
.append(deviceID).append("|")
|
||||||
.append(UUID.randomUUID().toString())
|
.append(UUID.randomUUID().toString())
|
||||||
@ -413,7 +413,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
val contentMap = MXUsersDevicesMap<Any>()
|
val contentMap = MXUsersDevicesMap<Any>()
|
||||||
contentMap.setObject(cancelMessage, userId, userDevice)
|
contentMap.setObject(cancelMessage, userId, userDevice)
|
||||||
|
|
||||||
mSendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId))
|
sendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId))
|
||||||
.dispatchTo(object : MatrixCallback<Unit> {
|
.dispatchTo(object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(data: Unit) {
|
override fun onSuccess(data: Unit) {
|
||||||
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
||||||
@ -423,6 +423,6 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.")
|
Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.executeBy(mTaskExecutor)
|
.executeBy(taskExecutor)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -103,13 +103,13 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||||||
val contentModule = ContentModule().definition
|
val contentModule = ContentModule().definition
|
||||||
val cryptoModule = CryptoModule().definition
|
val cryptoModule = CryptoModule().definition
|
||||||
MatrixKoinHolder.instance.loadModules(listOf(sessionModule,
|
MatrixKoinHolder.instance.loadModules(listOf(sessionModule,
|
||||||
syncModule,
|
syncModule,
|
||||||
roomModule,
|
roomModule,
|
||||||
groupModule,
|
groupModule,
|
||||||
userModule,
|
userModule,
|
||||||
signOutModule,
|
signOutModule,
|
||||||
contentModule,
|
contentModule,
|
||||||
cryptoModule))
|
cryptoModule))
|
||||||
scope = getKoin().getOrCreateScope(SCOPE)
|
scope = getKoin().getOrCreateScope(SCOPE)
|
||||||
if (!monarchy.isMonarchyThreadOpen) {
|
if (!monarchy.isMonarchyThreadOpen) {
|
||||||
monarchy.openManually()
|
monarchy.openManually()
|
||||||
@ -350,6 +350,10 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||||||
return cryptoService.decryptEvent(event, timeline)
|
return cryptoService.decryptEvent(event, timeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>) {
|
||||||
|
return cryptoService.decryptEventAsync(event, timeline, callback)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getEncryptionAlgorithm(roomId: String): String? {
|
override fun getEncryptionAlgorithm(roomId: String): String? {
|
||||||
return cryptoService.getEncryptionAlgorithm(roomId)
|
return cryptoService.getEncryptionAlgorithm(roomId)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.session.room.timeline
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
||||||
@ -44,23 +46,7 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
|
|||||||
}
|
}
|
||||||
val event = eventEntity.asDomain()
|
val event = eventEntity.asDomain()
|
||||||
if (event.getClearType() == EventType.ENCRYPTED) {
|
if (event.getClearType() == EventType.ENCRYPTED) {
|
||||||
try {
|
handleEncryptedEvent(event, eventEntity.localId)
|
||||||
Timber.v("Encrypted event: try to decrypt ${event.eventId}")
|
|
||||||
val result = if (decryptionCache.containsKey(eventEntity.localId)) {
|
|
||||||
Timber.v("Encrypted event ${event.eventId} cached")
|
|
||||||
decryptionCache[eventEntity.localId]
|
|
||||||
} else {
|
|
||||||
cryptoService.decryptEvent(event, timelineId)?.also {
|
|
||||||
decryptionCache[eventEntity.localId] = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event.setClearData(result)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Encrypted event: decryption failed")
|
|
||||||
if (e is MXDecryptionException) {
|
|
||||||
event.setCryptoError(e.cryptoError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return TimelineEvent(
|
return TimelineEvent(
|
||||||
event,
|
event,
|
||||||
@ -72,6 +58,28 @@ internal class TimelineEventFactory(private val roomMemberExtractor: SenderRoomM
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleEncryptedEvent(event: Event, eventId: String) {
|
||||||
|
Timber.v("Encrypted event: try to decrypt ${event.eventId}")
|
||||||
|
val cachedDecryption = decryptionCache[eventId]
|
||||||
|
if (cachedDecryption != null) {
|
||||||
|
Timber.v("Encrypted event ${event.eventId} cached")
|
||||||
|
event.setClearData(cachedDecryption)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
val result = cryptoService.decryptEvent(event, timelineId)
|
||||||
|
if (result != null) {
|
||||||
|
decryptionCache[eventId] = result
|
||||||
|
}
|
||||||
|
event.setClearData(result)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.e(failure, "Encrypted event: decryption failed")
|
||||||
|
if (failure is MXDecryptionException) {
|
||||||
|
event.setCryptoError(failure.cryptoError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
senderCache.clear()
|
senderCache.clear()
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ internal class CryptoSyncHandler(private val cryptoManager: CryptoManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSyncCompleted(syncResponse: SyncResponse, fromToken: String?, catchingUp: Boolean) {
|
fun onSyncCompleted(syncResponse: SyncResponse) {
|
||||||
cryptoManager.onSyncCompleted(syncResponse)
|
cryptoManager.onSyncCompleted(syncResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler,
|
|||||||
userAccountDataSyncHandler.handle(syncResponse.accountData)
|
userAccountDataSyncHandler.handle(syncResponse.accountData)
|
||||||
}
|
}
|
||||||
Timber.v("On sync completed")
|
Timber.v("On sync completed")
|
||||||
cryptoSyncHandler.onSyncCompleted(syncResponse, fromToken, isCatchingUp)
|
cryptoSyncHandler.onSyncCompleted(syncResponse)
|
||||||
}
|
}
|
||||||
val isInitialSync = fromToken == null
|
val isInitialSync = fromToken == null
|
||||||
if (!cryptoManager.isStarted()) {
|
if (!cryptoManager.isStarted()) {
|
||||||
|
@ -67,7 +67,7 @@ class HomeModule {
|
|||||||
roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()),
|
roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()),
|
||||||
callItemFactory = CallItemFactory(get()),
|
callItemFactory = CallItemFactory(get()),
|
||||||
encryptionItemFactory = EncryptionItemFactory(get()),
|
encryptionItemFactory = EncryptionItemFactory(get()),
|
||||||
encryptedItemFactory = EncryptedItemFactory(get(), get(), messageItemFactory),
|
encryptedItemFactory = EncryptedItemFactory(get()),
|
||||||
defaultItemFactory = DefaultItemFactory()
|
defaultItemFactory = DefaultItemFactory()
|
||||||
)
|
)
|
||||||
TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider)
|
TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider)
|
||||||
|
@ -20,29 +20,18 @@ import android.graphics.Typeface
|
|||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.style.StyleSpan
|
import android.text.style.StyleSpan
|
||||||
import im.vector.matrix.android.api.session.Session
|
|
||||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
|
||||||
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_
|
||||||
|
|
||||||
class EncryptedItemFactory(
|
// This class handles timeline event who haven't been successfully decrypted
|
||||||
private val session: Session,
|
class EncryptedItemFactory(private val stringProvider: StringProvider) {
|
||||||
private val stringProvider: StringProvider,
|
|
||||||
private val messageItemFactory: MessageItemFactory) {
|
|
||||||
|
|
||||||
fun create(timelineEvent: TimelineEvent,
|
|
||||||
nextEvent: TimelineEvent?,
|
|
||||||
callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {
|
|
||||||
|
|
||||||
|
fun create(timelineEvent: TimelineEvent): VectorEpoxyModel<*>? {
|
||||||
return when {
|
return when {
|
||||||
EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
|
EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
|
||||||
val cryptoError = timelineEvent.root.mCryptoError
|
val cryptoError = timelineEvent.root.mCryptoError
|
||||||
@ -54,7 +43,6 @@ class EncryptedItemFactory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val message = stringProvider.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription)
|
val message = stringProvider.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription)
|
||||||
|
|
||||||
val spannableStr = SpannableString(message)
|
val spannableStr = SpannableString(message)
|
||||||
spannableStr.setSpan(StyleSpan(Typeface.ITALIC), 0, message.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
spannableStr.setSpan(StyleSpan(Typeface.ITALIC), 0, message.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
// TODO This is not correct format for error, change it
|
// TODO This is not correct format for error, change it
|
||||||
|
@ -39,8 +39,9 @@ class RoomHistoryVisibilityItemFactory(private val stringProvider: StringProvide
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
|
private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
|
||||||
val content = event.content.toModel<RoomHistoryVisibilityContent>() ?: return null
|
val historyVisibility = event.content.toModel<RoomHistoryVisibilityContent>()?.historyVisibility
|
||||||
val formattedVisibility = when (content.historyVisibility) {
|
?: return null
|
||||||
|
val formattedVisibility = when (historyVisibility) {
|
||||||
RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared)
|
RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared)
|
||||||
RoomHistoryVisibility.INVITED -> stringProvider.getString(R.string.notice_room_visibility_invited)
|
RoomHistoryVisibility.INVITED -> stringProvider.getString(R.string.notice_room_visibility_invited)
|
||||||
RoomHistoryVisibility.JOINED -> stringProvider.getString(R.string.notice_room_visibility_joined)
|
RoomHistoryVisibility.JOINED -> stringProvider.getString(R.string.notice_room_visibility_joined)
|
||||||
|
@ -51,7 +51,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
|||||||
|
|
||||||
EventType.ENCRYPTION -> encryptionItemFactory.create(event)
|
EventType.ENCRYPTION -> encryptionItemFactory.create(event)
|
||||||
|
|
||||||
EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent, callback)
|
EventType.ENCRYPTED -> encryptedItemFactory.create(event)
|
||||||
|
|
||||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
||||||
EventType.STICKER,
|
EventType.STICKER,
|
||||||
|
Loading…
Reference in New Issue
Block a user