mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 19:05:56 +03:00
Fix QR code not always displayed
This commit is contained in:
parent
0c1e439313
commit
bed2c221e3
9 changed files with 473 additions and 256 deletions
|
@ -206,14 +206,14 @@ class VerificationTest : InstrumentedTest {
|
|||
|
||||
aliceReadyPendingVerificationRequest!!.let { pr ->
|
||||
pr.isSasSupported shouldBe expectedResultForAlice.sasIsSupported
|
||||
pr.otherCanShowQrCode shouldBe expectedResultForAlice.otherCanShowQrCode
|
||||
pr.otherCanScanQrCode shouldBe expectedResultForAlice.otherCanScanQrCode
|
||||
pr.weShouldShowScanOption shouldBe expectedResultForAlice.otherCanShowQrCode
|
||||
pr.weShouldDisplayQRCode shouldBe expectedResultForAlice.otherCanScanQrCode
|
||||
}
|
||||
|
||||
bobReadyPendingVerificationRequest!!.let { pr ->
|
||||
pr.isSasSupported shouldBe expectedResultForBob.sasIsSupported
|
||||
pr.otherCanShowQrCode shouldBe expectedResultForBob.otherCanShowQrCode
|
||||
pr.otherCanScanQrCode shouldBe expectedResultForBob.otherCanScanQrCode
|
||||
pr.weShouldShowScanOption shouldBe expectedResultForBob.otherCanShowQrCode
|
||||
pr.weShouldDisplayQRCode shouldBe expectedResultForBob.otherCanScanQrCode
|
||||
}
|
||||
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
|
|
|
@ -246,14 +246,14 @@ class VerificationTest : InstrumentedTest {
|
|||
|
||||
aliceReadyPendingVerificationRequest!!.let { pr ->
|
||||
pr.isSasSupported shouldBe expectedResultForAlice.sasIsSupported
|
||||
pr.otherCanShowQrCode shouldBe expectedResultForAlice.otherCanShowQrCode
|
||||
pr.otherCanScanQrCode shouldBe expectedResultForAlice.otherCanScanQrCode
|
||||
pr.weShouldShowScanOption shouldBe expectedResultForAlice.otherCanShowQrCode
|
||||
pr.weShouldDisplayQRCode shouldBe expectedResultForAlice.otherCanScanQrCode
|
||||
}
|
||||
|
||||
bobReadyPendingVerificationRequest!!.let { pr ->
|
||||
pr.isSasSupported shouldBe expectedResultForBob.sasIsSupported
|
||||
pr.otherCanShowQrCode shouldBe expectedResultForBob.otherCanShowQrCode
|
||||
pr.otherCanScanQrCode shouldBe expectedResultForBob.otherCanScanQrCode
|
||||
pr.weShouldShowScanOption shouldBe expectedResultForBob.otherCanShowQrCode
|
||||
pr.weShouldDisplayQRCode shouldBe expectedResultForBob.otherCanScanQrCode
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.crypto.verification
|
|||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.IVerificationRequest
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
|
||||
|
@ -35,7 +34,7 @@ internal class KotlinVerificationRequest(
|
|||
val otherUserId: String,
|
||||
var state: EVerificationState,
|
||||
val ageLocalTs: Long
|
||||
) : IVerificationRequest {
|
||||
) {
|
||||
|
||||
var roomId: String? = null
|
||||
var qrCodeData: QrCodeData? = null
|
||||
|
@ -44,21 +43,21 @@ internal class KotlinVerificationRequest(
|
|||
var readyInfo: ValidVerificationInfoReady? = null
|
||||
var cancelCode: CancelCode? = null
|
||||
|
||||
override fun requestId() = requestId
|
||||
// fun requestId() = requestId
|
||||
//
|
||||
// fun incoming() = incoming
|
||||
//
|
||||
// fun otherUserId() = otherUserId
|
||||
//
|
||||
// fun roomId() = roomId
|
||||
//
|
||||
// fun targetDevices() = targetDevices
|
||||
//
|
||||
// fun state() = state
|
||||
//
|
||||
// fun ageLocalTs() = ageLocalTs
|
||||
|
||||
override fun incoming() = incoming
|
||||
|
||||
override fun otherUserId() = otherUserId
|
||||
|
||||
override fun roomId() = roomId
|
||||
|
||||
override fun targetDevices() = targetDevices
|
||||
|
||||
override fun state() = state
|
||||
|
||||
override fun ageLocalTs() = ageLocalTs
|
||||
|
||||
override fun otherDeviceId(): String? {
|
||||
fun otherDeviceId(): String? {
|
||||
return if (incoming) {
|
||||
requestInfo?.fromDevice
|
||||
} else {
|
||||
|
@ -66,12 +65,12 @@ internal class KotlinVerificationRequest(
|
|||
}
|
||||
}
|
||||
|
||||
override fun cancelCode(): CancelCode? = cancelCode
|
||||
fun cancelCode(): CancelCode? = cancelCode
|
||||
|
||||
/**
|
||||
* SAS is supported if I support it and the other party support it.
|
||||
*/
|
||||
override fun isSasSupported(): Boolean {
|
||||
private fun isSasSupported(): Boolean {
|
||||
return requestInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse() &&
|
||||
readyInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse()
|
||||
}
|
||||
|
@ -79,7 +78,7 @@ internal class KotlinVerificationRequest(
|
|||
/**
|
||||
* Other can show QR code if I can scan QR code and other can show QR code.
|
||||
*/
|
||||
override fun otherCanShowQrCode(): Boolean {
|
||||
private fun otherCanShowQrCode(): Boolean {
|
||||
return if (incoming) {
|
||||
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse() &&
|
||||
readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
|
||||
|
@ -92,7 +91,7 @@ internal class KotlinVerificationRequest(
|
|||
/**
|
||||
* Other can scan QR code if I can show QR code and other can scan QR code.
|
||||
*/
|
||||
override fun otherCanScanQrCode(): Boolean {
|
||||
private fun otherCanScanQrCode(): Boolean {
|
||||
return if (incoming) {
|
||||
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse() &&
|
||||
readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
|
||||
|
@ -102,7 +101,7 @@ internal class KotlinVerificationRequest(
|
|||
}
|
||||
}
|
||||
|
||||
override fun qrCodeText() = qrCodeData?.toEncodedString()
|
||||
fun qrCodeText() = qrCodeData?.toEncodedString()
|
||||
|
||||
override fun toString(): String {
|
||||
return toPendingVerificationRequest().toString()
|
||||
|
@ -122,9 +121,11 @@ internal class KotlinVerificationRequest(
|
|||
targetDevices = targetDevices,
|
||||
qrCodeText = qrCodeText(),
|
||||
isSasSupported = isSasSupported(),
|
||||
otherCanShowQrCode = otherCanShowQrCode(),
|
||||
otherCanScanQrCode = otherCanScanQrCode(),
|
||||
weShouldShowScanOption = otherCanShowQrCode(),
|
||||
weShouldDisplayQRCode = otherCanScanQrCode(),
|
||||
otherDeviceId = otherDeviceId()
|
||||
)
|
||||
}
|
||||
|
||||
fun isFinished() = state == EVerificationState.Cancelled || state == EVerificationState.Done
|
||||
}
|
||||
|
|
|
@ -130,8 +130,8 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
*/
|
||||
private val pendingRequests = HashMap<String, MutableList<KotlinVerificationRequest>>()
|
||||
|
||||
// Replaces the typical list of listeners pattern. Looks to me as the sane setup, not sure if more than 1 is needed as extraBufferCapacity
|
||||
// We don't want to use emit as it would block if no listener is subscribed
|
||||
// Replaces the typical list of listeners pattern.
|
||||
// Looks to me as the sane setup, not sure if more than 1 is needed as extraBufferCapacity
|
||||
// So we should use try emit using extraBufferCapacity, we use drop_oldest instead of suspend.
|
||||
val eventFlow = MutableSharedFlow<VerificationEvent>(extraBufferCapacity = 4, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
|
||||
|
@ -214,7 +214,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
.v("[${myUserId.take(8)}]: $msg")
|
||||
when (msg) {
|
||||
is VerificationIntent.ActionRequestVerification -> {
|
||||
handleRequestAdd(msg)
|
||||
handleActionRequestVerification(msg)
|
||||
}
|
||||
is VerificationIntent.OnReadyReceived -> {
|
||||
handleReadyReceived(msg)
|
||||
|
@ -1046,7 +1046,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
existing.state = SasTransactionState.Done(true)
|
||||
dispatchUpdate(VerificationEvent.TransactionUpdated(existing))
|
||||
// we can forget about it
|
||||
txMap[matchingRequest.otherUserId()]?.remove(matchingRequest.requestId)
|
||||
txMap[matchingRequest.otherUserId]?.remove(matchingRequest.requestId)
|
||||
// XXX whatabout waiting for done?
|
||||
matchingRequest.state = EVerificationState.Done
|
||||
dispatchUpdate(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||
|
@ -1137,7 +1137,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
existing.state = QRCodeVerificationState.Done
|
||||
dispatchUpdate(VerificationEvent.TransactionUpdated(existing))
|
||||
// we can forget about it
|
||||
txMap[matchingRequest.otherUserId()]?.remove(matchingRequest.requestId)
|
||||
txMap[matchingRequest.otherUserId]?.remove(matchingRequest.requestId)
|
||||
matchingRequest.state = EVerificationState.WaitingForDone
|
||||
dispatchUpdate(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||
|
||||
|
@ -1309,6 +1309,11 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
if (commonMethods.isEmpty()) {
|
||||
Timber.tag(loggerTag.value).v("Request ${msg.transactionId} no common methods")
|
||||
cancelRequest(existing, CancelCode.UnknownMethod)
|
||||
// Upon receipt of Alice’s m.key.verification.request message, if Bob’s device does not understand any of the methods,
|
||||
// it should not cancel the request as one of his other devices may support the request.
|
||||
|
||||
// XXX How to o that??
|
||||
// Instead, Bob’s device should tell Bob that no supported method was found, and allow him to manually reject the request.
|
||||
msg.deferred.complete(null)
|
||||
return
|
||||
}
|
||||
|
@ -1367,7 +1372,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
|
||||
private fun getMethodAgreement(
|
||||
otherUserMethods: List<String>?,
|
||||
methods: List<VerificationMethod>,
|
||||
myMethods: List<VerificationMethod>,
|
||||
): List<String> {
|
||||
if (otherUserMethods.isNullOrEmpty()) {
|
||||
return emptyList()
|
||||
|
@ -1375,18 +1380,18 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
|
||||
val result = mutableSetOf<String>()
|
||||
|
||||
if (VERIFICATION_METHOD_SAS in otherUserMethods && VerificationMethod.SAS in methods) {
|
||||
if (VERIFICATION_METHOD_SAS in otherUserMethods && VerificationMethod.SAS in myMethods) {
|
||||
// Other can do SAS and so do I
|
||||
result.add(VERIFICATION_METHOD_SAS)
|
||||
}
|
||||
|
||||
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods || VERIFICATION_METHOD_QR_CODE_SHOW in otherUserMethods) {
|
||||
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods && VerificationMethod.QR_CODE_SHOW in methods) {
|
||||
if (VERIFICATION_METHOD_RECIPROCATE in otherUserMethods) {
|
||||
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods && VerificationMethod.QR_CODE_SHOW in myMethods) {
|
||||
// Other can Scan and I can show QR code
|
||||
result.add(VERIFICATION_METHOD_QR_CODE_SHOW)
|
||||
result.add(VERIFICATION_METHOD_RECIPROCATE)
|
||||
}
|
||||
if (VERIFICATION_METHOD_QR_CODE_SHOW in otherUserMethods && VerificationMethod.QR_CODE_SCAN in methods) {
|
||||
if (VERIFICATION_METHOD_QR_CODE_SHOW in otherUserMethods && VerificationMethod.QR_CODE_SCAN in myMethods) {
|
||||
// Other can show and I can scan QR code
|
||||
result.add(VERIFICATION_METHOD_QR_CODE_SCAN)
|
||||
result.add(VERIFICATION_METHOD_RECIPROCATE)
|
||||
|
@ -1400,7 +1405,11 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
return contains(VERIFICATION_METHOD_QR_CODE_SCAN) && contains(VERIFICATION_METHOD_RECIPROCATE)
|
||||
}
|
||||
|
||||
private suspend fun handleRequestAdd(msg: VerificationIntent.ActionRequestVerification) {
|
||||
private fun List<String>.canShowCode(): Boolean {
|
||||
return contains(VERIFICATION_METHOD_QR_CODE_SHOW) && contains(VERIFICATION_METHOD_RECIPROCATE)
|
||||
}
|
||||
|
||||
private suspend fun handleActionRequestVerification(msg: VerificationIntent.ActionRequestVerification) {
|
||||
val requestsForUser = pendingRequests.getOrPut(msg.otherUserId) { mutableListOf() }
|
||||
// there can only be one active request per user, so cancel existing ones
|
||||
requestsForUser.toList().forEach { existingRequest ->
|
||||
|
@ -1410,8 +1419,6 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val validLocalId = LocalEcho.createLocalEchoId()
|
||||
|
||||
val methodValues = if (cryptoStore.getMyCrossSigningInfo()?.isTrusted().orFalse()) {
|
||||
// Add reciprocate method if application declares it can scan or show QR codes
|
||||
// Not sure if it ok to do that (?)
|
||||
|
@ -1521,6 +1528,10 @@ internal class VerificationActor @AssistedInject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
if (matchingRequest.requestInfo?.methods?.canShowCode().orFalse() &&
|
||||
msg.readyInfo.methods.canScanCode()) {
|
||||
matchingRequest.qrCodeData = createQrCodeData(matchingRequest.requestId, msg.fromUser, msg.readyInfo.fromDevice)
|
||||
}
|
||||
matchingRequest.readyInfo = msg.readyInfo
|
||||
matchingRequest.state = EVerificationState.Ready
|
||||
dispatchUpdate(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -32,31 +32,3 @@ enum class EVerificationState {
|
|||
Cancelled,
|
||||
HandledByOtherSession
|
||||
}
|
||||
|
||||
// TODO remove that
|
||||
interface IVerificationRequest {
|
||||
|
||||
fun requestId(): String
|
||||
|
||||
fun incoming(): Boolean
|
||||
fun otherUserId(): String
|
||||
fun roomId(): String?
|
||||
|
||||
// target devices in case of to_device self verification
|
||||
fun targetDevices(): List<String>?
|
||||
|
||||
fun state(): EVerificationState
|
||||
fun ageLocalTs(): Long
|
||||
|
||||
fun isSasSupported(): Boolean
|
||||
fun otherCanShowQrCode(): Boolean
|
||||
fun otherCanScanQrCode(): Boolean
|
||||
|
||||
fun otherDeviceId(): String?
|
||||
|
||||
fun qrCodeText(): String?
|
||||
|
||||
fun isFinished(): Boolean = state() == EVerificationState.Cancelled || state() == EVerificationState.Done
|
||||
|
||||
fun cancelCode(): CancelCode?
|
||||
}
|
|
@ -38,11 +38,10 @@ data class PendingVerificationRequest(
|
|||
// if available store here the qr code to show
|
||||
val qrCodeText: String? = null,
|
||||
val isSasSupported: Boolean = false,
|
||||
val otherCanShowQrCode: Boolean = false,
|
||||
val otherCanScanQrCode: Boolean = false,
|
||||
val weShouldShowScanOption: Boolean = false,
|
||||
val weShouldDisplayQRCode: Boolean = false,
|
||||
|
||||
) {
|
||||
// val isReady: Boolean = readyInfo != null
|
||||
//
|
||||
// val isFinished: Boolean = isSuccessful || cancelConclusion != null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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 org.matrix.android.sdk.internal.crypto.verification
|
||||
|
||||
import dagger.Lazy
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationReadyContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||
import org.matrix.android.sdk.internal.crypto.SecretShareManager
|
||||
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import java.util.UUID
|
||||
|
||||
internal class VerificationActorHelper {
|
||||
|
||||
data class TestData(
|
||||
val aliceActor: VerificationActor,
|
||||
val bobActor: VerificationActor,
|
||||
)
|
||||
|
||||
val actorAScope = CoroutineScope(SupervisorJob())
|
||||
val actorBScope = CoroutineScope(SupervisorJob())
|
||||
val transportScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
var bobChannel: SendChannel<VerificationIntent>? = null
|
||||
var aliceChannel: SendChannel<VerificationIntent>? = null
|
||||
|
||||
fun setUpActors(): TestData {
|
||||
val aliceTransportLayer = mockTransportTo(FakeCryptoStoreForVerification.aliceMxId) { bobChannel }
|
||||
val bobTransportLayer = mockTransportTo(FakeCryptoStoreForVerification.bobMxId) { aliceChannel }
|
||||
|
||||
val aliceActor = fakeActor(
|
||||
actorAScope,
|
||||
FakeCryptoStoreForVerification.aliceMxId,
|
||||
FakeCryptoStoreForVerification(StoreMode.Alice).instance,
|
||||
aliceTransportLayer,
|
||||
mockk<Lazy<CrossSigningService>> {
|
||||
every {
|
||||
get()
|
||||
} returns mockk<CrossSigningService>(relaxed = true)
|
||||
}
|
||||
)
|
||||
aliceChannel = aliceActor.channel
|
||||
|
||||
val bobActor = fakeActor(
|
||||
actorBScope,
|
||||
FakeCryptoStoreForVerification.aliceMxId,
|
||||
FakeCryptoStoreForVerification(StoreMode.Alice).instance,
|
||||
bobTransportLayer,
|
||||
mockk<Lazy<CrossSigningService>> {
|
||||
every {
|
||||
get()
|
||||
} returns mockk<CrossSigningService>(relaxed = true)
|
||||
}
|
||||
)
|
||||
bobChannel = bobActor.channel
|
||||
|
||||
return TestData(
|
||||
aliceActor,
|
||||
bobActor
|
||||
)
|
||||
}
|
||||
|
||||
private fun mockTransportTo(fromUser: String, otherChannel: (() -> SendChannel<VerificationIntent>?)): VerificationTransportLayer {
|
||||
return mockk<VerificationTransportLayer> {
|
||||
coEvery { sendToOther(any(), any(), any()) } answers {
|
||||
val request = firstArg<KotlinVerificationRequest>()
|
||||
val type = secondArg<String>()
|
||||
val info = thirdArg<VerificationInfo<*>>()
|
||||
|
||||
transportScope.launch(Dispatchers.IO) {
|
||||
when (type) {
|
||||
EventType.KEY_VERIFICATION_READY -> {
|
||||
val readyContent = info.asValidObject()
|
||||
otherChannel()?.send(
|
||||
VerificationIntent.OnReadyReceived(
|
||||
transactionId = request.requestId,
|
||||
fromUser = fromUser,
|
||||
viaRoom = request.roomId,
|
||||
readyInfo = readyContent as ValidVerificationInfoReady,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
coEvery { sendInRoom(any(), any(), any(), any()) } answers {
|
||||
val type = secondArg<String>()
|
||||
val roomId = thirdArg<String>()
|
||||
val content = arg<Content>(3)
|
||||
|
||||
val fakeEventId = UUID.randomUUID().toString()
|
||||
transportScope.launch(Dispatchers.IO) {
|
||||
when (type) {
|
||||
EventType.MESSAGE -> {
|
||||
val requestContent = content.toModel<MessageVerificationRequestContent>()?.copy(
|
||||
transactionId = fakeEventId
|
||||
)?.asValidObject()
|
||||
otherChannel()?.send(
|
||||
VerificationIntent.OnVerificationRequestReceived(
|
||||
requestContent!!,
|
||||
senderId = FakeCryptoStoreForVerification.aliceMxId,
|
||||
roomId = roomId,
|
||||
timeStamp = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
EventType.KEY_VERIFICATION_READY -> {
|
||||
val readyContent = content.toModel<MessageVerificationReadyContent>()
|
||||
?.asValidObject()
|
||||
otherChannel()?.send(
|
||||
VerificationIntent.OnReadyReceived(
|
||||
transactionId = readyContent!!.transactionId,
|
||||
fromUser = fromUser,
|
||||
viaRoom = roomId,
|
||||
readyInfo = readyContent,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
fakeEventId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fakeActor(
|
||||
scope: CoroutineScope,
|
||||
userId: String,
|
||||
cryptoStore: IMXCryptoStore,
|
||||
transportLayer: VerificationTransportLayer,
|
||||
crossSigningService: dagger.Lazy<CrossSigningService>,
|
||||
): VerificationActor {
|
||||
return VerificationActor(
|
||||
scope,
|
||||
// channel = channel,
|
||||
clock = mockk<Clock> {
|
||||
every { epochMillis() } returns System.currentTimeMillis()
|
||||
},
|
||||
myUserId = userId,
|
||||
cryptoStore = cryptoStore,
|
||||
secretShareManager = mockk<SecretShareManager> {},
|
||||
transportLayer = transportLayer,
|
||||
crossSigningService = crossSigningService,
|
||||
setDeviceVerificationAction = SetDeviceVerificationAction(
|
||||
cryptoStore = cryptoStore,
|
||||
userId = userId,
|
||||
defaultKeysBackupService = mockk {
|
||||
coEvery { checkAndStartKeysBackup() } coAnswers { }
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -17,9 +17,7 @@
|
|||
package org.matrix.android.sdk.internal.crypto.verification.org.matrix.android.sdk.internal.crypto.verification
|
||||
|
||||
import android.util.Base64
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -27,44 +25,32 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.amshove.kluent.fail
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.amshove.kluent.internal.assertNotEquals
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.amshove.kluent.shouldNotBe
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.IVerificationRequest
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationReadyContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||
import org.matrix.android.sdk.internal.crypto.SecretShareManager
|
||||
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.verification.FakeCryptoStoreForVerification
|
||||
import org.matrix.android.sdk.internal.crypto.verification.StoreMode
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationActor
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationInfo
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationActorHelper
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationIntent
|
||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationTransportLayer
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import java.util.UUID
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class VerificationActorTest {
|
||||
|
||||
val transportScope = CoroutineScope(SupervisorJob())
|
||||
val actorAScope = CoroutineScope(SupervisorJob())
|
||||
val actorBScope = CoroutineScope(SupervisorJob())
|
||||
// val actorAScope = CoroutineScope(SupervisorJob())
|
||||
// val actorBScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
|
@ -86,38 +72,10 @@ class VerificationActorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `Request and accept`() = runTest {
|
||||
var bobChannel: SendChannel<VerificationIntent>? = null
|
||||
var aliceChannel: SendChannel<VerificationIntent>? = null
|
||||
|
||||
val aliceTransportLayer = mockTransportTo(FakeCryptoStoreForVerification.aliceMxId) { bobChannel }
|
||||
val bobTransportLayer = mockTransportTo(FakeCryptoStoreForVerification.bobMxId) { aliceChannel }
|
||||
|
||||
val aliceActor = fakeActor(
|
||||
actorAScope,
|
||||
FakeCryptoStoreForVerification.aliceMxId,
|
||||
FakeCryptoStoreForVerification(StoreMode.Alice).instance,
|
||||
aliceTransportLayer,
|
||||
mockk<dagger.Lazy<CrossSigningService>> {
|
||||
every {
|
||||
get()
|
||||
} returns mockk<CrossSigningService>(relaxed = true)
|
||||
}
|
||||
)
|
||||
aliceChannel = aliceActor.channel
|
||||
|
||||
val bobActor = fakeActor(
|
||||
actorBScope,
|
||||
FakeCryptoStoreForVerification.aliceMxId,
|
||||
FakeCryptoStoreForVerification(StoreMode.Alice).instance,
|
||||
bobTransportLayer,
|
||||
mockk<dagger.Lazy<CrossSigningService>> {
|
||||
every {
|
||||
get()
|
||||
} returns mockk<CrossSigningService>(relaxed = true)
|
||||
}
|
||||
)
|
||||
bobChannel = bobActor.channel
|
||||
fun `If ready both side should support sas and Qr show and scan`() = runTest {
|
||||
val testData = VerificationActorHelper().setUpActors()
|
||||
val aliceActor = testData.aliceActor
|
||||
val bobActor = testData.bobActor
|
||||
|
||||
val completableDeferred = CompletableDeferred<PendingVerificationRequest>()
|
||||
|
||||
|
@ -130,23 +88,14 @@ class VerificationActorTest {
|
|||
}
|
||||
}
|
||||
|
||||
awaitDeferrable<PendingVerificationRequest> {
|
||||
aliceActor.send(
|
||||
VerificationIntent.ActionRequestVerification(
|
||||
otherUserId = FakeCryptoStoreForVerification.bobMxId,
|
||||
roomId = "aRoom",
|
||||
methods = listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SHOW, VerificationMethod.QR_CODE_SCAN),
|
||||
deferred = it
|
||||
)
|
||||
)
|
||||
}
|
||||
aliceActor.requestVerification(listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SHOW, VerificationMethod.QR_CODE_SCAN))
|
||||
|
||||
val bobIncomingRequest = completableDeferred.await()
|
||||
bobIncomingRequest.state shouldBeEqualTo EVerificationState.Requested
|
||||
|
||||
val aliceReadied = CompletableDeferred<PendingVerificationRequest>()
|
||||
|
||||
val theJob = transportScope.launch {
|
||||
transportScope.launch {
|
||||
aliceActor.eventFlow.collect {
|
||||
if (it is VerificationEvent.RequestUpdated && it.request.state == EVerificationState.Ready) {
|
||||
aliceReadied.complete(it.request)
|
||||
|
@ -156,7 +105,7 @@ class VerificationActorTest {
|
|||
}
|
||||
|
||||
// test ready
|
||||
awaitDeferrable<PendingVerificationRequest?> {
|
||||
val bobReadied = awaitDeferrable<PendingVerificationRequest?> {
|
||||
bobActor.send(
|
||||
VerificationIntent.ActionReadyRequest(
|
||||
bobIncomingRequest.transactionId,
|
||||
|
@ -168,11 +117,143 @@ class VerificationActorTest {
|
|||
|
||||
val readiedAliceSide = aliceReadied.await()
|
||||
|
||||
println("transporte scope active? ${transportScope.isActive}")
|
||||
println("the job? ${theJob.isActive}")
|
||||
|
||||
readiedAliceSide.isSasSupported shouldBeEqualTo true
|
||||
readiedAliceSide.otherCanScanQrCode shouldBeEqualTo true
|
||||
readiedAliceSide.weShouldDisplayQRCode shouldBeEqualTo true
|
||||
|
||||
bobReadied shouldNotBe null
|
||||
bobReadied!!.isSasSupported shouldBeEqualTo true
|
||||
bobReadied.weShouldDisplayQRCode shouldBeEqualTo true
|
||||
|
||||
bobReadied.qrCodeText shouldNotBe null
|
||||
readiedAliceSide.qrCodeText shouldNotBe null
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test alice can show but not scan QR`() = runTest {
|
||||
val testData = VerificationActorHelper().setUpActors()
|
||||
val aliceActor = testData.aliceActor
|
||||
val bobActor = testData.bobActor
|
||||
|
||||
println("Alice sends a request")
|
||||
val outgoingRequest = aliceActor.requestVerification(
|
||||
listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SHOW)
|
||||
)
|
||||
|
||||
// wait for bob to get it
|
||||
println("Wait for bob to get it")
|
||||
waitForBobToSeeIncomingRequest(bobActor, outgoingRequest)
|
||||
|
||||
println("let bob ready it")
|
||||
val bobReady = bobActor.readyVerification(
|
||||
outgoingRequest.transactionId,
|
||||
listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW)
|
||||
)
|
||||
|
||||
println("Wait for alice to get the ready")
|
||||
retryUntil {
|
||||
awaitDeferrable<PendingVerificationRequest?> {
|
||||
aliceActor.send(VerificationIntent.GetExistingRequest(outgoingRequest.transactionId, outgoingRequest.otherUserId, it))
|
||||
}?.state == EVerificationState.Ready
|
||||
}
|
||||
|
||||
val aliceReady = awaitDeferrable<PendingVerificationRequest?> {
|
||||
aliceActor.send(VerificationIntent.GetExistingRequest(outgoingRequest.transactionId, outgoingRequest.otherUserId, it))
|
||||
}!!
|
||||
|
||||
aliceReady.isSasSupported shouldBeEqualTo bobReady.isSasSupported
|
||||
|
||||
// alice can't scan so there should not be option to do so
|
||||
assertEquals("Alice should not show scan option", false, aliceReady.weShouldShowScanOption)
|
||||
assertEquals("Alice should show QR as bob can scan", true, aliceReady.weShouldDisplayQRCode)
|
||||
|
||||
assertEquals("Bob should be able to scan", true, bobReady.weShouldShowScanOption)
|
||||
assertEquals("Bob should not show QR as alice can scan", false, bobReady.weShouldDisplayQRCode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test bob can show but not scan QR`() = runTest {
|
||||
val testData = VerificationActorHelper().setUpActors()
|
||||
val aliceActor = testData.aliceActor
|
||||
val bobActor = testData.bobActor
|
||||
|
||||
println("Alice sends a request")
|
||||
val outgoingRequest = aliceActor.requestVerification(
|
||||
listOf(VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW)
|
||||
)
|
||||
|
||||
// wait for bob to get it
|
||||
println("Wait for bob to get it")
|
||||
waitForBobToSeeIncomingRequest(bobActor, outgoingRequest)
|
||||
|
||||
println("let bob ready it")
|
||||
val bobReady = bobActor.readyVerification(
|
||||
outgoingRequest.transactionId,
|
||||
listOf(VerificationMethod.QR_CODE_SHOW)
|
||||
)
|
||||
|
||||
println("Wait for alice to get the ready")
|
||||
retryUntil {
|
||||
awaitDeferrable<PendingVerificationRequest?> {
|
||||
aliceActor.send(VerificationIntent.GetExistingRequest(outgoingRequest.transactionId, outgoingRequest.otherUserId, it))
|
||||
}?.state == EVerificationState.Ready
|
||||
}
|
||||
|
||||
val aliceReady = awaitDeferrable<PendingVerificationRequest?> {
|
||||
aliceActor.send(VerificationIntent.GetExistingRequest(outgoingRequest.transactionId, outgoingRequest.otherUserId, it))
|
||||
}!!
|
||||
|
||||
assertEquals("Alice sas is not supported", false, aliceReady.isSasSupported)
|
||||
aliceReady.isSasSupported shouldBeEqualTo bobReady.isSasSupported
|
||||
|
||||
// alice can't scan so there should not be option to do so
|
||||
assertEquals("Alice should show scan option", true, aliceReady.weShouldShowScanOption)
|
||||
assertEquals("Alice QR data should be null", null, aliceReady.qrCodeText)
|
||||
assertEquals("Alice should not show QR as bob can scan", false, aliceReady.weShouldDisplayQRCode)
|
||||
|
||||
assertEquals("Bob should not should not show cam option as it can't scan", false, bobReady.weShouldShowScanOption)
|
||||
assertNotEquals("Bob QR data should be there", null, bobReady.qrCodeText)
|
||||
assertEquals("Bob should show QR as alice can scan", true, bobReady.weShouldDisplayQRCode)
|
||||
}
|
||||
|
||||
private suspend fun VerificationActor.requestVerification(methods: List<VerificationMethod>): PendingVerificationRequest {
|
||||
return awaitDeferrable<PendingVerificationRequest> {
|
||||
send(
|
||||
VerificationIntent.ActionRequestVerification(
|
||||
otherUserId = FakeCryptoStoreForVerification.bobMxId,
|
||||
roomId = "aRoom",
|
||||
methods = methods,
|
||||
deferred = it
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun waitForBobToSeeIncomingRequest(bobActor: VerificationActor, aliceOutgoing: PendingVerificationRequest) {
|
||||
retryUntil {
|
||||
awaitDeferrable<PendingVerificationRequest?> {
|
||||
bobActor.send(
|
||||
VerificationIntent.GetExistingRequest(
|
||||
aliceOutgoing.transactionId,
|
||||
FakeCryptoStoreForVerification.aliceMxId, it
|
||||
)
|
||||
)
|
||||
}?.state == EVerificationState.Requested
|
||||
}
|
||||
}
|
||||
|
||||
private val backoff = listOf(500L, 1_000L, 1_000L, 3_000L, 3_000L, 5_000L)
|
||||
|
||||
private suspend fun retryUntil(condition: suspend (() -> Boolean)) {
|
||||
var tryCount = 0
|
||||
while (!condition()) {
|
||||
if (tryCount >= backoff.size) {
|
||||
fail("Retry Until Fialed")
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
delay(backoff[tryCount])
|
||||
}
|
||||
tryCount++
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T> awaitDeferrable(block: suspend ((CompletableDeferred<T>) -> Unit)): T {
|
||||
|
@ -181,113 +262,85 @@ class VerificationActorTest {
|
|||
return deferred.await()
|
||||
}
|
||||
|
||||
private fun mockTransportTo(fromUser: String, otherChannel: (() -> SendChannel<VerificationIntent>?)): VerificationTransportLayer {
|
||||
return mockk<VerificationTransportLayer> {
|
||||
coEvery { sendToOther(any(), any(), any()) } answers {
|
||||
val request = firstArg<IVerificationRequest>()
|
||||
val type = secondArg<String>()
|
||||
val info = thirdArg<VerificationInfo<*>>()
|
||||
|
||||
transportScope.launch(Dispatchers.IO) {
|
||||
when (type) {
|
||||
EventType.KEY_VERIFICATION_READY -> {
|
||||
val readyContent = info.asValidObject()
|
||||
otherChannel()?.send(
|
||||
VerificationIntent.OnReadyReceived(
|
||||
transactionId = request.requestId(),
|
||||
fromUser = fromUser,
|
||||
viaRoom = request.roomId(),
|
||||
readyInfo = readyContent as ValidVerificationInfoReady,
|
||||
private suspend fun VerificationActor.readyVerification(transactionId: String, methods: List<VerificationMethod>): PendingVerificationRequest {
|
||||
return awaitDeferrable<PendingVerificationRequest?> {
|
||||
send(
|
||||
VerificationIntent.ActionReadyRequest(
|
||||
transactionId,
|
||||
methods = methods,
|
||||
it
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
coEvery { sendInRoom(any(), any(), any(), any()) } answers {
|
||||
val type = secondArg<String>()
|
||||
val roomId = thirdArg<String>()
|
||||
val content = arg<Content>(3)
|
||||
|
||||
val fakeEventId = UUID.randomUUID().toString()
|
||||
transportScope.launch(Dispatchers.IO) {
|
||||
when (type) {
|
||||
EventType.MESSAGE -> {
|
||||
val requestContent = content.toModel<MessageVerificationRequestContent>()?.copy(
|
||||
transactionId = fakeEventId
|
||||
)?.asValidObject()
|
||||
otherChannel()?.send(
|
||||
VerificationIntent.OnVerificationRequestReceived(
|
||||
requestContent!!,
|
||||
senderId = FakeCryptoStoreForVerification.aliceMxId,
|
||||
roomId = roomId,
|
||||
timeStamp = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
EventType.KEY_VERIFICATION_READY -> {
|
||||
val readyContent = content.toModel<MessageVerificationReadyContent>()
|
||||
?.asValidObject()
|
||||
otherChannel()?.send(
|
||||
VerificationIntent.OnReadyReceived(
|
||||
transactionId = readyContent!!.transactionId,
|
||||
fromUser = fromUser,
|
||||
viaRoom = roomId,
|
||||
readyInfo = readyContent,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
fakeEventId
|
||||
}
|
||||
}
|
||||
}!!
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Every testing`() {
|
||||
val mockStore = mockk<IMXCryptoStore>()
|
||||
every { mockStore.getDeviceId() } returns "A"
|
||||
println("every ${mockStore.getDeviceId()}")
|
||||
every { mockStore.getDeviceId() } returns "B"
|
||||
println("every ${mockStore.getDeviceId()}")
|
||||
// @Test
|
||||
// fun `Every testing`() {
|
||||
// val mockStore = mockk<IMXCryptoStore>()
|
||||
// every { mockStore.getDeviceId() } returns "A"
|
||||
// println("every ${mockStore.getDeviceId()}")
|
||||
// every { mockStore.getDeviceId() } returns "B"
|
||||
// println("every ${mockStore.getDeviceId()}")
|
||||
//
|
||||
// every { mockStore.getDeviceId() } returns "A"
|
||||
// every { mockStore.getDeviceId() } returns "B"
|
||||
// println("every ${mockStore.getDeviceId()}")
|
||||
//
|
||||
// every { mockStore.getCrossSigningInfo(any()) } returns null
|
||||
// every { mockStore.getCrossSigningInfo("alice") } returns MXCrossSigningInfo("alice", emptyList(), false)
|
||||
//
|
||||
// println("XS ${mockStore.getCrossSigningInfo("alice")}")
|
||||
// println("XS ${mockStore.getCrossSigningInfo("bob")}")
|
||||
// }
|
||||
|
||||
every { mockStore.getDeviceId() } returns "A"
|
||||
every { mockStore.getDeviceId() } returns "B"
|
||||
println("every ${mockStore.getDeviceId()}")
|
||||
|
||||
every { mockStore.getCrossSigningInfo(any()) } returns null
|
||||
every { mockStore.getCrossSigningInfo("alice") } returns MXCrossSigningInfo("alice", emptyList(), false)
|
||||
|
||||
println("XS ${mockStore.getCrossSigningInfo("alice")}")
|
||||
println("XS ${mockStore.getCrossSigningInfo("bob")}")
|
||||
}
|
||||
|
||||
private fun fakeActor(
|
||||
scope: CoroutineScope,
|
||||
userId: String,
|
||||
cryptoStore: IMXCryptoStore,
|
||||
transportLayer: VerificationTransportLayer,
|
||||
crossSigningService: dagger.Lazy<CrossSigningService>,
|
||||
): VerificationActor {
|
||||
return VerificationActor(
|
||||
scope,
|
||||
// channel = channel,
|
||||
clock = mockk<Clock> {
|
||||
every { epochMillis() } returns System.currentTimeMillis()
|
||||
},
|
||||
myUserId = userId,
|
||||
cryptoStore = cryptoStore,
|
||||
secretShareManager = mockk<SecretShareManager> {},
|
||||
transportLayer = transportLayer,
|
||||
crossSigningService = crossSigningService,
|
||||
setDeviceVerificationAction = SetDeviceVerificationAction(
|
||||
cryptoStore = cryptoStore,
|
||||
userId = userId,
|
||||
defaultKeysBackupService = mockk {
|
||||
coEvery { checkAndStartKeysBackup() } coAnswers { }
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
// @Test
|
||||
// fun `Basic channel test`() {
|
||||
// // val sharedFlow = MutableSharedFlow<Int>(replay = 0, extraBufferCapacity = 2, BufferOverflow.DROP_OLDEST)
|
||||
// val sharedFlow = MutableSharedFlow<Int>(replay = 0)//, extraBufferCapacity = 0, BufferOverflow.DROP_OLDEST)
|
||||
//
|
||||
// val scope = CoroutineScope(SupervisorJob())
|
||||
// val deferred = CompletableDeferred<Unit>()
|
||||
// val listener = scope.launch {
|
||||
// sharedFlow.onEach {
|
||||
// println("L1 : Just collected $it")
|
||||
// delay(1000)
|
||||
// println("L1 : Just processed $it")
|
||||
// if (it == 2) {
|
||||
// deferred.complete(Unit)
|
||||
// }
|
||||
// }.launchIn(scope)
|
||||
// }
|
||||
//
|
||||
// // scope.launch {
|
||||
// // delay(700)
|
||||
// println("Pre Emit 1")
|
||||
// sharedFlow.tryEmit(1)
|
||||
// println("Emited 1")
|
||||
// sharedFlow.tryEmit(2)
|
||||
// println("Emited 2")
|
||||
// // }
|
||||
//
|
||||
// // runBlocking {
|
||||
// // deferred.await()
|
||||
// // }
|
||||
//
|
||||
// sharedFlow.onEach {
|
||||
// println("L2: Just collected $it")
|
||||
// delay(1000)
|
||||
// println("L2: Just processed $it")
|
||||
// }.launchIn(scope)
|
||||
//
|
||||
//
|
||||
// runBlocking {
|
||||
// deferred.await()
|
||||
// }
|
||||
//
|
||||
// val now = System.currentTimeMillis()
|
||||
// println("Just give some time for execution")
|
||||
// val job = scope.launch { delay(10_000) }
|
||||
// runBlocking {
|
||||
// job.join()
|
||||
// }
|
||||
// println("enough ${System.currentTimeMillis() - now}")
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ class UserVerificationController @Inject constructor(
|
|||
notice(scanCodeInstructions.toEpoxyCharSequence())
|
||||
}
|
||||
|
||||
if (request.otherCanScanQrCode && !request.qrCodeText.isNullOrEmpty()) {
|
||||
if (request.weShouldDisplayQRCode && !request.qrCodeText.isNullOrEmpty()) {
|
||||
bottomSheetVerificationQrCodeItem {
|
||||
id("qr")
|
||||
data(request.qrCodeText!!)
|
||||
|
@ -198,7 +198,7 @@ class UserVerificationController @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
if (request.otherCanShowQrCode) {
|
||||
if (request.weShouldShowScanOption) {
|
||||
bottomSheetVerificationActionItem {
|
||||
id("openCamera")
|
||||
title(scanOtherCodeTitle)
|
||||
|
|
Loading…
Reference in a new issue