Replace unbreakable space by a regular space
This commit is contained in:
parent
722bccb0bb
commit
448eda8624
|
@ -98,7 +98,7 @@ Changes in Element 1.1.4 (2021-04-09)
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Split network request `/keys/query` into smaller requests (250 users max) (#2925)
|
- Split network request `/keys/query` into smaller requests (250 users max) (#2925)
|
||||||
- Crypto improvement | Bulk send NO_OLM withheld code
|
- Crypto improvement | Bulk send NO_OLM withheld code
|
||||||
- Display the room shield in all room setting screens
|
- Display the room shield in all room setting screens
|
||||||
- Improve message with Emoji only detection (#3017)
|
- Improve message with Emoji only detection (#3017)
|
||||||
- Picture preview when replying. Also add the image preview in the message detail bottomsheet (#2916)
|
- Picture preview when replying. Also add the image preview in the message detail bottomsheet (#2916)
|
||||||
|
@ -657,7 +657,7 @@ Improvements 🙌:
|
||||||
- Sending events is now retried only 3 times, so we avoid blocking the sending queue too long.
|
- Sending events is now retried only 3 times, so we avoid blocking the sending queue too long.
|
||||||
- Display warning when fail to send events in room list
|
- Display warning when fail to send events in room list
|
||||||
- Improve UI of edit role action in member profile
|
- Improve UI of edit role action in member profile
|
||||||
- Moderation | New screen to display list of banned users in room settings, with unban action
|
- Moderation | New screen to display list of banned users in room settings, with unban action
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Fix theme issue on Room directory screen (#1613)
|
- Fix theme issue on Room directory screen (#1613)
|
||||||
|
|
|
@ -545,14 +545,14 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
|
val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
|
||||||
|
|
||||||
if (!existingAlgorithm.isNullOrEmpty() && existingAlgorithm != algorithm) {
|
if (!existingAlgorithm.isNullOrEmpty() && existingAlgorithm != algorithm) {
|
||||||
Timber.e("## CRYPTO | setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
|
Timber.e("## CRYPTO | setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm)
|
val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm)
|
||||||
|
|
||||||
if (!encryptingClass) {
|
if (!encryptingClass) {
|
||||||
Timber.e("## CRYPTO | setEncryptionInRoom() : Unable to encrypt room $roomId with $algorithm")
|
Timber.e("## CRYPTO | setEncryptionInRoom() : Unable to encrypt room $roomId with $algorithm")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,17 +649,17 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
val safeAlgorithm = alg
|
val safeAlgorithm = alg
|
||||||
if (safeAlgorithm != null) {
|
if (safeAlgorithm != null) {
|
||||||
val t0 = System.currentTimeMillis()
|
val t0 = System.currentTimeMillis()
|
||||||
Timber.v("## CRYPTO | encryptEventContent() starts")
|
Timber.v("## CRYPTO | encryptEventContent() starts")
|
||||||
runCatching {
|
runCatching {
|
||||||
val content = safeAlgorithm.encryptEventContent(eventContent, eventType, userIds)
|
val content = safeAlgorithm.encryptEventContent(eventContent, eventType, userIds)
|
||||||
Timber.v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
|
Timber.v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
|
||||||
MXEncryptEventContentResult(content, EventType.ENCRYPTED)
|
MXEncryptEventContentResult(content, EventType.ENCRYPTED)
|
||||||
}.foldToCallback(callback)
|
}.foldToCallback(callback)
|
||||||
} else {
|
} else {
|
||||||
val algorithm = getEncryptionAlgorithm(roomId)
|
val algorithm = getEncryptionAlgorithm(roomId)
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
|
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
|
||||||
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
||||||
Timber.e("## CRYPTO | encryptEventContent() : $reason")
|
Timber.e("## CRYPTO | encryptEventContent() : $reason")
|
||||||
callback.onFailure(Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason)))
|
callback.onFailure(Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -769,7 +769,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
}
|
}
|
||||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
|
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
|
||||||
if (alg == null) {
|
if (alg == null) {
|
||||||
Timber.e("## CRYPTO | GOSSIP onRoomKeyEvent() : Unable to handle keys for ${roomKeyContent.algorithm}")
|
Timber.e("## CRYPTO | GOSSIP onRoomKeyEvent() : Unable to handle keys for ${roomKeyContent.algorithm}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
alg.onRoomKeyEvent(event, keysBackupService)
|
alg.onRoomKeyEvent(event, keysBackupService)
|
||||||
|
@ -777,7 +777,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
|
|
||||||
private fun onKeyWithHeldReceived(event: Event) {
|
private fun onKeyWithHeldReceived(event: Event) {
|
||||||
val withHeldContent = event.getClearContent().toModel<RoomKeyWithHeldContent>() ?: return Unit.also {
|
val withHeldContent = event.getClearContent().toModel<RoomKeyWithHeldContent>() ?: return Unit.also {
|
||||||
Timber.i("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
|
Timber.i("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
|
||||||
}
|
}
|
||||||
Timber.i("## CRYPTO | onKeyWithHeldReceived() received from:${event.senderId}, content <$withHeldContent>")
|
Timber.i("## CRYPTO | onKeyWithHeldReceived() received from:${event.senderId}, content <$withHeldContent>")
|
||||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(withHeldContent.roomId, withHeldContent.algorithm)
|
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(withHeldContent.roomId, withHeldContent.algorithm)
|
||||||
|
@ -790,16 +790,16 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSecretSendReceived(event: Event) {
|
private fun onSecretSendReceived(event: Event) {
|
||||||
Timber.i("## CRYPTO | GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
|
Timber.i("## CRYPTO | GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
|
||||||
if (!event.isEncrypted()) {
|
if (!event.isEncrypted()) {
|
||||||
// secret send messages must be encrypted
|
// secret send messages must be encrypted
|
||||||
Timber.e("## CRYPTO | GOSSIP onSecretSend() :Received unencrypted secret send event")
|
Timber.e("## CRYPTO | GOSSIP onSecretSend() :Received unencrypted secret send event")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Was that sent by us?
|
// Was that sent by us?
|
||||||
if (event.senderId != userId) {
|
if (event.senderId != userId) {
|
||||||
Timber.e("## CRYPTO | GOSSIP onSecretSend() : Ignore secret from other user ${event.senderId}")
|
Timber.e("## CRYPTO | GOSSIP onSecretSend() : Ignore secret from other user ${event.senderId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,13 +809,13 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
.getOutgoingSecretKeyRequests().firstOrNull { it.requestId == secretContent.requestId }
|
.getOutgoingSecretKeyRequests().firstOrNull { it.requestId == secretContent.requestId }
|
||||||
|
|
||||||
if (existingRequest == null) {
|
if (existingRequest == null) {
|
||||||
Timber.i("## CRYPTO | GOSSIP onSecretSend() : Ignore secret that was not requested: ${secretContent.requestId}")
|
Timber.i("## CRYPTO | GOSSIP onSecretSend() : Ignore secret that was not requested: ${secretContent.requestId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handleSDKLevelGossip(existingRequest.secretName, secretContent.secretValue)) {
|
if (!handleSDKLevelGossip(existingRequest.secretName, secretContent.secretValue)) {
|
||||||
// TODO Ask to application layer?
|
// TODO Ask to application layer?
|
||||||
Timber.v("## CRYPTO | onSecretSend() : secret not handled by SDK")
|
Timber.v("## CRYPTO | onSecretSend() : secret not handled by SDK")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,13 +972,13 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||||
runCatching {
|
runCatching {
|
||||||
withContext(coroutineDispatchers.crypto) {
|
withContext(coroutineDispatchers.crypto) {
|
||||||
Timber.v("## CRYPTO | importRoomKeys starts")
|
Timber.v("## CRYPTO | importRoomKeys starts")
|
||||||
|
|
||||||
val t0 = System.currentTimeMillis()
|
val t0 = System.currentTimeMillis()
|
||||||
val roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password)
|
val roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password)
|
||||||
val t1 = System.currentTimeMillis()
|
val t1 = System.currentTimeMillis()
|
||||||
|
|
||||||
Timber.v("## CRYPTO | importRoomKeys : decryptMegolmKeyFile done in ${t1 - t0} ms")
|
Timber.v("## CRYPTO | importRoomKeys : decryptMegolmKeyFile done in ${t1 - t0} ms")
|
||||||
|
|
||||||
val importedSessions = MoshiProvider.providesMoshi()
|
val importedSessions = MoshiProvider.providesMoshi()
|
||||||
.adapter<List<MegolmSessionData>>(Types.newParameterizedType(List::class.java, MegolmSessionData::class.java))
|
.adapter<List<MegolmSessionData>>(Types.newParameterizedType(List::class.java, MegolmSessionData::class.java))
|
||||||
|
@ -986,7 +986,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
|
|
||||||
val t2 = System.currentTimeMillis()
|
val t2 = System.currentTimeMillis()
|
||||||
|
|
||||||
Timber.v("## CRYPTO | importRoomKeys : JSON parsing ${t2 - t1} ms")
|
Timber.v("## CRYPTO | importRoomKeys : JSON parsing ${t2 - t1} ms")
|
||||||
|
|
||||||
if (importedSessions == null) {
|
if (importedSessions == null) {
|
||||||
throw Exception("Error")
|
throw Exception("Error")
|
||||||
|
@ -1125,7 +1125,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
*/
|
*/
|
||||||
override fun reRequestRoomKeyForEvent(event: Event) {
|
override fun reRequestRoomKeyForEvent(event: Event) {
|
||||||
val wireContent = event.content.toModel<EncryptedEventContent>() ?: return Unit.also {
|
val wireContent = event.content.toModel<EncryptedEventContent>() ?: return Unit.also {
|
||||||
Timber.e("## CRYPTO | reRequestRoomKeyForEvent Failed to re-request key, null content")
|
Timber.e("## CRYPTO | reRequestRoomKeyForEvent Failed to re-request key, null content")
|
||||||
}
|
}
|
||||||
|
|
||||||
val requestBody = RoomKeyRequestBody(
|
val requestBody = RoomKeyRequestBody(
|
||||||
|
@ -1140,18 +1140,18 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
|
|
||||||
override fun requestRoomKeyForEvent(event: Event) {
|
override fun requestRoomKeyForEvent(event: Event) {
|
||||||
val wireContent = event.content.toModel<EncryptedEventContent>() ?: return Unit.also {
|
val wireContent = event.content.toModel<EncryptedEventContent>() ?: return Unit.also {
|
||||||
Timber.e("## CRYPTO | requestRoomKeyForEvent Failed to request key, null content eventId: ${event.eventId}")
|
Timber.e("## CRYPTO | requestRoomKeyForEvent Failed to request key, null content eventId: ${event.eventId}")
|
||||||
}
|
}
|
||||||
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||||
// if (!isStarted()) {
|
// if (!isStarted()) {
|
||||||
// Timber.v("## CRYPTO | requestRoomKeyForEvent() : wait after e2e init")
|
// Timber.v("## CRYPTO | requestRoomKeyForEvent() : wait after e2e init")
|
||||||
// internalStart(false)
|
// internalStart(false)
|
||||||
// }
|
// }
|
||||||
roomDecryptorProvider
|
roomDecryptorProvider
|
||||||
.getOrCreateRoomDecryptor(event.roomId, wireContent.algorithm)
|
.getOrCreateRoomDecryptor(event.roomId, wireContent.algorithm)
|
||||||
?.requestKeysForEvent(event, false) ?: run {
|
?.requestKeysForEvent(event, false) ?: run {
|
||||||
Timber.v("## CRYPTO | requestRoomKeyForEvent() : No room decryptor for roomId:${event.roomId} algorithm:${wireContent.algorithm}")
|
Timber.v("## CRYPTO | requestRoomKeyForEvent() : No room decryptor for roomId:${event.roomId} algorithm:${wireContent.algorithm}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1180,11 +1180,11 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
// val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
|
// val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
|
||||||
// val now = System.currentTimeMillis()
|
// val now = System.currentTimeMillis()
|
||||||
// if (now - lastForcedDate < CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
|
// if (now - lastForcedDate < CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
|
||||||
// Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
|
// Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
|
// Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
|
||||||
// lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
|
// lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
|
||||||
//
|
//
|
||||||
// cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
// cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||||
|
@ -1201,7 +1201,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
// val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
// val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
||||||
// val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
// val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||||
// sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
|
// sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
|
||||||
// Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
|
// Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
|
||||||
// val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
// val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
||||||
// sendToDeviceTask.execute(sendToDeviceParams)
|
// sendToDeviceTask.execute(sendToDeviceParams)
|
||||||
// }
|
// }
|
||||||
|
@ -1290,12 +1290,12 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
|
|
||||||
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>) {
|
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>) {
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||||
Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
|
Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
|
||||||
// Ensure to load all room members
|
// Ensure to load all room members
|
||||||
try {
|
try {
|
||||||
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
|
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
|
Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
|
||||||
callback.onFailure(failure)
|
callback.onFailure(failure)
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
@ -1308,7 +1308,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
|
|
||||||
if (alg == null) {
|
if (alg == null) {
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
||||||
Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
|
Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
|
||||||
callback.onFailure(IllegalArgumentException("Missing algorithm"))
|
callback.onFailure(IllegalArgumentException("Missing algorithm"))
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
@ -1318,7 +1318,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
}.fold(
|
}.fold(
|
||||||
{ callback.onSuccess(Unit) },
|
{ callback.onSuccess(Unit) },
|
||||||
{
|
{
|
||||||
Timber.e("## CRYPTO | prepareToEncrypt() failed.")
|
Timber.e("## CRYPTO | prepareToEncrypt() failed.")
|
||||||
callback.onFailure(it)
|
callback.onFailure(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -111,7 +111,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
res = !notReadyToRetryHS.contains(userId.substringAfter(':'))
|
res = !notReadyToRetryHS.contains(userId.substringAfter(':'))
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
|
Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
|
|
||||||
for (userId in userIds) {
|
for (userId in userIds) {
|
||||||
if (!deviceTrackingStatuses.containsKey(userId) || TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses[userId]) {
|
if (!deviceTrackingStatuses.containsKey(userId) || TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses[userId]) {
|
||||||
Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
|
Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
|
||||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||||
isUpdated = true
|
isUpdated = true
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
|
|
||||||
for (userId in changed) {
|
for (userId in changed) {
|
||||||
if (deviceTrackingStatuses.containsKey(userId)) {
|
if (deviceTrackingStatuses.containsKey(userId)) {
|
||||||
Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
|
Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
|
||||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||||
isUpdated = true
|
isUpdated = true
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
|
|
||||||
for (userId in left) {
|
for (userId in left) {
|
||||||
if (deviceTrackingStatuses.containsKey(userId)) {
|
if (deviceTrackingStatuses.containsKey(userId)) {
|
||||||
Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
|
Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
|
||||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED
|
deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED
|
||||||
isUpdated = true
|
isUpdated = true
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
* @param forceDownload Always download the keys even if cached.
|
* @param forceDownload Always download the keys even if cached.
|
||||||
*/
|
*/
|
||||||
suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): MXUsersDevicesMap<CryptoDeviceInfo> {
|
suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): MXUsersDevicesMap<CryptoDeviceInfo> {
|
||||||
Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
|
Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
|
||||||
// Map from userId -> deviceId -> MXDeviceInfo
|
// Map from userId -> deviceId -> MXDeviceInfo
|
||||||
val stored = MXUsersDevicesMap<CryptoDeviceInfo>()
|
val stored = MXUsersDevicesMap<CryptoDeviceInfo>()
|
||||||
|
|
||||||
|
@ -305,13 +305,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if (downloadUsers.isEmpty()) {
|
return if (downloadUsers.isEmpty()) {
|
||||||
Timber.v("## CRYPTO | downloadKeys() : no new user device")
|
Timber.v("## CRYPTO | downloadKeys() : no new user device")
|
||||||
stored
|
stored
|
||||||
} else {
|
} else {
|
||||||
Timber.v("## CRYPTO | downloadKeys() : starts")
|
Timber.v("## CRYPTO | downloadKeys() : starts")
|
||||||
val t0 = System.currentTimeMillis()
|
val t0 = System.currentTimeMillis()
|
||||||
val result = doKeyDownloadForUsers(downloadUsers)
|
val result = doKeyDownloadForUsers(downloadUsers)
|
||||||
Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms")
|
Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms")
|
||||||
result.also {
|
result.also {
|
||||||
it.addEntriesFromMap(stored)
|
it.addEntriesFromMap(stored)
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
* @param downloadUsers the user ids list
|
* @param downloadUsers the user ids list
|
||||||
*/
|
*/
|
||||||
private suspend fun doKeyDownloadForUsers(downloadUsers: List<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
|
private suspend fun doKeyDownloadForUsers(downloadUsers: List<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
|
||||||
Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
|
Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
|
||||||
// get the user ids which did not already trigger a keys download
|
// get the user ids which did not already trigger a keys download
|
||||||
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
|
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
|
||||||
if (filteredUsers.isEmpty()) {
|
if (filteredUsers.isEmpty()) {
|
||||||
|
@ -335,16 +335,16 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
val response = try {
|
val response = try {
|
||||||
downloadKeysForUsersTask.execute(params)
|
downloadKeysForUsersTask.execute(params)
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
|
Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
|
||||||
onKeysDownloadFailed(filteredUsers)
|
onKeysDownloadFailed(filteredUsers)
|
||||||
throw throwable
|
throw throwable
|
||||||
}
|
}
|
||||||
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
|
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
|
||||||
for (userId in filteredUsers) {
|
for (userId in filteredUsers) {
|
||||||
// al devices =
|
// al devices =
|
||||||
val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
|
val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
|
||||||
|
|
||||||
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
|
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
|
||||||
if (!models.isNullOrEmpty()) {
|
if (!models.isNullOrEmpty()) {
|
||||||
val workingCopy = models.toMutableMap()
|
val workingCopy = models.toMutableMap()
|
||||||
for ((deviceId, deviceInfo) in models) {
|
for ((deviceId, deviceInfo) in models) {
|
||||||
|
@ -377,13 +377,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
}
|
}
|
||||||
|
|
||||||
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
|
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
|
||||||
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
|
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
|
||||||
}
|
}
|
||||||
val selfSigningKey = response.selfSigningKeys?.get(userId)?.toCryptoModel()?.also {
|
val selfSigningKey = response.selfSigningKeys?.get(userId)?.toCryptoModel()?.also {
|
||||||
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
|
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
|
||||||
}
|
}
|
||||||
val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
|
val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
|
||||||
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
|
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
|
||||||
}
|
}
|
||||||
cryptoStore.storeUserCrossSigningKeys(
|
cryptoStore.storeUserCrossSigningKeys(
|
||||||
userId,
|
userId,
|
||||||
|
@ -411,28 +411,28 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
*/
|
*/
|
||||||
private fun validateDeviceKeys(deviceKeys: CryptoDeviceInfo?, userId: String, deviceId: String, previouslyStoredDeviceKeys: CryptoDeviceInfo?): Boolean {
|
private fun validateDeviceKeys(deviceKeys: CryptoDeviceInfo?, userId: String, deviceId: String, previouslyStoredDeviceKeys: CryptoDeviceInfo?): Boolean {
|
||||||
if (null == deviceKeys) {
|
if (null == deviceKeys) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
|
Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null == deviceKeys.keys) {
|
if (null == deviceKeys.keys) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
|
Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null == deviceKeys.signatures) {
|
if (null == deviceKeys.signatures) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
|
Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the user_id and device_id in the received deviceKeys are correct
|
// Check that the user_id and device_id in the received deviceKeys are correct
|
||||||
if (deviceKeys.userId != userId) {
|
if (deviceKeys.userId != userId) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
|
Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceKeys.deviceId != deviceId) {
|
if (deviceKeys.deviceId != deviceId) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
|
Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,21 +440,21 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
val signKey = deviceKeys.keys[signKeyId]
|
val signKey = deviceKeys.keys[signKeyId]
|
||||||
|
|
||||||
if (null == signKey) {
|
if (null == signKey) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
|
Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val signatureMap = deviceKeys.signatures[userId]
|
val signatureMap = deviceKeys.signatures[userId]
|
||||||
|
|
||||||
if (null == signatureMap) {
|
if (null == signatureMap) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
|
Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val signature = signatureMap[signKeyId]
|
val signature = signatureMap[signKeyId]
|
||||||
|
|
||||||
if (null == signature) {
|
if (null == signature) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
|
Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isVerified) {
|
if (!isVerified) {
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
|
Timber.e("## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
|
||||||
+ deviceKeys.deviceId + " with error " + errorMessage)
|
+ deviceKeys.deviceId + " with error " + errorMessage)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -480,12 +480,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
// best off sticking with the original keys.
|
// best off sticking with the original keys.
|
||||||
//
|
//
|
||||||
// Should we warn the user about it somehow?
|
// Should we warn the user about it somehow?
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
|
Timber.e("## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
|
||||||
+ deviceKeys.deviceId + " has changed : "
|
+ deviceKeys.deviceId + " has changed : "
|
||||||
+ previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey)
|
+ previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey)
|
||||||
|
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
|
Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
|
||||||
Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
|
Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -499,7 +499,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
* This method must be called on getEncryptingThreadHandler() thread.
|
* This method must be called on getEncryptingThreadHandler() thread.
|
||||||
*/
|
*/
|
||||||
suspend fun refreshOutdatedDeviceLists() {
|
suspend fun refreshOutdatedDeviceLists() {
|
||||||
Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
|
Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
|
||||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||||
|
|
||||||
val users = deviceTrackingStatuses.keys.filterTo(mutableListOf()) { userId ->
|
val users = deviceTrackingStatuses.keys.filterTo(mutableListOf()) { userId ->
|
||||||
|
@ -518,10 +518,10 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
doKeyDownloadForUsers(users)
|
doKeyDownloadForUsers(users)
|
||||||
}.fold(
|
}.fold(
|
||||||
{
|
{
|
||||||
Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
|
Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
|
Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,20 +92,20 @@ internal class EventDecryptor @Inject constructor(
|
||||||
private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
||||||
val eventContent = event.content
|
val eventContent = event.content
|
||||||
if (eventContent == null) {
|
if (eventContent == null) {
|
||||||
Timber.e("## CRYPTO | decryptEvent : empty event content")
|
Timber.e("## CRYPTO | decryptEvent : empty event content")
|
||||||
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
|
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
|
||||||
} else {
|
} else {
|
||||||
val algorithm = eventContent["algorithm"]?.toString()
|
val algorithm = eventContent["algorithm"]?.toString()
|
||||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
|
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
|
||||||
if (alg == null) {
|
if (alg == null) {
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
|
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
|
||||||
Timber.e("## CRYPTO | decryptEvent() : $reason")
|
Timber.e("## CRYPTO | decryptEvent() : $reason")
|
||||||
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason)
|
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
return alg.decryptEvent(event, timeline)
|
return alg.decryptEvent(event, timeline)
|
||||||
} catch (mxCryptoError: MXCryptoError) {
|
} catch (mxCryptoError: MXCryptoError) {
|
||||||
Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
|
Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
|
||||||
if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
|
if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
|
||||||
if (mxCryptoError is MXCryptoError.Base
|
if (mxCryptoError is MXCryptoError.Base
|
||||||
&& mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {
|
&& mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {
|
||||||
|
@ -119,7 +119,7 @@ internal class EventDecryptor @Inject constructor(
|
||||||
markOlmSessionForUnwedging(event.senderId ?: "", it)
|
markOlmSessionForUnwedging(event.senderId ?: "", it)
|
||||||
}
|
}
|
||||||
?: run {
|
?: run {
|
||||||
Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
|
Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,18 +137,18 @@ internal class EventDecryptor @Inject constructor(
|
||||||
val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
|
val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
|
if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
|
||||||
Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
|
Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
|
Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
|
||||||
lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
|
lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
|
||||||
|
|
||||||
// offload this from crypto thread (?)
|
// offload this from crypto thread (?)
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
|
||||||
val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
|
val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
|
||||||
|
|
||||||
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
|
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
|
||||||
|
|
||||||
// Now send a blank message on that session so the other side knows about it.
|
// Now send a blank message on that session so the other side knows about it.
|
||||||
// (The keyshare request is sent in the clear so that won't do)
|
// (The keyshare request is sent in the clear so that won't do)
|
||||||
|
@ -161,13 +161,13 @@ internal class EventDecryptor @Inject constructor(
|
||||||
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
||||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||||
sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
|
sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
|
||||||
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
|
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
|
||||||
withContext(coroutineDispatchers.io) {
|
withContext(coroutineDispatchers.io) {
|
||||||
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
||||||
try {
|
try {
|
||||||
sendToDeviceTask.execute(sendToDeviceParams)
|
sendToDeviceTask.execute(sendToDeviceParams)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
|
Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ internal class MXMegolmDecryption(private val userId: String,
|
||||||
|
|
||||||
@Throws(MXCryptoError::class)
|
@Throws(MXCryptoError::class)
|
||||||
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult {
|
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult {
|
||||||
Timber.v("## CRYPTO | decryptEvent ${event.eventId} , requestKeysOnFail:$requestKeysOnFail")
|
Timber.v("## CRYPTO | decryptEvent ${event.eventId}, requestKeysOnFail:$requestKeysOnFail")
|
||||||
if (event.roomId.isNullOrBlank()) {
|
if (event.roomId.isNullOrBlank()) {
|
||||||
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
|
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ internal class MXMegolmDecryption(private val userId: String,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
|
Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
|
||||||
}
|
}
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -80,9 +80,9 @@ internal class MXMegolmEncryption(
|
||||||
eventType: String,
|
eventType: String,
|
||||||
userIds: List<String>): Content {
|
userIds: List<String>): Content {
|
||||||
val ts = System.currentTimeMillis()
|
val ts = System.currentTimeMillis()
|
||||||
Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
|
Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
|
||||||
val devices = getDevicesInRoom(userIds)
|
val devices = getDevicesInRoom(userIds)
|
||||||
Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
|
Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
|
||||||
val outboundSession = ensureOutboundSession(devices.allowedDevices)
|
val outboundSession = ensureOutboundSession(devices.allowedDevices)
|
||||||
|
|
||||||
return encryptContent(outboundSession, eventType, eventContent)
|
return encryptContent(outboundSession, eventType, eventContent)
|
||||||
|
@ -91,7 +91,7 @@ internal class MXMegolmEncryption(
|
||||||
// annoyingly we have to serialize again the saved outbound session to store message index :/
|
// annoyingly we have to serialize again the saved outbound session to store message index :/
|
||||||
// if not we would see duplicate message index errors
|
// if not we would see duplicate message index errors
|
||||||
olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId)
|
olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId)
|
||||||
Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
|
Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,13 +118,13 @@ internal class MXMegolmEncryption(
|
||||||
|
|
||||||
override suspend fun preshareKey(userIds: List<String>) {
|
override suspend fun preshareKey(userIds: List<String>) {
|
||||||
val ts = System.currentTimeMillis()
|
val ts = System.currentTimeMillis()
|
||||||
Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
|
Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
|
||||||
val devices = getDevicesInRoom(userIds)
|
val devices = getDevicesInRoom(userIds)
|
||||||
val outboundSession = ensureOutboundSession(devices.allowedDevices)
|
val outboundSession = ensureOutboundSession(devices.allowedDevices)
|
||||||
|
|
||||||
notifyWithheldForSession(devices.withHeldDevices, outboundSession)
|
notifyWithheldForSession(devices.withHeldDevices, outboundSession)
|
||||||
|
|
||||||
Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
|
Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,7 +133,7 @@ internal class MXMegolmEncryption(
|
||||||
* @return the session description
|
* @return the session description
|
||||||
*/
|
*/
|
||||||
private fun prepareNewSessionInRoom(): MXOutboundSessionInfo {
|
private fun prepareNewSessionInRoom(): MXOutboundSessionInfo {
|
||||||
Timber.v("## CRYPTO | prepareNewSessionInRoom() ")
|
Timber.v("## CRYPTO | prepareNewSessionInRoom() ")
|
||||||
val sessionId = olmDevice.createOutboundGroupSessionForRoom(roomId)
|
val sessionId = olmDevice.createOutboundGroupSessionForRoom(roomId)
|
||||||
|
|
||||||
val keysClaimedMap = HashMap<String, String>()
|
val keysClaimedMap = HashMap<String, String>()
|
||||||
|
@ -153,7 +153,7 @@ internal class MXMegolmEncryption(
|
||||||
* @param devicesInRoom the devices list
|
* @param devicesInRoom the devices list
|
||||||
*/
|
*/
|
||||||
private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap<CryptoDeviceInfo>): MXOutboundSessionInfo {
|
private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap<CryptoDeviceInfo>): MXOutboundSessionInfo {
|
||||||
Timber.v("## CRYPTO | ensureOutboundSession start")
|
Timber.v("## CRYPTO | ensureOutboundSession start")
|
||||||
var session = outboundSession
|
var session = outboundSession
|
||||||
if (session == null
|
if (session == null
|
||||||
// Need to make a brand new session?
|
// Need to make a brand new session?
|
||||||
|
@ -190,7 +190,7 @@ internal class MXMegolmEncryption(
|
||||||
devicesByUsers: Map<String, List<CryptoDeviceInfo>>) {
|
devicesByUsers: Map<String, List<CryptoDeviceInfo>>) {
|
||||||
// nothing to send, the task is done
|
// nothing to send, the task is done
|
||||||
if (devicesByUsers.isEmpty()) {
|
if (devicesByUsers.isEmpty()) {
|
||||||
Timber.v("## CRYPTO | shareKey() : nothing more to do")
|
Timber.v("## CRYPTO | shareKey() : nothing more to do")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// reduce the map size to avoid request timeout when there are too many devices (Users size * devices per user)
|
// reduce the map size to avoid request timeout when there are too many devices (Users size * devices per user)
|
||||||
|
@ -203,7 +203,7 @@ internal class MXMegolmEncryption(
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timber.v("## CRYPTO | shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
|
Timber.v("## CRYPTO | shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
|
||||||
shareUserDevicesKey(session, subMap)
|
shareUserDevicesKey(session, subMap)
|
||||||
val remainingDevices = devicesByUsers - subMap.keys
|
val remainingDevices = devicesByUsers - subMap.keys
|
||||||
shareKey(session, remainingDevices)
|
shareKey(session, remainingDevices)
|
||||||
|
@ -232,11 +232,11 @@ internal class MXMegolmEncryption(
|
||||||
payload["content"] = submap
|
payload["content"] = submap
|
||||||
|
|
||||||
var t0 = System.currentTimeMillis()
|
var t0 = System.currentTimeMillis()
|
||||||
Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
|
Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
|
||||||
|
|
||||||
val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
|
val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
|
||||||
Timber.v(
|
Timber.v(
|
||||||
"""## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
|
"""## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
|
||||||
.trimMargin()
|
.trimMargin()
|
||||||
)
|
)
|
||||||
val contentMap = MXUsersDevicesMap<Any>()
|
val contentMap = MXUsersDevicesMap<Any>()
|
||||||
|
@ -257,7 +257,7 @@ internal class MXMegolmEncryption(
|
||||||
noOlmToNotify.add(UserDevice(userId, deviceID))
|
noOlmToNotify.add(UserDevice(userId, deviceID))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
|
Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
|
||||||
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
|
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
|
||||||
haveTargets = true
|
haveTargets = true
|
||||||
}
|
}
|
||||||
|
@ -289,17 +289,17 @@ internal class MXMegolmEncryption(
|
||||||
|
|
||||||
if (haveTargets) {
|
if (haveTargets) {
|
||||||
t0 = System.currentTimeMillis()
|
t0 = System.currentTimeMillis()
|
||||||
Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
|
Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
|
||||||
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
|
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
|
||||||
try {
|
try {
|
||||||
sendToDeviceTask.execute(sendToDeviceParams)
|
sendToDeviceTask.execute(sendToDeviceParams)
|
||||||
Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
|
Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
// What to do here...
|
// What to do here...
|
||||||
Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
|
Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
|
Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noOlmToNotify.isNotEmpty()) {
|
if (noOlmToNotify.isNotEmpty()) {
|
||||||
|
@ -317,7 +317,7 @@ internal class MXMegolmEncryption(
|
||||||
sessionId: String,
|
sessionId: String,
|
||||||
senderKey: String?,
|
senderKey: String?,
|
||||||
code: WithHeldCode) {
|
code: WithHeldCode) {
|
||||||
Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
|
Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
|
||||||
val withHeldContent = RoomKeyWithHeldContent(
|
val withHeldContent = RoomKeyWithHeldContent(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
senderKey = senderKey,
|
senderKey = senderKey,
|
||||||
|
@ -336,7 +336,7 @@ internal class MXMegolmEncryption(
|
||||||
try {
|
try {
|
||||||
sendToDeviceTask.execute(params)
|
sendToDeviceTask.execute(params)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
|
Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ internal class MXMegolmEncryption(
|
||||||
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
|
||||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||||
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
|
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
|
||||||
Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
|
Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
|
||||||
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
||||||
return try {
|
return try {
|
||||||
sendToDeviceTask.execute(sendToDeviceParams)
|
sendToDeviceTask.execute(sendToDeviceParams)
|
||||||
|
|
|
@ -57,7 +57,7 @@ object HkdfSha256 {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The output OKM is calculated as follows:
|
The output OKM is calculated as follows:
|
||||||
Notation | -> When the message is composed of several elements we use concatenation (denoted |) in the second argument;
|
Notation | -> When the message is composed of several elements we use concatenation (denoted |) in the second argument;
|
||||||
|
|
||||||
|
|
||||||
N = ceil(L/HashLen)
|
N = ceil(L/HashLen)
|
||||||
|
|
|
@ -83,7 +83,7 @@ internal class DefaultJoinSpaceTask @Inject constructor(
|
||||||
Timber.v("## Space: > Sync done ...")
|
Timber.v("## Space: > Sync done ...")
|
||||||
// after that i should have the children (? do I need to paginate to get state)
|
// after that i should have the children (? do I need to paginate to get state)
|
||||||
val summary = roomSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
|
val summary = roomSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
|
||||||
Timber.v("## Space: Found space summary Name:[${summary?.name}] children: ${summary?.spaceChildren?.size}")
|
Timber.v("## Space: Found space summary Name:[${summary?.name}] children: ${summary?.spaceChildren?.size}")
|
||||||
summary?.spaceChildren?.forEach {
|
summary?.spaceChildren?.forEach {
|
||||||
// val childRoomSummary = it.roomSummary ?: return@forEach
|
// val childRoomSummary = it.roomSummary ?: return@forEach
|
||||||
Timber.v("## Space: Processing child :[${it.childRoomId}] autoJoin:${it.autoJoin}")
|
Timber.v("## Space: Processing child :[${it.childRoomId}] autoJoin:${it.autoJoin}")
|
||||||
|
|
|
@ -64,7 +64,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
|
||||||
* @return true if the event has been decrypted
|
* @return true if the event has been decrypted
|
||||||
*/
|
*/
|
||||||
private fun decryptToDeviceEvent(event: Event, timelineId: String?): Boolean {
|
private fun decryptToDeviceEvent(event: Event, timelineId: String?): Boolean {
|
||||||
Timber.v("## CRYPTO | decryptToDeviceEvent")
|
Timber.v("## CRYPTO | decryptToDeviceEvent")
|
||||||
if (event.getClearType() == EventType.ENCRYPTED) {
|
if (event.getClearType() == EventType.ENCRYPTED) {
|
||||||
var result: MXEventDecryptionResult? = null
|
var result: MXEventDecryptionResult? = null
|
||||||
try {
|
try {
|
||||||
|
@ -76,7 +76,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
|
||||||
val deviceId = cryptoService.getCryptoDeviceInfo(event.senderId!!).firstOrNull {
|
val deviceId = cryptoService.getCryptoDeviceInfo(event.senderId!!).firstOrNull {
|
||||||
it.identityKey() == senderKey
|
it.identityKey() == senderKey
|
||||||
}?.deviceId ?: senderKey
|
}?.deviceId ?: senderKey
|
||||||
Timber.e("## CRYPTO | Failed to decrypt to device event from ${event.senderId}|$deviceId reason:<${event.mCryptoError ?: exception}>")
|
Timber.e("## CRYPTO | Failed to decrypt to device event from ${event.senderId}|$deviceId reason:<${event.mCryptoError ?: exception}>")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != result) {
|
if (null != result) {
|
||||||
|
@ -89,7 +89,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
// should not happen
|
// should not happen
|
||||||
Timber.e("## CRYPTO | ERROR NULL DECRYPTION RESULT from ${event.senderId}")
|
Timber.e("## CRYPTO | ERROR NULL DECRYPTION RESULT from ${event.senderId}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue