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,
|
||||
// the event has been 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 {
|
||||
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]!!
|
||||
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.
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||
isUpdated = true
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||
import android.text.TextUtils
|
||||
import arrow.core.Try
|
||||
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.EventType
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
@ -88,7 +90,7 @@ internal class MXMegolmEncryption(
|
||||
keysClaimedMap["ed25519"] = olmDevice.deviceEd25519Key!!
|
||||
|
||||
olmDevice.addInboundGroupSession(sessionId!!, olmDevice.getSessionKey(sessionId)!!, roomId, olmDevice.deviceCurve25519Key!!,
|
||||
ArrayList(), keysClaimedMap, false)
|
||||
ArrayList(), keysClaimedMap, false)
|
||||
|
||||
keysBackup.maybeBackupKeys()
|
||||
|
||||
@ -103,10 +105,10 @@ internal class MXMegolmEncryption(
|
||||
private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap<MXDeviceInfo>): Try<MXOutboundSessionInfo> {
|
||||
var session = outboundSession
|
||||
if (session == null
|
||||
// Need to make a brand new session?
|
||||
|| session.needsRotation(sessionRotationPeriodMsgs, sessionRotationPeriodMs)
|
||||
// Determine if we have shared with anyone we shouldn't have
|
||||
|| session.sharedWithTooManyDevices(devicesInRoom)) {
|
||||
// Need to make a brand new session?
|
||||
|| session.needsRotation(sessionRotationPeriodMsgs, sessionRotationPeriodMs)
|
||||
// Determine if we have shared with anyone we shouldn't have
|
||||
|| session.sharedWithTooManyDevices(devicesInRoom)) {
|
||||
session = prepareNewSessionInRoom()
|
||||
outboundSession = session
|
||||
}
|
||||
@ -192,7 +194,7 @@ internal class MXMegolmEncryption(
|
||||
return ensureOlmSessionsForDevicesAction.handle(devicesByUser)
|
||||
.flatMap {
|
||||
Timber.v("## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after "
|
||||
+ (System.currentTimeMillis() - t0) + " ms")
|
||||
+ (System.currentTimeMillis() - t0) + " ms")
|
||||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
var haveTargets = false
|
||||
val userIds = it.userIds
|
||||
@ -227,7 +229,7 @@ internal class MXMegolmEncryption(
|
||||
sendToDeviceTask.execute(sendToDeviceParams)
|
||||
.map {
|
||||
Timber.v("## shareUserDevicesKey() : sendToDevice succeeds after "
|
||||
+ (System.currentTimeMillis() - t0) + " ms")
|
||||
+ (System.currentTimeMillis() - t0) + " ms")
|
||||
|
||||
// Add the devices we have shared with to session.sharedWithDevices.
|
||||
// we deliberately iterate over devicesByUser (ie, the devices we
|
||||
@ -291,24 +293,23 @@ internal class MXMegolmEncryption(
|
||||
// an m.new_device.
|
||||
return deviceListManager
|
||||
.downloadKeys(userIds, false)
|
||||
.map {
|
||||
.flatMap {
|
||||
val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices()
|
||||
|| cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId)
|
||||
|| cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId)
|
||||
|
||||
val devicesInRoom = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
|
||||
for (userId in it.userIds) {
|
||||
val deviceIds = it.getUserDeviceIds(userId)
|
||||
|
||||
for (deviceId in deviceIds!!) {
|
||||
val deviceInfo = it.getObject(deviceId, userId)
|
||||
if (warnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo!!.isUnknown) {
|
||||
val deviceIds = it.getUserDeviceIds(userId) ?: continue
|
||||
for (deviceId in deviceIds) {
|
||||
val deviceInfo = it.getObject(deviceId, userId) ?: continue
|
||||
if (warnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo.isUnknown) {
|
||||
// The device is not yet known by the user
|
||||
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
||||
continue
|
||||
}
|
||||
if (deviceInfo!!.isBlocked) {
|
||||
if (deviceInfo.isBlocked) {
|
||||
// Remove any blocked devices
|
||||
continue
|
||||
}
|
||||
@ -324,7 +325,13 @@ internal class MXMegolmEncryption(
|
||||
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
|
||||
public String toString() {
|
||||
if (null != mMap) {
|
||||
|
@ -20,14 +20,14 @@ internal class WarnOnUnknownDeviceRepository {
|
||||
|
||||
// TODO: set it back to true by default. Need UI
|
||||
// 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.
|
||||
*
|
||||
* @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.
|
||||
@ -35,7 +35,7 @@ internal class WarnOnUnknownDeviceRepository {
|
||||
* @param warn true to warn when some unknown devices are detected.
|
||||
*/
|
||||
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.UpdateQuickReactionTask
|
||||
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.SendStateTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.*
|
||||
@ -76,6 +77,10 @@ class RoomModule {
|
||||
LocalEchoEventFactory(get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
LocalEchoUpdater(get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
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 com.squareup.moshi.JsonClass
|
||||
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.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.di.MatrixKoinComponent
|
||||
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||
@ -40,16 +42,18 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
)
|
||||
|
||||
private val crypto by inject<CryptoService>()
|
||||
private val localEchoUpdater by inject<LocalEchoUpdater>()
|
||||
|
||||
override fun doWork(): Result {
|
||||
|
||||
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||
?: return Result.success()
|
||||
?: return Result.success()
|
||||
|
||||
val localEvent = params.event
|
||||
if (localEvent.eventId == null) {
|
||||
return Result.success()
|
||||
}
|
||||
localEchoUpdater.updateSendState(localEvent.eventId, SendState.ENCRYPTING)
|
||||
|
||||
// TODO Better async handling
|
||||
val latch = CountDownLatch(1)
|
||||
@ -76,19 +80,21 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
latch.await()
|
||||
|
||||
val safeResult = result
|
||||
// TODO Update local echo
|
||||
return if (error != null) {
|
||||
Result.success() // TODO Pass error!!)
|
||||
} else if (safeResult != null) {
|
||||
if (safeResult != null) {
|
||||
val encryptedEvent = localEvent.copy(
|
||||
type = safeResult.mEventType,
|
||||
content = safeResult.mEventContent
|
||||
)
|
||||
val nextWorkerParams = SendEventWorker.Params(params.roomId, encryptedEvent)
|
||||
Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
||||
|
||||
} else {
|
||||
Result.success()
|
||||
return Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
||||
}
|
||||
val safeError = error
|
||||
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 im.vector.matrix.android.api.failure.Failure
|
||||
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.network.executeRequest
|
||||
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 localEchoUpdater by inject<LocalEchoUpdater>()
|
||||
|
||||
override fun doWork(): Result {
|
||||
|
||||
@ -50,6 +52,7 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
localEchoUpdater.updateSendState(event.eventId, SendState.SENDING)
|
||||
val result = executeRequest<SendResponse> {
|
||||
apiCall = roomAPI.send(
|
||||
event.eventId,
|
||||
@ -62,7 +65,7 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
||||
when (it) {
|
||||
is Failure.NetworkConnection -> Result.retry()
|
||||
else -> {
|
||||
//TODO mark as failed to send?
|
||||
localEchoUpdater.updateSendState(event.eventId, SendState.UNDELIVERED)
|
||||
//always return success, or the chain will be stuck for ever!
|
||||
Result.success()
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ internal object TimelineSendEventWorkCommon {
|
||||
WorkManager.getInstance()
|
||||
.beginUniqueWork(buildWorkIdentifier(roomId), ExistingWorkPolicy.APPEND, workRequest)
|
||||
.enqueue()
|
||||
|
||||
}
|
||||
|
||||
inline fun <reified W : ListenableWorker> createWork(data: Data): OneTimeWorkRequest {
|
||||
|
@ -56,12 +56,12 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
var reactionPillCallback: TimelineEventController.ReactionPillCallback? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var avatarCallback: TimelineEventController.AvatarCallback?= null
|
||||
var avatarCallback: TimelineEventController.AvatarCallback? = null
|
||||
|
||||
private val _avatarClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _avatarClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
avatarCallback?.onAvatarClicked(informationData)
|
||||
})
|
||||
private val _memberNameClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _memberNameClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
avatarCallback?.onMemberNameClicked(informationData)
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user