mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Notify other devices of acceptance of verification request
This commit is contained in:
parent
f7303789a0
commit
123ad87eda
1
changelog.d/5724.sdk
Normal file
1
changelog.d/5724.sdk
Normal file
@ -0,0 +1 @@
|
||||
- Notifies other devices when a verification request sent from an Android device is accepted.`
|
@ -27,11 +27,13 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.auth.UserPasswordAuth
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||
import org.matrix.android.sdk.common.CommonTestHelper
|
||||
import org.matrix.android.sdk.common.CryptoTestHelper
|
||||
import org.matrix.android.sdk.common.SessionTestParams
|
||||
import org.matrix.android.sdk.common.TestConstants
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import kotlin.coroutines.Continuation
|
||||
@ -252,4 +254,48 @@ class VerificationTest : InstrumentedTest {
|
||||
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_selfVerificationAcceptedCancelsItForOtherSessions() {
|
||||
val defaultSessionParams = SessionTestParams(true)
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSessionToVerify = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
|
||||
val aliceSessionThatVerifies = testHelper.logIntoAccount(aliceSessionToVerify.myUserId, TestConstants.PASSWORD, defaultSessionParams)
|
||||
val aliceSessionThatReceivesCanceledEvent = testHelper.logIntoAccount(aliceSessionToVerify.myUserId, TestConstants.PASSWORD, defaultSessionParams)
|
||||
|
||||
val verificationMethods = listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW)
|
||||
|
||||
val serviceOfVerified = aliceSessionToVerify.cryptoService().verificationService()
|
||||
val serviceOfVerifier = aliceSessionThatVerifies.cryptoService().verificationService()
|
||||
val serviceOfUserWhoReceivesCancellation = aliceSessionThatReceivesCanceledEvent.cryptoService().verificationService()
|
||||
|
||||
serviceOfVerifier.addListener(object : VerificationService.Listener {
|
||||
override fun verificationRequestCreated(pr: PendingVerificationRequest) {
|
||||
// Accept verification request
|
||||
serviceOfVerifier.readyPendingVerification(
|
||||
verificationMethods,
|
||||
pr.otherUserId,
|
||||
pr.transactionId!!,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
serviceOfVerified.requestKeyVerification(
|
||||
methods = verificationMethods,
|
||||
otherUserId = aliceSessionToVerify.myUserId,
|
||||
otherDevices = listOfNotNull(aliceSessionThatVerifies.sessionParams.deviceId, aliceSessionThatReceivesCanceledEvent.sessionParams.deviceId),
|
||||
)
|
||||
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val requests = serviceOfUserWhoReceivesCancellation.getExistingVerificationRequests(aliceSessionToVerify.myUserId)
|
||||
requests.any { it.cancelConclusion == CancelCode.AcceptedByAnotherDevice }
|
||||
}
|
||||
}
|
||||
|
||||
testHelper.signOutAndClose(aliceSessionToVerify)
|
||||
testHelper.signOutAndClose(aliceSessionThatVerifies)
|
||||
testHelper.signOutAndClose(aliceSessionThatReceivesCanceledEvent)
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ enum class CancelCode(val value: String, val humanReadable: String) {
|
||||
MismatchedKeys("m.key_mismatch", "Key mismatch"),
|
||||
UserError("m.user_error", "User error"),
|
||||
MismatchedUser("m.user_mismatch", "User mismatch"),
|
||||
QrCodeInvalid("m.qr_code.invalid", "Invalid QR code")
|
||||
QrCodeInvalid("m.qr_code.invalid", "Invalid QR code"),
|
||||
AcceptedByAnotherDevice("m.accepted", "Verification request accepted by another device")
|
||||
}
|
||||
|
||||
fun safeValueOf(code: String?): CancelCode {
|
||||
|
@ -939,9 +939,25 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
|
||||
updatePendingRequest(
|
||||
existingRequest.copy(
|
||||
readyInfo = readyReq
|
||||
readyInfo = readyReq
|
||||
)
|
||||
)
|
||||
|
||||
notifyOthersOfAcceptance(readyReq.transactionId, readyReq.fromDevice)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of device ids excluding the current one.
|
||||
*/
|
||||
private fun getMyOtherDeviceIds(): List<String> = cryptoStore.getUserDevices(userId)?.keys?.filter { it != deviceId }.orEmpty()
|
||||
|
||||
/**
|
||||
* Notifies other devices that the current verification transaction is being handled by [acceptedByDeviceId].
|
||||
*/
|
||||
private fun notifyOthersOfAcceptance(transactionId: String, acceptedByDeviceId: String) {
|
||||
val deviceIds = getMyOtherDeviceIds().filter { it != acceptedByDeviceId }
|
||||
val transport = verificationTransportToDeviceFactory.createTransport(null)
|
||||
transport.cancelTransaction(transactionId, userId, deviceIds, CancelCode.AcceptedByAnotherDevice)
|
||||
}
|
||||
|
||||
private fun createQrCodeData(requestId: String?, otherUserId: String, otherDeviceId: String?): QrCodeData? {
|
||||
|
@ -49,6 +49,11 @@ internal interface VerificationTransport {
|
||||
otherUserDeviceId: String?,
|
||||
code: CancelCode)
|
||||
|
||||
fun cancelTransaction(transactionId: String,
|
||||
otherUserId: String,
|
||||
otherUserDeviceIds: List<String>,
|
||||
code: CancelCode)
|
||||
|
||||
fun done(transactionId: String,
|
||||
onDone: (() -> Unit)?)
|
||||
|
||||
|
@ -160,6 +160,9 @@ internal class VerificationTransportRoomMessage(
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceIds: List<String>, code: CancelCode) =
|
||||
cancelTransaction(transactionId, otherUserId, null, code)
|
||||
|
||||
override fun done(transactionId: String,
|
||||
onDone: (() -> Unit)?) {
|
||||
Timber.d("## SAS sending done for $transactionId")
|
||||
|
@ -193,6 +193,27 @@ internal class VerificationTransportToDevice(
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceIds: List<String>, code: CancelCode) {
|
||||
Timber.d("## SAS canceling transaction $transactionId for reason $code")
|
||||
val cancelMessage = KeyVerificationCancel.create(transactionId, code)
|
||||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
val messages = otherUserDeviceIds.associateWith { cancelMessage }
|
||||
contentMap.setObjects(otherUserId, messages)
|
||||
sendToDeviceTask
|
||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap)) {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun createAccept(tid: String,
|
||||
keyAgreementProtocol: String,
|
||||
hash: String,
|
||||
|
Loading…
Reference in New Issue
Block a user