mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Use workers to send verification messages
This commit is contained in:
parent
5b210df7c5
commit
f541661059
@ -106,6 +106,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||||
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
|
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
|
||||||
|
implementation("com.google.guava:guava:28.2-jre")
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
|
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
|
||||||
|
@ -55,7 +55,7 @@ interface SasVerificationService {
|
|||||||
*/
|
*/
|
||||||
fun beginKeyVerification(method: String, userId: String, deviceID: String): String?
|
fun beginKeyVerification(method: String, userId: String, deviceID: String): String?
|
||||||
|
|
||||||
fun requestKeyVerificationInDMs(userId: String, roomId: String, callback: MatrixCallback<String>?): PendingVerificationRequest
|
fun requestKeyVerificationInDMs(userId: String, roomId: String): PendingVerificationRequest
|
||||||
|
|
||||||
fun beginKeyVerificationInDMs(method: String,
|
fun beginKeyVerificationInDMs(method: String,
|
||||||
transactionId: String,
|
transactionId: String,
|
||||||
|
@ -180,6 +180,9 @@ internal abstract class CryptoModule {
|
|||||||
@Binds
|
@Binds
|
||||||
abstract fun bindEncryptEventTask(encryptEventTask: DefaultEncryptEventTask): EncryptEventTask
|
abstract fun bindEncryptEventTask(encryptEventTask: DefaultEncryptEventTask): EncryptEventTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindSendVerificationMessageTask(sendDefaultSendVerificationMessageTask: DefaultSendVerificationMessageTask): SendVerificationMessageTask
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindClaimOneTimeKeysForUsersDeviceTask(claimOneTimeKeysForUsersDevice: DefaultClaimOneTimeKeysForUsersDevice)
|
abstract fun bindClaimOneTimeKeysForUsersDeviceTask(claimOneTimeKeysForUsersDevice: DefaultClaimOneTimeKeysForUsersDevice)
|
||||||
: ClaimOneTimeKeysForUsersDeviceTask
|
: ClaimOneTimeKeysForUsersDeviceTask
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package im.vector.matrix.android.internal.crypto.tasks
|
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
|
||||||
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.network.executeRequest
|
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
|
||||||
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.send.SendResponse
|
|
||||||
import im.vector.matrix.android.internal.task.Task
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
internal interface RequestVerificationDMTask : Task<RequestVerificationDMTask.Params, SendResponse> {
|
|
||||||
data class Params(
|
|
||||||
val event: Event,
|
|
||||||
val cryptoService: CryptoService
|
|
||||||
)
|
|
||||||
|
|
||||||
fun createParamsAndLocalEcho(roomId: String, from: String, methods: List<String>, to: String, cryptoService: CryptoService): Params
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class DefaultRequestVerificationDMTask @Inject constructor(
|
|
||||||
private val localEchoUpdater: LocalEchoUpdater,
|
|
||||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
|
||||||
private val encryptEventTask: DefaultEncryptEventTask,
|
|
||||||
private val monarchy: Monarchy,
|
|
||||||
private val roomAPI: RoomAPI)
|
|
||||||
: RequestVerificationDMTask {
|
|
||||||
|
|
||||||
override fun createParamsAndLocalEcho(roomId: String, from: String, methods: List<String>, to: String, cryptoService: CryptoService)
|
|
||||||
: RequestVerificationDMTask.Params {
|
|
||||||
val event = localEchoEventFactory.createVerificationRequest(roomId, from, to, methods)
|
|
||||||
.also { localEchoEventFactory.saveLocalEcho(monarchy, it) }
|
|
||||||
return RequestVerificationDMTask.Params(
|
|
||||||
event,
|
|
||||||
cryptoService
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun execute(params: RequestVerificationDMTask.Params): SendResponse {
|
|
||||||
val event = handleEncryption(params)
|
|
||||||
val localID = event.eventId!!
|
|
||||||
|
|
||||||
try {
|
|
||||||
localEchoUpdater.updateSendState(localID, SendState.SENDING)
|
|
||||||
val executeRequest = executeRequest<SendResponse> {
|
|
||||||
apiCall = roomAPI.send(
|
|
||||||
localID,
|
|
||||||
roomId = event.roomId ?: "",
|
|
||||||
content = event.content,
|
|
||||||
eventType = event.type // message or room.encrypted
|
|
||||||
)
|
|
||||||
}
|
|
||||||
localEchoUpdater.updateSendState(localID, SendState.SENT)
|
|
||||||
return executeRequest
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
localEchoUpdater.updateSendState(localID, SendState.UNDELIVERED)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun handleEncryption(params: RequestVerificationDMTask.Params): Event {
|
|
||||||
val roomId = params.event.roomId ?: ""
|
|
||||||
if (params.cryptoService.isRoomEncrypted(roomId)) {
|
|
||||||
try {
|
|
||||||
return encryptEventTask.execute(EncryptEventTask.Params(
|
|
||||||
roomId,
|
|
||||||
params.event,
|
|
||||||
listOf("m.relates_to"),
|
|
||||||
params.cryptoService
|
|
||||||
))
|
|
||||||
} catch (throwable: Throwable) {
|
|
||||||
// We said it's ok to send verification request in clear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params.event
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,64 +15,29 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.matrix.android.internal.crypto.tasks
|
package im.vector.matrix.android.internal.crypto.tasks
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
|
||||||
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.Content
|
|
||||||
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.events.model.LocalEcho
|
|
||||||
import im.vector.matrix.android.api.session.events.model.UnsignedData
|
|
||||||
import im.vector.matrix.android.api.session.room.send.SendState
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.internal.di.UserId
|
|
||||||
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
|
||||||
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.send.LocalEchoUpdater
|
||||||
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal interface SendVerificationMessageTask : Task<SendVerificationMessageTask.Params, SendResponse> {
|
internal interface SendVerificationMessageTask : Task<SendVerificationMessageTask.Params, String> {
|
||||||
data class Params(
|
data class Params(
|
||||||
val type: String,
|
|
||||||
val event: Event,
|
val event: Event,
|
||||||
val cryptoService: CryptoService?
|
val cryptoService: CryptoService?
|
||||||
)
|
)
|
||||||
|
|
||||||
fun createParamsAndLocalEcho(type: String,
|
|
||||||
roomId: String,
|
|
||||||
content: Content,
|
|
||||||
cryptoService: CryptoService?) : Params
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DefaultSendVerificationMessageTask @Inject constructor(
|
internal class DefaultSendVerificationMessageTask @Inject constructor(
|
||||||
private val localEchoUpdater: LocalEchoUpdater,
|
private val localEchoUpdater: LocalEchoUpdater,
|
||||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
|
||||||
private val encryptEventTask: DefaultEncryptEventTask,
|
private val encryptEventTask: DefaultEncryptEventTask,
|
||||||
private val monarchy: Monarchy,
|
|
||||||
@UserId private val userId: String,
|
|
||||||
private val roomAPI: RoomAPI) : SendVerificationMessageTask {
|
private val roomAPI: RoomAPI) : SendVerificationMessageTask {
|
||||||
|
|
||||||
override fun createParamsAndLocalEcho(type: String, roomId: String, content: Content, cryptoService: CryptoService?): SendVerificationMessageTask.Params {
|
override suspend fun execute(params: SendVerificationMessageTask.Params): String {
|
||||||
val localID = LocalEcho.createLocalEchoId()
|
|
||||||
val event = Event(
|
|
||||||
roomId = roomId,
|
|
||||||
originServerTs = System.currentTimeMillis(),
|
|
||||||
senderId = userId,
|
|
||||||
eventId = localID,
|
|
||||||
type = type,
|
|
||||||
content = content,
|
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localID)
|
|
||||||
).also {
|
|
||||||
localEchoEventFactory.saveLocalEcho(monarchy, it)
|
|
||||||
}
|
|
||||||
return SendVerificationMessageTask.Params(
|
|
||||||
type,
|
|
||||||
event,
|
|
||||||
cryptoService
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun execute(params: SendVerificationMessageTask.Params): SendResponse {
|
|
||||||
val event = handleEncryption(params)
|
val event = handleEncryption(params)
|
||||||
val localID = event.eventId!!
|
val localID = event.eventId!!
|
||||||
|
|
||||||
@ -87,7 +52,7 @@ internal class DefaultSendVerificationMessageTask @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
localEchoUpdater.updateSendState(localID, SendState.SENT)
|
localEchoUpdater.updateSendState(localID, SendState.SENT)
|
||||||
return executeRequest
|
return executeRequest.eventId
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
localEchoUpdater.updateSendState(localID, SendState.UNDELIVERED)
|
localEchoUpdater.updateSendState(localID, SendState.UNDELIVERED)
|
||||||
throw e
|
throw e
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.crypto.verification
|
package im.vector.matrix.android.internal.crypto.verification
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
@ -28,6 +29,7 @@ import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
|||||||
import im.vector.matrix.android.api.session.crypto.sas.safeValueOf
|
import im.vector.matrix.android.api.session.crypto.sas.safeValueOf
|
||||||
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.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
|
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.message.*
|
import im.vector.matrix.android.api.session.room.model.message.*
|
||||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||||
@ -37,12 +39,7 @@ import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
|||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.*
|
import im.vector.matrix.android.internal.crypto.model.rest.*
|
||||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultRequestVerificationDMTask
|
|
||||||
import im.vector.matrix.android.internal.session.SessionScope
|
import im.vector.matrix.android.internal.session.SessionScope
|
||||||
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
|
||||||
import im.vector.matrix.android.internal.task.TaskConstraints
|
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
|
||||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -55,16 +52,15 @@ import kotlin.collections.set
|
|||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class DefaultSasVerificationService @Inject constructor(
|
internal class DefaultSasVerificationService @Inject constructor(
|
||||||
|
private val context: Context,
|
||||||
private val credentials: Credentials,
|
private val credentials: Credentials,
|
||||||
private val cryptoStore: IMXCryptoStore,
|
private val cryptoStore: IMXCryptoStore,
|
||||||
private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
|
private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
|
||||||
private val deviceListManager: DeviceListManager,
|
private val deviceListManager: DeviceListManager,
|
||||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val requestVerificationDMTask: DefaultRequestVerificationDMTask,
|
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
private val sasTransportRoomMessageFactory: SasTransportRoomMessageFactory,
|
private val sasTransportRoomMessageFactory: SasTransportRoomMessageFactory,
|
||||||
private val sasTransportToDeviceFactory: SasTransportToDeviceFactory,
|
private val sasTransportToDeviceFactory: SasTransportToDeviceFactory
|
||||||
private val taskExecutor: TaskExecutor
|
|
||||||
) : VerificationTransaction.Listener, SasVerificationService {
|
) : VerificationTransaction.Listener, SasVerificationService {
|
||||||
|
|
||||||
private val uiHandler = Handler(Looper.getMainLooper())
|
private val uiHandler = Handler(Looper.getMainLooper())
|
||||||
@ -279,8 +275,9 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||||||
if (startReq?.isValid()?.not() == true) {
|
if (startReq?.isValid()?.not() == true) {
|
||||||
Timber.e("## received invalid verification request")
|
Timber.e("## received invalid verification request")
|
||||||
if (startReq.transactionID != null) {
|
if (startReq.transactionID != null) {
|
||||||
sasTransportRoomMessageFactory.createTransport(event.roomId
|
sasTransportRoomMessageFactory.createTransport(context, credentials.userId, credentials.deviceId
|
||||||
?: "", cryptoService, null).cancelTransaction(
|
?: "", event.roomId
|
||||||
|
?: "", null).cancelTransaction(
|
||||||
startReq.transactionID ?: "",
|
startReq.transactionID ?: "",
|
||||||
otherUserId!!,
|
otherUserId!!,
|
||||||
startReq.fromDevice ?: event.getSenderKey()!!,
|
startReq.fromDevice ?: event.getSenderKey()!!,
|
||||||
@ -291,11 +288,13 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleStart(otherUserId, startReq as VerificationInfoStart) {
|
handleStart(otherUserId, startReq as VerificationInfoStart) {
|
||||||
it.transport = sasTransportRoomMessageFactory.createTransport(event.roomId
|
it.transport = sasTransportRoomMessageFactory.createTransport(context, credentials.userId, credentials.deviceId
|
||||||
?: "", cryptoService, it)
|
?: "", event.roomId
|
||||||
|
?: "", it)
|
||||||
}?.let {
|
}?.let {
|
||||||
sasTransportRoomMessageFactory.createTransport(event.roomId
|
sasTransportRoomMessageFactory.createTransport(context, credentials.userId, credentials.deviceId
|
||||||
?: "", cryptoService, null).cancelTransaction(
|
?: "", event.roomId
|
||||||
|
?: "", null).cancelTransaction(
|
||||||
startReq.transactionID ?: "",
|
startReq.transactionID ?: "",
|
||||||
otherUserId!!,
|
otherUserId!!,
|
||||||
startReq.fromDevice ?: event.getSenderKey()!!,
|
startReq.fromDevice ?: event.getSenderKey()!!,
|
||||||
@ -693,57 +692,37 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun requestKeyVerificationInDMs(userId: String, roomId: String, callback: MatrixCallback<String>?)
|
override fun requestKeyVerificationInDMs(userId: String, roomId: String)
|
||||||
: PendingVerificationRequest {
|
: PendingVerificationRequest {
|
||||||
Timber.i("## SAS Requesting verification to user: $userId in room $roomId")
|
Timber.i("## SAS Requesting verification to user: $userId in room $roomId")
|
||||||
|
|
||||||
val requestsForUser = pendingRequests[userId]
|
val requestsForUser = pendingRequests[userId]
|
||||||
?: ArrayList<PendingVerificationRequest>().also {
|
?: ArrayList<PendingVerificationRequest>().also {
|
||||||
pendingRequests[userId] = it
|
pendingRequests[userId] = it
|
||||||
}
|
}
|
||||||
|
|
||||||
val params = requestVerificationDMTask.createParamsAndLocalEcho(
|
val transport = sasTransportRoomMessageFactory.createTransport(context, credentials.userId, credentials.deviceId
|
||||||
roomId = roomId,
|
?: "", roomId, null)
|
||||||
from = credentials.deviceId ?: "",
|
|
||||||
methods = listOf(KeyVerificationStart.VERIF_METHOD_SAS),
|
val localID = LocalEcho.createLocalEchoId()
|
||||||
to = userId,
|
|
||||||
cryptoService = cryptoService
|
|
||||||
)
|
|
||||||
val verificationRequest = PendingVerificationRequest(
|
val verificationRequest = PendingVerificationRequest(
|
||||||
ageLocalTs = System.currentTimeMillis(),
|
ageLocalTs = System.currentTimeMillis(),
|
||||||
isIncoming = false,
|
isIncoming = false,
|
||||||
localID = params.event.eventId ?: "",
|
localID = localID,
|
||||||
otherUserId = userId
|
otherUserId = userId
|
||||||
)
|
)
|
||||||
requestsForUser.add(verificationRequest)
|
|
||||||
dispatchRequestAdded(verificationRequest)
|
|
||||||
|
|
||||||
requestVerificationDMTask.configureWith(
|
transport.sendVerificationRequest(localID, userId, roomId) { syncedId, info ->
|
||||||
requestVerificationDMTask.createParamsAndLocalEcho(
|
// We need to update with the syncedID
|
||||||
roomId = roomId,
|
|
||||||
from = credentials.deviceId ?: "",
|
|
||||||
methods = listOf(KeyVerificationStart.VERIF_METHOD_SAS),
|
|
||||||
to = userId,
|
|
||||||
cryptoService = cryptoService
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
this.callback = object : MatrixCallback<SendResponse> {
|
|
||||||
override fun onSuccess(data: SendResponse) {
|
|
||||||
params.event.getClearContent().toModel<MessageVerificationRequestContent>()?.let {
|
|
||||||
updatePendingRequest(verificationRequest.copy(
|
updatePendingRequest(verificationRequest.copy(
|
||||||
transactionId = data.eventId,
|
transactionId = syncedId,
|
||||||
requestInfo = it
|
requestInfo = info
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
callback?.onSuccess(data.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
requestsForUser.add(verificationRequest)
|
||||||
callback?.onFailure(failure)
|
dispatchRequestAdded(verificationRequest)
|
||||||
}
|
|
||||||
}
|
|
||||||
constraints = TaskConstraints(true)
|
|
||||||
retryCount = 3
|
|
||||||
}.executeBy(taskExecutor)
|
|
||||||
|
|
||||||
return verificationRequest
|
return verificationRequest
|
||||||
}
|
}
|
||||||
@ -776,7 +755,8 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||||||
transactionId,
|
transactionId,
|
||||||
otherUserId,
|
otherUserId,
|
||||||
otherDeviceId)
|
otherDeviceId)
|
||||||
tx.transport = sasTransportRoomMessageFactory.createTransport(roomId, cryptoService, tx)
|
tx.transport = sasTransportRoomMessageFactory.createTransport(context, credentials.userId, credentials.deviceId
|
||||||
|
?: "", roomId, tx)
|
||||||
addTransaction(tx)
|
addTransaction(tx)
|
||||||
|
|
||||||
tx.start()
|
tx.start()
|
||||||
@ -790,7 +770,8 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||||||
// Let's find the related request
|
// Let's find the related request
|
||||||
getExistingVerificationRequest(otherUserId)?.find { it.transactionId == transactionId }?.let {
|
getExistingVerificationRequest(otherUserId)?.find { it.transactionId == transactionId }?.let {
|
||||||
// we need to send a ready event, with matching methods
|
// we need to send a ready event, with matching methods
|
||||||
val transport = sasTransportRoomMessageFactory.createTransport(roomId, cryptoService, null)
|
val transport = sasTransportRoomMessageFactory.createTransport(context, credentials.userId, credentials.deviceId
|
||||||
|
?: "", roomId, null)
|
||||||
val methods = it.requestInfo?.methods?.intersect(listOf(KeyVerificationStart.VERIF_METHOD_SAS))?.toList()
|
val methods = it.requestInfo?.methods?.intersect(listOf(KeyVerificationStart.VERIF_METHOD_SAS))?.toList()
|
||||||
if (methods.isNullOrEmpty()) {
|
if (methods.isNullOrEmpty()) {
|
||||||
Timber.i("Cannot ready this request, no common methods found txId:$transactionId")
|
Timber.i("Cannot ready this request, no common methods found txId:$transactionId")
|
||||||
@ -831,28 +812,4 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||||||
this.removeTransaction(tx.otherUserId, tx.transactionId)
|
this.removeTransaction(tx.otherUserId, tx.transactionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// fun cancelTransaction(transactionId: String, userId: String, userDevice: String, code: CancelCode, roomId: String? = null) {
|
|
||||||
// val cancelMessage = KeyVerificationCancel.create(transactionId, code)
|
|
||||||
// val contentMap = MXUsersDevicesMap<Any>()
|
|
||||||
// contentMap.setObject(userId, userDevice, cancelMessage)
|
|
||||||
//
|
|
||||||
// if (roomId != null) {
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// sendToDeviceTask
|
|
||||||
// .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId)) {
|
|
||||||
// this.callback = object : MatrixCallback<Unit> {
|
|
||||||
// override fun onSuccess(data: Unit) {
|
|
||||||
// Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onFailure(failure: Throwable) {
|
|
||||||
// Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// .executeBy(taskExecutor)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.crypto.verification
|
|||||||
|
|
||||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SAS verification can be performed using toDevice events or via DM.
|
* SAS verification can be performed using toDevice events or via DM.
|
||||||
@ -33,6 +34,8 @@ internal interface SasTransport {
|
|||||||
onErrorReason: CancelCode,
|
onErrorReason: CancelCode,
|
||||||
onDone: (() -> Unit)?)
|
onDone: (() -> Unit)?)
|
||||||
|
|
||||||
|
fun sendVerificationRequest(localID: String, otherUserId: String, roomId: String, callback: (String?, MessageVerificationRequestContent?) -> Unit)
|
||||||
|
|
||||||
fun cancelTransaction(transactionId: String, userId: String, userDevice: String, code: CancelCode)
|
fun cancelTransaction(transactionId: String, userId: String, userDevice: String, code: CancelCode)
|
||||||
|
|
||||||
fun done(transactionId: String)
|
fun done(transactionId: String)
|
||||||
|
@ -15,33 +15,41 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.matrix.android.internal.crypto.verification
|
package im.vector.matrix.android.internal.crypto.verification
|
||||||
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import android.content.Context
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.work.*
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.R
|
||||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.*
|
||||||
import im.vector.matrix.android.api.session.events.model.RelationType
|
|
||||||
import im.vector.matrix.android.api.session.events.model.toContent
|
|
||||||
import im.vector.matrix.android.api.session.room.model.message.*
|
import im.vector.matrix.android.api.session.room.model.message.*
|
||||||
import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent
|
import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultSendVerificationMessageTask
|
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.SendVerificationMessageTask
|
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||||
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
import im.vector.matrix.android.internal.worker.WorkManagerUtil
|
||||||
import im.vector.matrix.android.internal.task.TaskConstraints
|
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import kotlinx.coroutines.Dispatchers
|
||||||
import im.vector.matrix.android.internal.task.TaskThread
|
import kotlinx.coroutines.GlobalScope
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class SasTransportRoomMessage(
|
internal class SasTransportRoomMessage(
|
||||||
|
private val context: Context,
|
||||||
|
private val userId: String,
|
||||||
|
private val userDevice: String,
|
||||||
private val roomId: String,
|
private val roomId: String,
|
||||||
private val cryptoService: CryptoService,
|
private val monarchy: Monarchy,
|
||||||
private val tx: SASVerificationTransaction?,
|
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||||
private val sendVerificationMessageTask: SendVerificationMessageTask,
|
private val tx: SASVerificationTransaction?
|
||||||
private val taskExecutor: TaskExecutor
|
|
||||||
) : SasTransport {
|
) : SasTransport {
|
||||||
|
|
||||||
|
private val listenerExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
override fun sendToOther(type: String,
|
override fun sendToOther(type: String,
|
||||||
verificationInfo: VerificationInfo,
|
verificationInfo: VerificationInfo,
|
||||||
nextState: SasVerificationTxState,
|
nextState: SasVerificationTxState,
|
||||||
@ -49,83 +57,167 @@ internal class SasTransportRoomMessage(
|
|||||||
onDone: (() -> Unit)?) {
|
onDone: (() -> Unit)?) {
|
||||||
Timber.d("## SAS sending msg type $type")
|
Timber.d("## SAS sending msg type $type")
|
||||||
Timber.v("## SAS sending msg info $verificationInfo")
|
Timber.v("## SAS sending msg info $verificationInfo")
|
||||||
sendVerificationMessageTask.configureWith(
|
val event = createEventAndLocalEcho(
|
||||||
sendVerificationMessageTask.createParamsAndLocalEcho(
|
type = type,
|
||||||
type,
|
roomId = roomId,
|
||||||
roomId,
|
content = verificationInfo.toEventContent()!!
|
||||||
verificationInfo.toEventContent()!!,
|
|
||||||
cryptoService
|
|
||||||
)
|
)
|
||||||
) {
|
|
||||||
callbackThread = TaskThread.DM_VERIF
|
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
|
||||||
executionThread = TaskThread.DM_VERIF
|
userId = userId,
|
||||||
constraints = TaskConstraints(true)
|
event = event
|
||||||
callback = object : MatrixCallback<SendResponse> {
|
))
|
||||||
override fun onSuccess(data: SendResponse) {
|
val enqueueInfo = enqueueSendWork(workerParams)
|
||||||
|
|
||||||
|
// I cannot just listen to the given work request, because when used in a uniqueWork,
|
||||||
|
// The callback is called while it is still Running ...
|
||||||
|
|
||||||
|
// Futures.addCallback(enqueueInfo.first.result, object : FutureCallback<Operation.State.SUCCESS> {
|
||||||
|
// override fun onSuccess(result: Operation.State.SUCCESS?) {
|
||||||
|
// if (onDone != null) {
|
||||||
|
// onDone()
|
||||||
|
// } else {
|
||||||
|
// tx?.state = nextState
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onFailure(t: Throwable) {
|
||||||
|
// Timber.e("## SAS verification [${tx?.transactionId}] failed to send toDevice in state : ${tx?.state}, reason: ${t.localizedMessage}")
|
||||||
|
// tx?.cancel(onErrorReason)
|
||||||
|
// }
|
||||||
|
// }, listenerExecutor)
|
||||||
|
|
||||||
|
val workLiveData = WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
|
||||||
|
|
||||||
|
val observer = object : Observer<List<WorkInfo>> {
|
||||||
|
override fun onChanged(workInfoList: List<WorkInfo>?) {
|
||||||
|
workInfoList
|
||||||
|
?.filter { it.state == WorkInfo.State.SUCCEEDED }
|
||||||
|
?.firstOrNull { it.id == enqueueInfo.second }
|
||||||
|
?.let { wInfo ->
|
||||||
|
if (wInfo.outputData.getBoolean("failed", false)) {
|
||||||
|
Timber.e("## SAS verification [${tx?.transactionId}] failed to send verification message in state : ${tx?.state}")
|
||||||
|
tx?.cancel(onErrorReason)
|
||||||
|
} else {
|
||||||
if (onDone != null) {
|
if (onDone != null) {
|
||||||
onDone()
|
onDone()
|
||||||
} else {
|
} else {
|
||||||
tx?.state = nextState
|
tx?.state = nextState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
workLiveData.removeObserver(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
// TODO listen to DB to get synced info
|
||||||
Timber.e("## SAS verification [${tx?.transactionId}] failed to send toDevice in state : ${tx?.state}")
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
tx?.cancel(onErrorReason)
|
workLiveData.observeForever(observer)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendVerificationRequest(localID: String, otherUserId: String, roomId: String, callback: (String?, MessageVerificationRequestContent?) -> Unit) {
|
||||||
|
val info = MessageVerificationRequestContent(
|
||||||
|
body = context.getString(R.string.key_verification_request_fallback_message, userId),
|
||||||
|
fromDevice = userDevice,
|
||||||
|
toUserId = otherUserId,
|
||||||
|
methods = listOf(KeyVerificationStart.VERIF_METHOD_SAS)
|
||||||
|
)
|
||||||
|
val content = info.toContent()
|
||||||
|
|
||||||
|
val event = createEventAndLocalEcho(
|
||||||
|
localID,
|
||||||
|
EventType.MESSAGE,
|
||||||
|
roomId,
|
||||||
|
content
|
||||||
|
)
|
||||||
|
|
||||||
|
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
|
||||||
|
userId = userId,
|
||||||
|
event = event
|
||||||
|
))
|
||||||
|
|
||||||
|
val workRequest = WorkManagerUtil.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
|
||||||
|
.setConstraints(WorkManagerUtil.workConstraints)
|
||||||
|
.setInputData(workerParams)
|
||||||
|
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
WorkManager.getInstance(context)
|
||||||
|
.beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND, workRequest)
|
||||||
|
.enqueue()
|
||||||
|
|
||||||
|
// I cannot just listen to the given work request, because when used in a uniqueWork,
|
||||||
|
// The callback is called while it is still Running ...
|
||||||
|
|
||||||
|
val workLiveData = WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
|
||||||
|
|
||||||
|
val observer = object : Observer<List<WorkInfo>> {
|
||||||
|
override fun onChanged(workInfoList: List<WorkInfo>?) {
|
||||||
|
workInfoList
|
||||||
|
?.filter { it.state == WorkInfo.State.SUCCEEDED }
|
||||||
|
?.firstOrNull { it.id == workRequest.id }
|
||||||
|
?.let { wInfo ->
|
||||||
|
if (wInfo.outputData.getBoolean("failed", false)) {
|
||||||
|
callback(null, null)
|
||||||
|
} else if (wInfo.outputData.getString(localID) != null) {
|
||||||
|
callback(wInfo.outputData.getString(localID), info)
|
||||||
|
} else {
|
||||||
|
callback(null, null)
|
||||||
|
}
|
||||||
|
workLiveData.removeObserver(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retryCount = 3
|
|
||||||
}
|
}
|
||||||
.executeBy(taskExecutor)
|
|
||||||
|
// TODO listen to DB to get synced info
|
||||||
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
|
workLiveData.observeForever(observer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelTransaction(transactionId: String, userId: String, userDevice: String, code: CancelCode) {
|
override fun cancelTransaction(transactionId: String, userId: String, userDevice: String, code: CancelCode) {
|
||||||
Timber.d("## SAS canceling transaction $transactionId for reason $code")
|
Timber.d("## SAS canceling transaction $transactionId for reason $code")
|
||||||
sendVerificationMessageTask.configureWith(
|
val event = createEventAndLocalEcho(
|
||||||
sendVerificationMessageTask.createParamsAndLocalEcho(
|
type = EventType.KEY_VERIFICATION_CANCEL,
|
||||||
EventType.KEY_VERIFICATION_CANCEL,
|
roomId = roomId,
|
||||||
roomId,
|
content = MessageVerificationCancelContent.create(transactionId, code).toContent()
|
||||||
MessageVerificationCancelContent.create(transactionId, code).toContent(),
|
|
||||||
cryptoService
|
|
||||||
)
|
)
|
||||||
) {
|
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
|
||||||
callbackThread = TaskThread.DM_VERIF
|
userId = userId,
|
||||||
executionThread = TaskThread.DM_VERIF
|
event = event
|
||||||
constraints = TaskConstraints(true)
|
))
|
||||||
retryCount = 3
|
enqueueSendWork(workerParams)
|
||||||
callback = object : MatrixCallback<SendResponse> {
|
|
||||||
override fun onSuccess(data: SendResponse) {
|
|
||||||
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
|
||||||
Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.executeBy(taskExecutor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun done(transactionId: String) {
|
override fun done(transactionId: String) {
|
||||||
sendVerificationMessageTask.configureWith(
|
val event = createEventAndLocalEcho(
|
||||||
sendVerificationMessageTask.createParamsAndLocalEcho(
|
type = EventType.KEY_VERIFICATION_DONE,
|
||||||
EventType.KEY_VERIFICATION_DONE,
|
roomId = roomId,
|
||||||
roomId,
|
content = MessageVerificationDoneContent(
|
||||||
MessageVerificationDoneContent(
|
|
||||||
relatesTo = RelationDefaultContent(
|
relatesTo = RelationDefaultContent(
|
||||||
RelationType.REFERENCE,
|
RelationType.REFERENCE,
|
||||||
transactionId
|
transactionId
|
||||||
)
|
)
|
||||||
).toContent(),
|
).toContent()
|
||||||
cryptoService
|
|
||||||
)
|
)
|
||||||
) {
|
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
|
||||||
callbackThread = TaskThread.DM_VERIF
|
userId = userId,
|
||||||
executionThread = TaskThread.DM_VERIF
|
event = event
|
||||||
constraints = TaskConstraints(true)
|
))
|
||||||
retryCount = 3
|
enqueueSendWork(workerParams)
|
||||||
}
|
}
|
||||||
.executeBy(taskExecutor)
|
|
||||||
|
private fun enqueueSendWork(workerParams: Data): Pair<Operation, UUID> {
|
||||||
|
val workRequest = WorkManagerUtil.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
|
||||||
|
.setConstraints(WorkManagerUtil.workConstraints)
|
||||||
|
.setInputData(workerParams)
|
||||||
|
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
|
||||||
|
.build()
|
||||||
|
return WorkManager.getInstance(context)
|
||||||
|
.beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND, workRequest)
|
||||||
|
.enqueue() to workRequest.id
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAccept(tid: String,
|
override fun createAccept(tid: String,
|
||||||
@ -178,16 +270,28 @@ internal class SasTransportRoomMessage(
|
|||||||
methods = methods
|
methods = methods
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createEventAndLocalEcho(localID: String = LocalEcho.createLocalEchoId(), type: String, roomId: String, content: Content): Event {
|
||||||
|
return Event(
|
||||||
|
roomId = roomId,
|
||||||
|
originServerTs = System.currentTimeMillis(),
|
||||||
|
senderId = userId,
|
||||||
|
eventId = localID,
|
||||||
|
type = type,
|
||||||
|
content = content,
|
||||||
|
unsignedData = UnsignedData(age = null, transactionId = localID)
|
||||||
|
).also {
|
||||||
|
localEchoEventFactory.saveLocalEcho(monarchy, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SasTransportRoomMessageFactory @Inject constructor(
|
internal class SasTransportRoomMessageFactory @Inject constructor(
|
||||||
private val sendVerificationMessageTask: DefaultSendVerificationMessageTask,
|
private val monarchy: Monarchy,
|
||||||
private val taskExecutor: TaskExecutor) {
|
private val localEchoEventFactory: LocalEchoEventFactory) {
|
||||||
|
|
||||||
fun createTransport(roomId: String,
|
fun createTransport(context: Context, userId: String, userDevice: String, roomId: String, tx: SASVerificationTransaction?
|
||||||
cryptoService: CryptoService,
|
|
||||||
tx: SASVerificationTransaction?
|
|
||||||
): SasTransportRoomMessage {
|
): SasTransportRoomMessage {
|
||||||
return SasTransportRoomMessage(roomId, cryptoService, tx, sendVerificationMessageTask, taskExecutor)
|
return SasTransportRoomMessage(context, userId, userDevice, roomId, monarchy, localEchoEventFactory, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import im.vector.matrix.android.api.MatrixCallback
|
|||||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||||
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.model.message.MessageVerificationRequestContent
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.*
|
import im.vector.matrix.android.internal.crypto.model.rest.*
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||||
@ -33,6 +34,10 @@ internal class SasTransportToDevice(
|
|||||||
private var taskExecutor: TaskExecutor
|
private var taskExecutor: TaskExecutor
|
||||||
) : SasTransport {
|
) : SasTransport {
|
||||||
|
|
||||||
|
override fun sendVerificationRequest(localID: String, otherUserId: String, roomId: String, callback: (String?, MessageVerificationRequestContent?) -> Unit) {
|
||||||
|
// TODO "not implemented"
|
||||||
|
}
|
||||||
|
|
||||||
override fun sendToOther(type: String,
|
override fun sendToOther(type: String,
|
||||||
verificationInfo: VerificationInfo,
|
verificationInfo: VerificationInfo,
|
||||||
nextState: SasVerificationTxState,
|
nextState: SasVerificationTxState,
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
package im.vector.matrix.android.internal.crypto.verification
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.CoroutineWorker
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
|
import im.vector.matrix.android.api.failure.MatrixError
|
||||||
|
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.internal.crypto.tasks.SendVerificationMessageTask
|
||||||
|
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||||
|
import im.vector.matrix.android.internal.worker.getSessionComponent
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class SendVerificationMessageWorker constructor(context: Context, params: WorkerParameters)
|
||||||
|
: CoroutineWorker(context, params) {
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class Params(
|
||||||
|
val userId: String,
|
||||||
|
val event: Event
|
||||||
|
)
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var sendVerificationMessageTask: SendVerificationMessageTask
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var cryptoService: CryptoService
|
||||||
|
|
||||||
|
override suspend fun doWork(): Result {
|
||||||
|
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||||
|
?: return Result.success(Data.Builder().putBoolean("failed", true).build())
|
||||||
|
|
||||||
|
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success()
|
||||||
|
sessionComponent.inject(this)
|
||||||
|
val localId = params.event.eventId ?: ""
|
||||||
|
return try {
|
||||||
|
val eventId = sendVerificationMessageTask.execute(
|
||||||
|
SendVerificationMessageTask.Params(
|
||||||
|
event = params.event,
|
||||||
|
cryptoService = cryptoService
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Result.success(Data.Builder().putString(localId, eventId).build())
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
if (exception.shouldBeRetried()) {
|
||||||
|
Result.retry()
|
||||||
|
} else {
|
||||||
|
Result.success(Data.Builder().putBoolean("failed", true).build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Throwable.shouldBeRetried(): Boolean {
|
||||||
|
return this is Failure.NetworkConnection
|
||||||
|
|| (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ import dagger.Component
|
|||||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.internal.crypto.CryptoModule
|
import im.vector.matrix.android.internal.crypto.CryptoModule
|
||||||
|
import im.vector.matrix.android.internal.crypto.verification.SendVerificationMessageWorker
|
||||||
import im.vector.matrix.android.internal.di.MatrixComponent
|
import im.vector.matrix.android.internal.di.MatrixComponent
|
||||||
import im.vector.matrix.android.internal.di.SessionAssistedInjectModule
|
import im.vector.matrix.android.internal.di.SessionAssistedInjectModule
|
||||||
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
||||||
@ -98,6 +99,8 @@ internal interface SessionComponent {
|
|||||||
|
|
||||||
fun inject(addHttpPusherWorker: AddHttpPusherWorker)
|
fun inject(addHttpPusherWorker: AddHttpPusherWorker)
|
||||||
|
|
||||||
|
fun inject(sendVerificationMessageWorker: SendVerificationMessageWorker)
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(
|
fun create(
|
||||||
|
@ -109,7 +109,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||||||
is VerificationAction.RequestVerificationByDM -> {
|
is VerificationAction.RequestVerificationByDM -> {
|
||||||
// session
|
// session
|
||||||
setState {
|
setState {
|
||||||
copy(pendingRequest = session.getSasVerificationService().requestKeyVerificationInDMs(otherUserId, roomId, null))
|
copy(pendingRequest = session.getSasVerificationService().requestKeyVerificationInDMs(otherUserId, roomId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VerificationAction.StartSASVerification -> {
|
is VerificationAction.StartSASVerification -> {
|
||||||
|
@ -398,7 +398,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
popDraft()
|
popDraft()
|
||||||
}
|
}
|
||||||
is ParsedCommand.VerifyUser -> {
|
is ParsedCommand.VerifyUser -> {
|
||||||
session.getSasVerificationService().requestKeyVerificationInDMs(slashCommandResult.userId, room.roomId, null)
|
session.getSasVerificationService().requestKeyVerificationInDMs(slashCommandResult.userId, room.roomId)
|
||||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled())
|
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled())
|
||||||
popDraft()
|
popDraft()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user