Support .verification.ready event
This commit is contained in:
parent
308b15b908
commit
4c0cbca4cb
@ -17,6 +17,7 @@
|
||||
package im.vector.matrix.android.api.session.crypto.sas
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
|
||||
|
||||
/**
|
||||
* https://matrix.org/docs/spec/client_server/r0.5.0#key-verification-framework
|
||||
@ -39,6 +40,8 @@ interface SasVerificationService {
|
||||
|
||||
fun getExistingTransaction(otherUser: String, tid: String): SasVerificationTransaction?
|
||||
|
||||
fun getExistingVerificationRequest(otherUser: String): List<PendingVerificationRequest>?
|
||||
|
||||
/**
|
||||
* Shortcut for KeyVerificationStart.VERIF_METHOD_SAS
|
||||
* @see beginKeyVerification
|
||||
@ -50,7 +53,7 @@ interface SasVerificationService {
|
||||
*/
|
||||
fun beginKeyVerification(method: String, userId: String, deviceID: String): String?
|
||||
|
||||
fun requestKeyVerificationInDMs(userId: String, roomId: String, callback: MatrixCallback<String>?)
|
||||
fun requestKeyVerificationInDMs(userId: String, roomId: String, callback: MatrixCallback<String>?) : PendingVerificationRequest
|
||||
|
||||
fun beginKeyVerificationInDMs(method: String,
|
||||
transactionId: String,
|
||||
@ -59,13 +62,16 @@ interface SasVerificationService {
|
||||
otherDeviceId: String,
|
||||
callback: MatrixCallback<String>?): String?
|
||||
|
||||
fun readyPendingVerificationInDMs(transactionId: String)
|
||||
fun readyPendingVerificationInDMs(otherUserId: String, roomId: String, transactionId: String)
|
||||
|
||||
// fun transactionUpdated(tx: SasVerificationTransaction)
|
||||
|
||||
interface SasVerificationListener {
|
||||
fun transactionCreated(tx: SasVerificationTransaction)
|
||||
fun transactionUpdated(tx: SasVerificationTransaction)
|
||||
fun markedAsManuallyVerified(userId: String, deviceId: String)
|
||||
fun markedAsManuallyVerified(userId: String, deviceId: String) {}
|
||||
|
||||
fun verificationRequestCreated(pr: PendingVerificationRequest) {}
|
||||
fun verificationRequestUpdated(pr: PendingVerificationRequest) {}
|
||||
}
|
||||
}
|
||||
|
@ -89,4 +89,6 @@ interface RoomService {
|
||||
fun getRoomIdByAlias(roomAlias: String,
|
||||
searchOnServer: Boolean,
|
||||
callback: MatrixCallback<Optional<String>>): Cancelable
|
||||
|
||||
fun getExistingDirectRoomWithUser(otherUserId: String) : Room?
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.api.session.room.model.message
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
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.relation.RelationDefaultContent
|
||||
import im.vector.matrix.android.internal.crypto.verification.MessageVerificationReadyFactory
|
||||
import im.vector.matrix.android.internal.crypto.verification.VerificationInfoReady
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class MessageVerificationReadyContent(
|
||||
@Json(name = "from_device") override val fromDevice: String? = null,
|
||||
@Json(name = "methods") override val methods: List<String>? = null,
|
||||
@Json(name = "m.relates_to") val relatesTo: RelationDefaultContent?
|
||||
) : VerificationInfoReady {
|
||||
|
||||
override val transactionID: String?
|
||||
get() = relatesTo?.eventId
|
||||
|
||||
override fun toEventContent() = this.toContent()
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
if (transactionID.isNullOrBlank() || methods.isNullOrEmpty() || fromDevice.isNullOrEmpty()) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
companion object : MessageVerificationReadyFactory {
|
||||
override fun create(tid: String, methods: List<String>, fromDevice: String): VerificationInfoReady {
|
||||
return MessageVerificationReadyContent(
|
||||
fromDevice = fromDevice,
|
||||
methods = methods,
|
||||
relatesTo = RelationDefaultContent(
|
||||
RelationType.REFERENCE,
|
||||
tid
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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.crypto.model.rest
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.internal.crypto.verification.VerificationInfoReady
|
||||
|
||||
/**
|
||||
* Requests a key verification with another user's devices.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class KeyVerificationReady(
|
||||
@Json(name = "from_device") override val fromDevice: String?,
|
||||
//TODO add qr?
|
||||
@Json(name = "methods") override val methods: List<String>? = listOf(KeyVerificationStart.VERIF_METHOD_SAS),
|
||||
@Json(name = "transaction_id") override var transactionID: String? = null
|
||||
) : SendToDeviceObject, VerificationInfoReady {
|
||||
|
||||
override fun toSendToDeviceObject() = this
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
return !transactionID.isNullOrBlank() && !fromDevice.isNullOrBlank() && !methods.isNullOrEmpty()
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ data class KeyVerificationStart(
|
||||
|
||||
companion object {
|
||||
const val VERIF_METHOD_SAS = "m.sas.v1"
|
||||
const val VERIF_METHOD_SCAN = "m.qr_code.scan.v1"
|
||||
}
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
|
@ -33,7 +33,8 @@ internal class DefaultIncomingSASVerificationTransaction(
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
deviceFingerprint: String,
|
||||
transactionId: String,
|
||||
otherUserID: String
|
||||
otherUserID: String,
|
||||
val autoAccept: Boolean = false
|
||||
) : SASVerificationTransaction(
|
||||
setDeviceVerificationAction,
|
||||
credentials,
|
||||
@ -76,6 +77,10 @@ internal class DefaultIncomingSASVerificationTransaction(
|
||||
this.startReq = startReq
|
||||
state = SasVerificationTxState.OnStarted
|
||||
this.otherDeviceId = startReq.fromDevice
|
||||
|
||||
if (autoAccept) {
|
||||
performAccept()
|
||||
}
|
||||
}
|
||||
|
||||
override fun performAccept() {
|
||||
|
@ -78,12 +78,8 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
/**
|
||||
* Map [sender: [PendingVerificationRequest]]
|
||||
*/
|
||||
private val incomingRequests = HashMap<String, ArrayList<PendingVerificationRequest>>()
|
||||
private val pendingRequests = HashMap<String, ArrayList<PendingVerificationRequest>>()
|
||||
|
||||
/**
|
||||
* Map [sender: [PendingVerificationRequest]]
|
||||
*/
|
||||
private val outgoingRequests = HashMap<String, ArrayList<PendingVerificationRequest>>()
|
||||
|
||||
// Event received from the sync
|
||||
fun onToDeviceEvent(event: Event) {
|
||||
@ -130,6 +126,9 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
EventType.KEY_VERIFICATION_MAC -> {
|
||||
onRoomMacReceived(event)
|
||||
}
|
||||
EventType.KEY_VERIFICATION_READY -> {
|
||||
onRoomReadyReceived(event)
|
||||
}
|
||||
EventType.KEY_VERIFICATION_DONE -> {
|
||||
// TODO?
|
||||
}
|
||||
@ -185,6 +184,31 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun dispatchRequestAdded(tx: PendingVerificationRequest) {
|
||||
uiHandler.post {
|
||||
listeners.forEach {
|
||||
try {
|
||||
it.verificationRequestCreated(tx)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "## Error while notifying listeners")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dispatchRequestUpdated(tx: PendingVerificationRequest) {
|
||||
uiHandler.post {
|
||||
listeners.forEach {
|
||||
try {
|
||||
it.verificationRequestUpdated(tx)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "## Error while notifying listeners")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
|
||||
setDeviceVerificationAction.handle(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
|
||||
deviceID,
|
||||
@ -204,13 +228,21 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
val requestInfo = event.getClearContent().toModel<MessageVerificationRequestContent>()
|
||||
?: return
|
||||
val senderId = event.senderId ?: return
|
||||
|
||||
if (requestInfo.toUserId != credentials.userId) {
|
||||
//I should ignore this, it's not for me
|
||||
Timber.w("## SAS Verification ignoring request from ${event.senderId}, not sent to me")
|
||||
return
|
||||
}
|
||||
// Remember this request
|
||||
val requestsForUser = incomingRequests[senderId]
|
||||
val requestsForUser = pendingRequests[senderId]
|
||||
?: ArrayList<PendingVerificationRequest>().also {
|
||||
incomingRequests[event.senderId] = it
|
||||
pendingRequests[event.senderId] = it
|
||||
}
|
||||
|
||||
val pendingVerificationRequest = PendingVerificationRequest(
|
||||
isIncoming = true,
|
||||
otherUserId = senderId,//requestInfo.toUserId,
|
||||
transactionId = event.eventId,
|
||||
requestInfo = requestInfo
|
||||
)
|
||||
@ -320,6 +352,10 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
// Ok we can create
|
||||
if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) {
|
||||
Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
|
||||
// If there is a corresponding request, we can auto accept
|
||||
// as we are the one requesting in first place (or we accepted the request)
|
||||
val autoAccept = getExistingVerificationRequest(otherUserId)?.any { it.transactionId == startReq.transactionID }
|
||||
?: false
|
||||
val tx = DefaultIncomingSASVerificationTransaction(
|
||||
// this,
|
||||
setDeviceVerificationAction,
|
||||
@ -327,7 +363,8 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
cryptoStore,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
startReq.transactionID!!,
|
||||
otherUserId).also { txConfigure(it) }
|
||||
otherUserId,
|
||||
autoAccept).also { txConfigure(it) }
|
||||
addTransaction(tx)
|
||||
tx.acceptVerificationEvent(otherUserId, startReq)
|
||||
} else {
|
||||
@ -490,6 +527,21 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
handleMacReceived(event.senderId, macReq)
|
||||
}
|
||||
|
||||
private fun onRoomReadyReceived(event: Event) {
|
||||
val readyReq = event.getClearContent().toModel<MessageVerificationReadyContent>()
|
||||
?.copy(
|
||||
// relates_to is in clear in encrypted payload
|
||||
relatesTo = event.content.toModel<MessageRelationContent>()?.relatesTo
|
||||
)
|
||||
if (readyReq == null || readyReq.isValid().not() || event.senderId == null) {
|
||||
// ignore
|
||||
Timber.e("## SAS Received invalid ready request")
|
||||
// TODO should we cancel?
|
||||
return
|
||||
}
|
||||
handleReadyReceived(event.senderId, readyReq)
|
||||
}
|
||||
|
||||
private fun onMacReceived(event: Event) {
|
||||
val macReq = event.getClearContent().toModel<KeyVerificationMac>()!!
|
||||
|
||||
@ -515,12 +567,27 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleReadyReceived(senderId: String, readyReq: VerificationInfoReady) {
|
||||
val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == readyReq.transactionID }
|
||||
if (existingRequest == null) {
|
||||
Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionID} fromDevice ${readyReq.fromDevice}")
|
||||
return
|
||||
}
|
||||
updateOutgoingPendingRequest(existingRequest.copy(readyInfo = readyReq))
|
||||
}
|
||||
|
||||
override fun getExistingTransaction(otherUser: String, tid: String): VerificationTransaction? {
|
||||
synchronized(lock = txMap) {
|
||||
return txMap[otherUser]?.get(tid)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExistingVerificationRequest(otherUser: String): List<PendingVerificationRequest>? {
|
||||
synchronized(lock = pendingRequests) {
|
||||
return pendingRequests[otherUser]
|
||||
}
|
||||
}
|
||||
|
||||
private fun getExistingTransactionsForUser(otherUser: String): Collection<VerificationTransaction>? {
|
||||
synchronized(txMap) {
|
||||
return txMap[otherUser]?.values
|
||||
@ -534,13 +601,11 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
}
|
||||
|
||||
private fun addTransaction(tx: VerificationTransaction) {
|
||||
tx.otherUserId.let { otherUserId ->
|
||||
synchronized(txMap) {
|
||||
val txInnerMap = txMap.getOrPut(otherUserId) { HashMap() }
|
||||
txInnerMap[tx.transactionId] = tx
|
||||
dispatchTxAdded(tx)
|
||||
tx.addListener(this)
|
||||
}
|
||||
synchronized(txMap) {
|
||||
val txInnerMap = txMap.getOrPut(tx.otherUserId) { HashMap() }
|
||||
txInnerMap[tx.transactionId] = tx
|
||||
dispatchTxAdded(tx)
|
||||
tx.addListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
@ -570,12 +635,14 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestKeyVerificationInDMs(userId: String, roomId: String, callback: MatrixCallback<String>?) {
|
||||
val requestsForUser = outgoingRequests[userId]
|
||||
override fun requestKeyVerificationInDMs(userId: String, roomId: String, callback: MatrixCallback<String>?)
|
||||
: PendingVerificationRequest {
|
||||
Timber.i("Requesting verification to user: $userId in room ${roomId}")
|
||||
val requestsForUser = pendingRequests[userId]
|
||||
?: ArrayList<PendingVerificationRequest>().also {
|
||||
outgoingRequests[userId] = it
|
||||
pendingRequests[userId] = it
|
||||
}
|
||||
|
||||
|
||||
val params = requestVerificationDMTask.createParamsAndLocalEcho(
|
||||
roomId = roomId,
|
||||
from = credentials.deviceId ?: "",
|
||||
@ -583,13 +650,21 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
to = userId,
|
||||
cryptoService = cryptoService
|
||||
)
|
||||
val verificationRequest = PendingVerificationRequest(
|
||||
isIncoming = false,
|
||||
localID = params.event.eventId ?: "",
|
||||
otherUserId = userId
|
||||
)
|
||||
requestsForUser.add(verificationRequest)
|
||||
dispatchRequestAdded(verificationRequest)
|
||||
|
||||
requestVerificationDMTask.configureWith(
|
||||
params
|
||||
) {
|
||||
this.callback = object : MatrixCallback<SendResponse> {
|
||||
override fun onSuccess(data: SendResponse) {
|
||||
params.event.getClearContent().toModel<MessageVerificationRequestContent>()?.let {
|
||||
requestsForUser.add(PendingVerificationRequest(
|
||||
updateOutgoingPendingRequest(verificationRequest.copy(
|
||||
transactionId = data.eventId,
|
||||
requestInfo = it
|
||||
))
|
||||
@ -604,6 +679,24 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
constraints = TaskConstraints(true)
|
||||
retryCount = 3
|
||||
}.executeBy(taskExecutor)
|
||||
|
||||
return verificationRequest
|
||||
}
|
||||
|
||||
private fun updateOutgoingPendingRequest(updated: PendingVerificationRequest) {
|
||||
val requestsForUser = pendingRequests[updated.otherUserId]
|
||||
?: ArrayList<PendingVerificationRequest>().also {
|
||||
pendingRequests[updated.otherUserId] = it
|
||||
}
|
||||
val index = requestsForUser.indexOfFirst {
|
||||
it.transactionId == updated.transactionId
|
||||
|| it.transactionId == null && it.localID == updated.localID
|
||||
}
|
||||
if (index != -1) {
|
||||
requestsForUser.removeAt(index)
|
||||
}
|
||||
requestsForUser.add(updated)
|
||||
dispatchRequestUpdated(updated)
|
||||
}
|
||||
|
||||
override fun beginKeyVerificationInDMs(method: String, transactionId: String, roomId: String,
|
||||
@ -628,9 +721,27 @@ internal class DefaultSasVerificationService @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun readyPendingVerificationInDMs(transactionId: String) {
|
||||
//
|
||||
override fun readyPendingVerificationInDMs(otherUserId: String, roomId: String, transactionId: String) {
|
||||
// Let's find the related request
|
||||
getExistingVerificationRequest(otherUserId)?.find { it.transactionId == transactionId }?.let {
|
||||
//we need to send a ready event, with matching methods
|
||||
val transport = sasTransportRoomMessageFactory.createTransport(roomId, cryptoService, null)
|
||||
val methods = it.requestInfo?.methods?.intersect(listOf(KeyVerificationStart.VERIF_METHOD_SAS))?.toList()
|
||||
if (methods.isNullOrEmpty()) {
|
||||
Timber.i("Cannot ready this request, no common methods found txId:$transactionId")
|
||||
return@let
|
||||
}
|
||||
//TODO this is not yet related to a transaction, maybe we should use another method like for cancel?
|
||||
val readyMsg = transport.createReady(transactionId, credentials.deviceId ?: "", methods)
|
||||
transport.sendToOther(EventType.KEY_VERIFICATION_READY, readyMsg,
|
||||
SasVerificationTxState.None,
|
||||
CancelCode.User,
|
||||
null // TODO handle error?
|
||||
)
|
||||
updateOutgoingPendingRequest(it.copy(readyInfo = readyMsg))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This string must be unique for the pair of users performing verification for the duration that the transaction is valid
|
||||
*/
|
||||
|
@ -16,12 +16,20 @@
|
||||
package im.vector.matrix.android.internal.crypto.verification
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Stores current pending verification requests
|
||||
*/
|
||||
internal data class PendingVerificationRequest(
|
||||
val transactionId: String?,
|
||||
val requestInfo: MessageVerificationRequestContent?,
|
||||
data class PendingVerificationRequest(
|
||||
val isIncoming: Boolean = false,
|
||||
val localID: String = UUID.randomUUID().toString(),
|
||||
val otherUserId: String,
|
||||
val transactionId: String? = null,
|
||||
val requestInfo: MessageVerificationRequestContent? = null,
|
||||
val readyInfo: VerificationInfoReady? = null
|
||||
)
|
||||
) {
|
||||
|
||||
val isReady: Boolean = readyInfo != null
|
||||
val isSent: Boolean = transactionId != null
|
||||
}
|
||||
|
@ -58,4 +58,7 @@ internal interface SasTransport {
|
||||
shortAuthenticationStrings: List<String>) : VerificationInfoStart
|
||||
|
||||
fun createMac(tid: String, mac: Map<String, String>, keys: String): VerificationInfoMac
|
||||
|
||||
|
||||
fun createReady(tid: String, fromDevice: String, methods: List<String>): VerificationInfoReady
|
||||
}
|
||||
|
@ -167,6 +167,17 @@ internal class SasTransportRoomMessage(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun createReady(tid: String, fromDevice: String, methods: List<String>): VerificationInfoReady {
|
||||
return MessageVerificationReadyContent(
|
||||
fromDevice = fromDevice,
|
||||
relatesTo = RelationDefaultContent(
|
||||
type = RelationType.REFERENCE,
|
||||
eventId = tid
|
||||
),
|
||||
methods = methods
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class SasTransportRoomMessageFactory @Inject constructor(
|
||||
|
@ -126,6 +126,14 @@ internal class SasTransportToDevice(
|
||||
messageAuthenticationCodes,
|
||||
shortAuthenticationStrings)
|
||||
}
|
||||
|
||||
override fun createReady(tid: String, fromDevice: String, methods: List<String>): VerificationInfoReady {
|
||||
return KeyVerificationReady(
|
||||
transactionID = tid,
|
||||
fromDevice = fromDevice,
|
||||
methods = methods
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class SasTransportToDeviceFactory @Inject constructor(
|
||||
|
@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.crypto.verification
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.SendToDeviceObject
|
||||
|
||||
internal interface VerificationInfo {
|
||||
interface VerificationInfo {
|
||||
fun toEventContent(): Content? = null
|
||||
fun toSendToDeviceObject(): SendToDeviceObject? = null
|
||||
fun isValid() : Boolean
|
||||
|
@ -22,7 +22,7 @@ package im.vector.matrix.android.internal.crypto.verification
|
||||
* The m.key.verification.ready event is optional; the recipient of the m.key.verification.request event may respond directly
|
||||
* with a m.key.verification.start event instead.
|
||||
*/
|
||||
internal interface VerificationInfoReady : VerificationInfo {
|
||||
interface VerificationInfoReady : VerificationInfo {
|
||||
|
||||
val transactionID: String?
|
||||
|
||||
@ -36,3 +36,7 @@ internal interface VerificationInfoReady : VerificationInfo {
|
||||
*/
|
||||
val methods: List<String>?
|
||||
}
|
||||
|
||||
internal interface MessageVerificationReadyFactory {
|
||||
fun create(tid: String, methods: List<String>, fromDevice: String): VerificationInfoReady
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ internal class VerificationMessageLiveObserver @Inject constructor(
|
||||
EventType.KEY_VERIFICATION_MAC,
|
||||
EventType.KEY_VERIFICATION_CANCEL,
|
||||
EventType.KEY_VERIFICATION_DONE,
|
||||
EventType.KEY_VERIFICATION_READY,
|
||||
EventType.MESSAGE,
|
||||
EventType.ENCRYPTED)
|
||||
)
|
||||
@ -141,6 +142,14 @@ internal class VerificationMessageLiveObserver @Inject constructor(
|
||||
it.transactionID?.let { txId -> transactionsHandledByOtherDevice.add(txId) }
|
||||
}
|
||||
}
|
||||
} else if (EventType.KEY_VERIFICATION_READY == event.type) {
|
||||
event.getClearContent().toModel<MessageVerificationReadyContent>()?.let {
|
||||
if (it.fromDevice != deviceId) {
|
||||
// The verification is started from another device
|
||||
Timber.v("## SAS Verification live observer: Transaction started by other device tid:${it.transactionID} ")
|
||||
it.transactionID?.let { txId -> transactionsHandledByOtherDevice.add(txId) }
|
||||
}
|
||||
}
|
||||
} else if (EventType.KEY_VERIFICATION_CANCEL == event.type || EventType.KEY_VERIFICATION_DONE == event.type) {
|
||||
event.getClearContent().toModel<MessageRelationContent>()?.relatesTo?.eventId?.let {
|
||||
transactionsHandledByOtherDevice.remove(it)
|
||||
@ -162,6 +171,7 @@ internal class VerificationMessageLiveObserver @Inject constructor(
|
||||
EventType.KEY_VERIFICATION_KEY,
|
||||
EventType.KEY_VERIFICATION_MAC,
|
||||
EventType.KEY_VERIFICATION_CANCEL,
|
||||
EventType.KEY_VERIFICATION_READY,
|
||||
EventType.KEY_VERIFICATION_DONE -> {
|
||||
sasVerificationService.onRoomEvent(event)
|
||||
}
|
||||
|
@ -86,6 +86,20 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
||||
})
|
||||
}
|
||||
|
||||
override fun getExistingDirectRoomWithUser(otherUserId: String): Room? {
|
||||
Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
val roomId = RoomSummaryEntity.where(realm)
|
||||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
|
||||
.findAll()?.let { dms ->
|
||||
dms.firstOrNull {
|
||||
it.otherMemberIds.contains(otherUserId)
|
||||
}
|
||||
}
|
||||
?.roomId ?: return null
|
||||
return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm ->
|
||||
|
@ -49,14 +49,16 @@ enum class VerificationState {
|
||||
UNKNOWN,
|
||||
REQUEST,
|
||||
WAITING,
|
||||
READY,
|
||||
CANCELED_BY_ME,
|
||||
CANCELED_BY_OTHER,
|
||||
DONE
|
||||
}
|
||||
|
||||
fun VerificationState.isCanceled() : Boolean {
|
||||
fun VerificationState.isCanceled(): Boolean {
|
||||
return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by EventRelationAggregationUpdater, when new events that can affect relations are inserted in base.
|
||||
*/
|
||||
@ -119,6 +121,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||
EventType.KEY_VERIFICATION_ACCEPT,
|
||||
EventType.KEY_VERIFICATION_START,
|
||||
EventType.KEY_VERIFICATION_MAC,
|
||||
EventType.KEY_VERIFICATION_READY,
|
||||
EventType.KEY_VERIFICATION_KEY -> {
|
||||
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
||||
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
|
||||
@ -459,6 +462,9 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||
EventType.KEY_VERIFICATION_DONE -> {
|
||||
updateVerificationState(currentState, VerificationState.DONE)
|
||||
}
|
||||
EventType.KEY_VERIFICATION_READY -> {
|
||||
updateVerificationState(currentState, VerificationState.READY)
|
||||
}
|
||||
else -> VerificationState.REQUEST
|
||||
}
|
||||
|
||||
@ -474,7 +480,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateVerificationState(oldState: VerificationState?, newState: VerificationState) : VerificationState {
|
||||
private fun updateVerificationState(oldState: VerificationState?, newState: VerificationState): VerificationState {
|
||||
// Cancel is always prioritary ?
|
||||
// Eg id i found that mac or keys mismatch and send a cancel and the other send a done, i have to
|
||||
// consider as canceled
|
||||
|
@ -30,7 +30,7 @@
|
||||
<!-- This part is inserted in verify_by_scanning_description-->
|
||||
<string name="verify_open_camera_link">open your camera</string>
|
||||
|
||||
<string name="verify_by_emoji_title">Verify by emoji</string>
|
||||
<string name="verify_by_emoji_title">Verify by Emoji</string>
|
||||
<string name="verify_by_emoji_description">If you can’t scan the code above, verify by comparing a short, unique selection of emoji.</string>
|
||||
|
||||
<string name="aria_qr_code_description">QR code image</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user