forked from GitHub-Mirror/riotX-android
Crypto: clean some code + add failure send state (but not handled yet).
This commit is contained in:
parent
f2722f4766
commit
612b13808f
@ -26,10 +26,19 @@ enum class SendState {
|
|||||||
SENDING,
|
SENDING,
|
||||||
// the event has been sent
|
// the event has been sent
|
||||||
SENT,
|
SENT,
|
||||||
SYNCED;
|
// the event has been received from server
|
||||||
|
SYNCED,
|
||||||
|
// The event failed to be sent
|
||||||
|
UNDELIVERED,
|
||||||
|
// the event failed to be sent because some unknown devices have been found while encrypting it
|
||||||
|
FAILED_UNKNOWN_DEVICES;
|
||||||
|
|
||||||
fun isSent(): Boolean {
|
fun isSent(): Boolean {
|
||||||
return this == SENT || this == SYNCED
|
return this == SENT || this == SYNCED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasFailed(): Boolean {
|
||||||
|
return this == UNDELIVERED || this == FAILED_UNKNOWN_DEVICES
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
|||||||
val status = deviceTrackingStatuses[userId]!!
|
val status = deviceTrackingStatuses[userId]!!
|
||||||
if (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == status || TRACKING_STATUS_UNREACHABLE_SERVER == status) {
|
if (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == status || TRACKING_STATUS_UNREACHABLE_SERVER == status) {
|
||||||
// if a download was in progress when we got shut down, it isn't any more.
|
// if a download was in progress when we got shut down, it isn't any more.
|
||||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||||
isUpdated = true
|
isUpdated = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import arrow.core.Try
|
import arrow.core.Try
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
|
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||||
import im.vector.matrix.android.api.session.events.model.Content
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||||
@ -291,7 +293,7 @@ internal class MXMegolmEncryption(
|
|||||||
// an m.new_device.
|
// an m.new_device.
|
||||||
return deviceListManager
|
return deviceListManager
|
||||||
.downloadKeys(userIds, false)
|
.downloadKeys(userIds, false)
|
||||||
.map {
|
.flatMap {
|
||||||
val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices()
|
val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices()
|
||||||
|| cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId)
|
|| cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId)
|
||||||
|
|
||||||
@ -299,16 +301,15 @@ internal class MXMegolmEncryption(
|
|||||||
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
||||||
|
|
||||||
for (userId in it.userIds) {
|
for (userId in it.userIds) {
|
||||||
val deviceIds = it.getUserDeviceIds(userId)
|
val deviceIds = it.getUserDeviceIds(userId) ?: continue
|
||||||
|
for (deviceId in deviceIds) {
|
||||||
for (deviceId in deviceIds!!) {
|
val deviceInfo = it.getObject(deviceId, userId) ?: continue
|
||||||
val deviceInfo = it.getObject(deviceId, userId)
|
if (warnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo.isUnknown) {
|
||||||
if (warnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo!!.isUnknown) {
|
|
||||||
// The device is not yet known by the user
|
// The device is not yet known by the user
|
||||||
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (deviceInfo!!.isBlocked) {
|
if (deviceInfo.isBlocked) {
|
||||||
// Remove any blocked devices
|
// Remove any blocked devices
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -324,7 +325,13 @@ internal class MXMegolmEncryption(
|
|||||||
devicesInRoom.setObject(deviceInfo, userId, deviceId)
|
devicesInRoom.setObject(deviceInfo, userId, deviceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
devicesInRoom
|
if (unknownDevices.isEmpty) {
|
||||||
|
Try.just(devicesInRoom)
|
||||||
|
} else {
|
||||||
|
val cryptoError = MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
|
||||||
|
MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)
|
||||||
|
Try.Failure(Failure.CryptoError(cryptoError))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,10 @@ public class MXUsersDevicesMap<E> implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty(){
|
||||||
|
return mMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (null != mMap) {
|
if (null != mMap) {
|
||||||
|
@ -20,14 +20,14 @@ internal class WarnOnUnknownDeviceRepository {
|
|||||||
|
|
||||||
// TODO: set it back to true by default. Need UI
|
// TODO: set it back to true by default. Need UI
|
||||||
// Warn the user if some new devices are detected while encrypting a message.
|
// Warn the user if some new devices are detected while encrypting a message.
|
||||||
private var mWarnOnUnknownDevices = false
|
private var warnOnUnknownDevices = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the encryption must fail if some unknown devices are detected.
|
* Tells if the encryption must fail if some unknown devices are detected.
|
||||||
*
|
*
|
||||||
* @return true to warn when some unknown devices are detected.
|
* @return true to warn when some unknown devices are detected.
|
||||||
*/
|
*/
|
||||||
fun warnOnUnknownDevices() = mWarnOnUnknownDevices
|
fun warnOnUnknownDevices() = warnOnUnknownDevices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the warn status when some unknown devices are detected.
|
* Update the warn status when some unknown devices are detected.
|
||||||
@ -35,7 +35,7 @@ internal class WarnOnUnknownDeviceRepository {
|
|||||||
* @param warn true to warn when some unknown devices are detected.
|
* @param warn true to warn when some unknown devices are detected.
|
||||||
*/
|
*/
|
||||||
fun setWarnOnUnknownDevices(warn: Boolean) {
|
fun setWarnOnUnknownDevices(warn: Boolean) {
|
||||||
mWarnOnUnknownDevices = warn
|
warnOnUnknownDevices = warn
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -36,6 +36,7 @@ import im.vector.matrix.android.internal.session.room.relation.DefaultUpdateQuic
|
|||||||
import im.vector.matrix.android.internal.session.room.relation.FindReactionEventForUndoTask
|
import im.vector.matrix.android.internal.session.room.relation.FindReactionEventForUndoTask
|
||||||
import im.vector.matrix.android.internal.session.room.relation.UpdateQuickReactionTask
|
import im.vector.matrix.android.internal.session.room.relation.UpdateQuickReactionTask
|
||||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||||
|
import im.vector.matrix.android.internal.session.room.send.LocalEchoUpdater
|
||||||
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
|
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
|
||||||
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.*
|
import im.vector.matrix.android.internal.session.room.timeline.*
|
||||||
@ -76,6 +77,10 @@ class RoomModule {
|
|||||||
LocalEchoEventFactory(get(), get())
|
LocalEchoEventFactory(get(), get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
LocalEchoUpdater(get())
|
||||||
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,10 @@ import androidx.work.Worker
|
|||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
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.Event
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult
|
import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult
|
||||||
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
||||||
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||||
@ -40,6 +42,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val crypto by inject<CryptoService>()
|
private val crypto by inject<CryptoService>()
|
||||||
|
private val localEchoUpdater by inject<LocalEchoUpdater>()
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
|
|
||||||
@ -50,6 +53,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
|||||||
if (localEvent.eventId == null) {
|
if (localEvent.eventId == null) {
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
localEchoUpdater.updateSendState(localEvent.eventId, SendState.ENCRYPTING)
|
||||||
|
|
||||||
// TODO Better async handling
|
// TODO Better async handling
|
||||||
val latch = CountDownLatch(1)
|
val latch = CountDownLatch(1)
|
||||||
@ -76,19 +80,21 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
|||||||
latch.await()
|
latch.await()
|
||||||
|
|
||||||
val safeResult = result
|
val safeResult = result
|
||||||
// TODO Update local echo
|
if (safeResult != null) {
|
||||||
return if (error != null) {
|
|
||||||
Result.success() // TODO Pass error!!)
|
|
||||||
} else if (safeResult != null) {
|
|
||||||
val encryptedEvent = localEvent.copy(
|
val encryptedEvent = localEvent.copy(
|
||||||
type = safeResult.mEventType,
|
type = safeResult.mEventType,
|
||||||
content = safeResult.mEventContent
|
content = safeResult.mEventContent
|
||||||
)
|
)
|
||||||
val nextWorkerParams = SendEventWorker.Params(params.roomId, encryptedEvent)
|
val nextWorkerParams = SendEventWorker.Params(params.roomId, encryptedEvent)
|
||||||
Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
return Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
||||||
|
}
|
||||||
} else {
|
val safeError = error
|
||||||
Result.success()
|
val sendState = when (safeError) {
|
||||||
}
|
is Failure.CryptoError -> SendState.FAILED_UNKNOWN_DEVICES
|
||||||
|
else -> SendState.UNDELIVERED
|
||||||
|
}
|
||||||
|
localEchoUpdater.updateSendState(localEvent.eventId, sendState)
|
||||||
|
//always return success, or the chain will be stuck for ever!
|
||||||
|
return Result.success()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * 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.session.room.send
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
|
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.tryTransactionAsync
|
||||||
|
|
||||||
|
internal class LocalEchoUpdater(private val monarchy: Monarchy) {
|
||||||
|
|
||||||
|
fun updateSendState(eventId: String, sendState: SendState) {
|
||||||
|
monarchy.tryTransactionAsync { realm ->
|
||||||
|
val sendingEventEntity = EventEntity.where(realm, eventId).findFirst()
|
||||||
|
if (sendingEventEntity != null) {
|
||||||
|
sendingEventEntity.sendState = sendState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,6 +22,7 @@ import androidx.work.WorkerParameters
|
|||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
@ -39,6 +40,7 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val roomAPI by inject<RoomAPI>()
|
private val roomAPI by inject<RoomAPI>()
|
||||||
|
private val localEchoUpdater by inject<LocalEchoUpdater>()
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localEchoUpdater.updateSendState(event.eventId, SendState.SENDING)
|
||||||
val result = executeRequest<SendResponse> {
|
val result = executeRequest<SendResponse> {
|
||||||
apiCall = roomAPI.send(
|
apiCall = roomAPI.send(
|
||||||
event.eventId,
|
event.eventId,
|
||||||
@ -62,7 +65,7 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
|||||||
when (it) {
|
when (it) {
|
||||||
is Failure.NetworkConnection -> Result.retry()
|
is Failure.NetworkConnection -> Result.retry()
|
||||||
else -> {
|
else -> {
|
||||||
//TODO mark as failed to send?
|
localEchoUpdater.updateSendState(event.eventId, SendState.UNDELIVERED)
|
||||||
//always return success, or the chain will be stuck for ever!
|
//always return success, or the chain will be stuck for ever!
|
||||||
Result.success()
|
Result.success()
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,6 @@ internal object TimelineSendEventWorkCommon {
|
|||||||
WorkManager.getInstance()
|
WorkManager.getInstance()
|
||||||
.beginUniqueWork(buildWorkIdentifier(roomId), ExistingWorkPolicy.APPEND, workRequest)
|
.beginUniqueWork(buildWorkIdentifier(roomId), ExistingWorkPolicy.APPEND, workRequest)
|
||||||
.enqueue()
|
.enqueue()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified W : ListenableWorker> createWork(data: Data): OneTimeWorkRequest {
|
inline fun <reified W : ListenableWorker> createWork(data: Data): OneTimeWorkRequest {
|
||||||
|
Loading…
Reference in New Issue
Block a user