Convert VerificationTxState to a sealed class

This commit is contained in:
Benoit Marty 2020-01-29 12:00:49 +01:00
parent 1d84ccd64a
commit 80ec199135
12 changed files with 171 additions and 174 deletions

View file

@ -20,13 +20,13 @@ interface VerificationTransaction {
var state: VerificationTxState
val cancelledReason: CancelCode?
val transactionId: String
val otherUserId: String
var otherDeviceId: String?
// TODO Not used. Remove?
val isIncoming: Boolean
/**
* User wants to cancel the transaction
*/

View file

@ -16,36 +16,36 @@
package im.vector.matrix.android.api.session.crypto.sas
enum class VerificationTxState {
None,
// I have started a verification request
SendingStart,
Started,
// Other user/device sent me a request
OnStarted,
// I have accepted a request started by the other user/device
SendingAccept,
Accepted,
// My request has been accepted by the other user/device
OnAccepted,
// I have sent my public key
SendingKey,
KeySent,
// The other user/device has sent me his public key
OnKeyReceived,
// Short code is ready to be displayed
ShortCodeReady,
// I have compared the code and manually said that they match
ShortCodeAccepted,
sealed class VerificationTxState {
// Uninitialized state
object None : VerificationTxState()
SendingMac,
MacSent,
Verifying,
Verified,
// Specific for SAS
abstract class VerificationSasTxState : VerificationTxState()
// Global: The verification has been cancelled (by me or other), see cancelReason for details
// When I do the cancel
Cancelled,
// When the other user do a cancel
OnCancelled
object SendingStart : VerificationSasTxState()
object Started : VerificationSasTxState()
object OnStarted : VerificationSasTxState()
object SendingAccept : VerificationSasTxState()
object Accepted : VerificationSasTxState()
object OnAccepted : VerificationSasTxState()
object SendingKey : VerificationSasTxState()
object KeySent : VerificationSasTxState()
object OnKeyReceived : VerificationSasTxState()
object ShortCodeReady : VerificationSasTxState()
object ShortCodeAccepted : VerificationSasTxState()
object SendingMac : VerificationSasTxState()
object MacSent : VerificationSasTxState()
object Verifying : VerificationSasTxState()
// Specific for QR code
// TODO Add code for the confirmation step for the user who has been scanned
// Terminal states
abstract class TerminalTxState : VerificationTxState()
object Verified : TerminalTxState()
// Cancelled by me or by other
data class Cancelled(val cancelCode: CancelCode, val byMe: Boolean) : TerminalTxState()
}

View file

@ -52,22 +52,27 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
override val uxState: IncomingSasVerificationTransaction.UxState
get() {
return when (state) {
VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
VerificationTxState.SendingAccept,
VerificationTxState.Accepted,
VerificationTxState.OnKeyReceived,
VerificationTxState.SendingKey,
VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
VerificationTxState.ShortCodeReady -> IncomingSasVerificationTransaction.UxState.SHOW_SAS
VerificationTxState.ShortCodeAccepted,
VerificationTxState.SendingMac,
VerificationTxState.MacSent,
VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
VerificationTxState.Cancelled -> IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME
VerificationTxState.OnCancelled -> IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
return when (val immutableState = state) {
is VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
is VerificationTxState.SendingAccept,
is VerificationTxState.Accepted,
is VerificationTxState.OnKeyReceived,
is VerificationTxState.SendingKey,
is VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
is VerificationTxState.ShortCodeReady -> IncomingSasVerificationTransaction.UxState.SHOW_SAS
is VerificationTxState.ShortCodeAccepted,
is VerificationTxState.SendingMac,
is VerificationTxState.MacSent,
is VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
is VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
is VerificationTxState.Cancelled -> {
if (immutableState.byMe) {
IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME
} else {
IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
}
}
else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
}
}

View file

@ -49,23 +49,28 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
override val uxState: OutgoingSasVerificationTransaction.UxState
get() {
return when (state) {
VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START
VerificationTxState.SendingStart,
VerificationTxState.Started,
VerificationTxState.OnAccepted,
VerificationTxState.SendingKey,
VerificationTxState.KeySent,
VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
VerificationTxState.ShortCodeReady -> OutgoingSasVerificationTransaction.UxState.SHOW_SAS
VerificationTxState.ShortCodeAccepted,
VerificationTxState.SendingMac,
VerificationTxState.MacSent,
VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED
VerificationTxState.OnCancelled -> OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_ME
VerificationTxState.Cancelled -> OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN
return when (val immutableState = state) {
is VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START
is VerificationTxState.SendingStart,
is VerificationTxState.Started,
is VerificationTxState.OnAccepted,
is VerificationTxState.SendingKey,
is VerificationTxState.KeySent,
is VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
is VerificationTxState.ShortCodeReady -> OutgoingSasVerificationTransaction.UxState.SHOW_SAS
is VerificationTxState.ShortCodeAccepted,
is VerificationTxState.SendingMac,
is VerificationTxState.MacSent,
is VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
is VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED
is VerificationTxState.Cancelled -> {
if (immutableState.byMe) {
OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
} else {
OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_ME
}
}
else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN
}
}

View file

@ -518,8 +518,7 @@ internal class DefaultVerificationService @Inject constructor(
}
if (existingTransaction is SASDefaultVerificationTransaction) {
existingTransaction.cancelledReason = safeValueOf(cancelReq.code)
existingTransaction.state = VerificationTxState.OnCancelled
existingTransaction.state = VerificationTxState.Cancelled(safeValueOf(cancelReq.code), false)
}
}
@ -1075,19 +1074,7 @@ internal class DefaultVerificationService @Inject constructor(
override fun transactionUpdated(tx: VerificationTransaction) {
dispatchTxUpdated(tx)
if (tx is SASDefaultVerificationTransaction
&& (tx.state == VerificationTxState.Cancelled
|| tx.state == VerificationTxState.OnCancelled
|| tx.state == VerificationTxState.Verified)
) {
// remove
this.removeTransaction(tx.otherUserId, tx.transactionId)
}
if (tx is QrCodeVerificationTransaction
&& (tx.state == VerificationTxState.Cancelled
|| tx.state == VerificationTxState.OnCancelled
|| tx.state == VerificationTxState.Verified)
) {
if (tx.state is VerificationTxState.TerminalTxState) {
// remove
this.removeTransaction(tx.otherUserId, tx.transactionId)
}

View file

@ -33,7 +33,6 @@ import im.vector.matrix.android.internal.util.withoutPrefix
import org.matrix.olm.OlmSAS
import org.matrix.olm.OlmUtility
import timber.log.Timber
import kotlin.properties.Delegates
/**
* Represents an ongoing short code interactive key verification between two devices.
@ -71,23 +70,22 @@ internal abstract class SASDefaultVerificationTransaction(
}
}
override var state by Delegates.observable(VerificationTxState.None) { _, _, new ->
// println("$property has changed from $old to $new")
listeners.forEach {
try {
it.transactionUpdated(this)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
override var state: VerificationTxState = VerificationTxState.None
set(newState) {
field = newState
listeners.forEach {
try {
it.transactionUpdated(this)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
if (newState is VerificationTxState.TerminalTxState) {
releaseSAS()
}
}
if (new == VerificationTxState.Cancelled
|| new == VerificationTxState.OnCancelled
|| new == VerificationTxState.Verified) {
releaseSAS()
}
}
override var cancelledReason: CancelCode? = null
private var olmSas: OlmSAS? = null
@ -341,8 +339,7 @@ internal abstract class SASDefaultVerificationTransaction(
}
override fun cancel(code: CancelCode) {
cancelledReason = code
state = VerificationTxState.Cancelled
state = VerificationTxState.Cancelled(code, true)
transport.cancelTransaction(transactionId, otherUserId, otherDeviceId ?: "", code)
}

View file

@ -30,7 +30,6 @@ import im.vector.matrix.android.internal.crypto.verification.VerificationInfo
import im.vector.matrix.android.internal.crypto.verification.VerificationInfoStart
import im.vector.matrix.android.internal.util.withoutPrefix
import timber.log.Timber
import kotlin.properties.Delegates
internal class DefaultQrCodeVerificationTransaction(
private val setDeviceVerificationAction: SetDeviceVerificationAction,
@ -46,20 +45,21 @@ internal class DefaultQrCodeVerificationTransaction(
override val isIncoming: Boolean
) : DefaultVerificationTransaction(transactionId, otherUserId, otherDeviceId, isIncoming), QrCodeVerificationTransaction {
override var cancelledReason: CancelCode? = null
override val qrCodeText: String?
get() = qrCodeData?.toUrl()
override var state by Delegates.observable(VerificationTxState.None) { _, _, _ ->
listeners.forEach {
try {
it.transactionUpdated(this)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
override var state: VerificationTxState = VerificationTxState.None
set(newState) {
field = newState
listeners.forEach {
try {
it.transactionUpdated(this)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
override fun userHasScannedOtherQrCode(otherQrCodeText: String) {
val otherQrCodeData = otherQrCodeText.toQrCodeData() ?: run {
@ -181,8 +181,7 @@ internal class DefaultQrCodeVerificationTransaction(
}
override fun cancel(code: CancelCode) {
cancelledReason = code
state = VerificationTxState.Cancelled
state = VerificationTxState.Cancelled(code, true)
transport.cancelTransaction(transactionId, otherUserId, otherDeviceId ?: "", code)
}

View file

@ -189,7 +189,7 @@ class MainActivity : VectorBaseActivity() {
// The homeserver has invalidated the token, with a soft logout
SoftLogoutActivity.newIntent(this)
args.isUserLoggedOut ->
// the homeserver has invalidated the token (password changed, device deleted, other security reason
// the homeserver has invalidated the token (password changed, device deleted, other security reasons)
SignedOutActivity.newIntent(this)
sessionHolder.hasActiveSession() ->
// We have a session.

View file

@ -18,8 +18,8 @@ package im.vector.riotx.features.crypto.verification
import android.content.Context
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState
import im.vector.matrix.android.api.session.crypto.sas.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseActivity
@ -54,7 +54,7 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
if (!tx.isToDeviceTransport()) return
// TODO maybe check also if
when (tx.state) {
VerificationTxState.OnStarted -> {
is VerificationTxState.OnStarted -> {
// Add a notification for every incoming request
val name = session?.getUser(tx.otherUserId)?.displayName
?: tx.otherUserId
@ -92,13 +92,11 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
}
PopupAlertManager.postVectorAlert(alert)
}
VerificationTxState.Cancelled,
VerificationTxState.OnCancelled,
VerificationTxState.Verified -> {
is VerificationTxState.TerminalTxState -> {
// cancel related notification
PopupAlertManager.cancelAlert("kvr_${tx.transactionId}")
}
else -> Unit
else -> Unit
}
}
@ -134,7 +132,7 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
pr.requestInfo?.fromDevice ?: "",
pr.transactionId ?: "",
pr.roomId ?: ""
)
)
}
colorInt = ThemeUtils.getColor(context, R.attr.vctr_notice_secondary)
// 5mn expiration

View file

@ -110,21 +110,21 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
// Did the request result in a SAS transaction?
if (it.sasTransactionState != null) {
when (it.sasTransactionState) {
VerificationTxState.None,
VerificationTxState.SendingStart,
VerificationTxState.Started,
VerificationTxState.OnStarted,
VerificationTxState.SendingAccept,
VerificationTxState.Accepted,
VerificationTxState.OnAccepted,
VerificationTxState.SendingKey,
VerificationTxState.KeySent,
VerificationTxState.OnKeyReceived,
VerificationTxState.ShortCodeReady,
VerificationTxState.ShortCodeAccepted,
VerificationTxState.SendingMac,
VerificationTxState.MacSent,
VerificationTxState.Verifying -> {
is VerificationTxState.None,
is VerificationTxState.SendingStart,
is VerificationTxState.Started,
is VerificationTxState.OnStarted,
is VerificationTxState.SendingAccept,
is VerificationTxState.Accepted,
is VerificationTxState.OnAccepted,
is VerificationTxState.SendingKey,
is VerificationTxState.KeySent,
is VerificationTxState.OnKeyReceived,
is VerificationTxState.ShortCodeReady,
is VerificationTxState.ShortCodeAccepted,
is VerificationTxState.SendingMac,
is VerificationTxState.MacSent,
is VerificationTxState.Verifying -> {
showFragment(VerificationEmojiCodeFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationArgs(
it.otherUserMxItem?.id ?: "",
@ -133,13 +133,14 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
it.pendingRequest.invoke()?.transactionId ?: it.transactionId))
})
}
VerificationTxState.Verified,
VerificationTxState.Cancelled,
VerificationTxState.OnCancelled -> {
is VerificationTxState.Verified -> {
showFragment(VerificationConclusionFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(
it.sasTransactionState == VerificationTxState.Verified,
it.cancelCode?.value))
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null))
})
}
is VerificationTxState.Cancelled -> {
showFragment(VerificationConclusionFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(false, it.sasTransactionState.cancelCode.value))
})
}
}
@ -148,17 +149,19 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
}
when (it.qrTransactionState) {
VerificationTxState.Verified,
VerificationTxState.Cancelled,
VerificationTxState.OnCancelled -> {
is VerificationTxState.Verified -> {
showFragment(VerificationConclusionFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(
it.qrTransactionState == VerificationTxState.Verified,
it.cancelCode?.value))
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null))
})
return@withState
}
else -> Unit
is VerificationTxState.Cancelled -> {
showFragment(VerificationConclusionFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(false, it.qrTransactionState.cancelCode.value))
})
return@withState
}
else -> Unit
}
// At this point there is no SAS transaction for this request

View file

@ -30,7 +30,6 @@ import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
import im.vector.matrix.android.api.session.crypto.sas.QrCodeVerificationTransaction
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
@ -55,8 +54,7 @@ data class VerificationBottomSheetViewState(
val pendingLocalId: String? = null,
val sasTransactionState: VerificationTxState? = null,
val qrTransactionState: VerificationTxState? = null,
val transactionId: String? = null,
val cancelCode: CancelCode? = null
val transactionId: String? = null
) : MvRxState
class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState,
@ -217,19 +215,17 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
// A SAS tx has been started following this request
setState {
copy(
sasTransactionState = tx.state,
cancelCode = tx.cancelledReason
sasTransactionState = tx.state
)
}
}
}
is QrCodeVerificationTransaction -> {
if (tx.transactionId == (state.pendingRequest.invoke()?.transactionId ?: state.transactionId)) {
// A SAS tx has been started following this request
// A QR tx has been started following this request
setState {
copy(
qrTransactionState = tx.state,
cancelCode = tx.cancelledReason
qrTransactionState = tx.state
)
}
}

View file

@ -15,15 +15,23 @@
*/
package im.vector.riotx.features.crypto.verification.emoji
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
import im.vector.matrix.android.api.session.crypto.sas.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState
import im.vector.matrix.android.api.util.MatrixItem
import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.core.di.HasScreenInjector
@ -63,16 +71,16 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor(
private fun refreshStateFromTx(sasTx: SasVerificationTransaction?) {
when (sasTx?.state) {
VerificationTxState.None,
VerificationTxState.SendingStart,
VerificationTxState.Started,
VerificationTxState.OnStarted,
VerificationTxState.SendingAccept,
VerificationTxState.Accepted,
VerificationTxState.OnAccepted,
VerificationTxState.SendingKey,
VerificationTxState.KeySent,
VerificationTxState.OnKeyReceived -> {
is VerificationTxState.None,
is VerificationTxState.SendingStart,
is VerificationTxState.Started,
is VerificationTxState.OnStarted,
is VerificationTxState.SendingAccept,
is VerificationTxState.Accepted,
is VerificationTxState.OnAccepted,
is VerificationTxState.SendingKey,
is VerificationTxState.KeySent,
is VerificationTxState.OnKeyReceived -> {
setState {
copy(
isWaitingFromOther = false,
@ -86,7 +94,7 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor(
)
}
}
VerificationTxState.ShortCodeReady -> {
is VerificationTxState.ShortCodeReady -> {
setState {
copy(
isWaitingFromOther = false,
@ -98,17 +106,16 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor(
)
}
}
VerificationTxState.ShortCodeAccepted,
VerificationTxState.SendingMac,
VerificationTxState.MacSent,
VerificationTxState.Verifying,
VerificationTxState.Verified -> {
is VerificationTxState.ShortCodeAccepted,
is VerificationTxState.SendingMac,
is VerificationTxState.MacSent,
is VerificationTxState.Verifying,
is VerificationTxState.Verified -> {
setState {
copy(isWaitingFromOther = true)
}
}
VerificationTxState.Cancelled,
VerificationTxState.OnCancelled -> {
is VerificationTxState.Cancelled -> {
// The fragment should not be rendered in this state,
// it should have been replaced by a conclusion fragment
setState {