mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-18 20:29:10 +03:00
Merge pull request #916 from vector-im/debug_qr
Negotiate E2E by default for DMs (#907)
This commit is contained in:
commit
c4649a5824
23 changed files with 427 additions and 331 deletions
|
@ -3,6 +3,7 @@ Changes in RiotX 0.14.0 (2020-XX-XX)
|
|||
|
||||
Features ✨:
|
||||
- Enable encryption in unencrypted rooms, from the room settings (#212)
|
||||
- Negotiate E2E by default for DMs (#907)
|
||||
|
||||
Improvements 🙌:
|
||||
- Sharing things to RiotX: sort list by recent room first (#771)
|
||||
|
|
|
@ -37,8 +37,12 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.*
|
||||
import java.util.*
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import java.util.Arrays
|
||||
import java.util.HashMap
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
|
||||
|
@ -57,7 +61,7 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
|
|||
var roomId: String? = null
|
||||
val lock1 = CountDownLatch(1)
|
||||
|
||||
aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" }, object : TestMatrixCallback<String>(lock1) {
|
||||
aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), object : TestMatrixCallback<String>(lock1) {
|
||||
override fun onSuccess(data: String) {
|
||||
roomId = data
|
||||
super.onSuccess(data)
|
||||
|
|
|
@ -19,7 +19,14 @@ package im.vector.matrix.android.internal.crypto.verification
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.crypto.sas.*
|
||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||
import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasMode
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
|
||||
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.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.common.CommonTestHelper
|
||||
|
@ -30,12 +37,17 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
|||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationCancel
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.toValue
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
import java.util.*
|
||||
import java.util.ArrayList
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
|
@ -97,7 +109,8 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||
if (tx.transactionId == txID) {
|
||||
if ((tx as SASDefaultVerificationTransaction).state === VerificationTxState.OnCancelled) {
|
||||
val immutableState = (tx as SASDefaultVerificationTransaction).state
|
||||
if (immutableState is VerificationTxState.Cancelled && !immutableState.byMe) {
|
||||
cancelLatch.countDown()
|
||||
}
|
||||
}
|
||||
|
@ -110,15 +123,17 @@ class SASTest : InstrumentedTest {
|
|||
aliceSasTx.cancel(CancelCode.User)
|
||||
mTestHelper.await(cancelLatch)
|
||||
|
||||
assertEquals("Should be cancelled on alice side",
|
||||
VerificationTxState.Cancelled, aliceSasTx.state)
|
||||
assertEquals("Should be cancelled on bob side",
|
||||
VerificationTxState.OnCancelled, bobSasTx.state)
|
||||
assertTrue("Should be cancelled on alice side", aliceSasTx.state is VerificationTxState.Cancelled)
|
||||
assertTrue("Should be cancelled on bob side", bobSasTx.state is VerificationTxState.Cancelled)
|
||||
|
||||
assertEquals("Should be User cancelled on alice side",
|
||||
CancelCode.User, aliceSasTx.cancelledReason)
|
||||
assertEquals("Should be User cancelled on bob side",
|
||||
CancelCode.User, aliceSasTx.cancelledReason)
|
||||
val aliceCancelState = aliceSasTx.state as VerificationTxState.Cancelled
|
||||
val bobCancelState = bobSasTx.state as VerificationTxState.Cancelled
|
||||
|
||||
assertTrue("Should be cancelled by me on alice side", aliceCancelState.byMe)
|
||||
assertFalse("Should be cancelled by other on bob side", bobCancelState.byMe)
|
||||
|
||||
assertEquals("Should be User cancelled on alice side", CancelCode.User, aliceCancelState.cancelCode)
|
||||
assertEquals("Should be User cancelled on bob side", CancelCode.User, bobCancelState.cancelCode)
|
||||
|
||||
assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID))
|
||||
assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID))
|
||||
|
@ -128,6 +143,7 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_key_agreement_protocols_must_include_curve25519() {
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
@ -136,15 +152,15 @@ class SASTest : InstrumentedTest {
|
|||
val tid = "00000000"
|
||||
|
||||
// Bob should receive a cancel
|
||||
var cancelReason: String? = null
|
||||
var cancelReason: CancelCode? = null
|
||||
val cancelLatch = CountDownLatch(1)
|
||||
|
||||
val bobListener = object : VerificationService.VerificationListener {
|
||||
override fun transactionCreated(tx: VerificationTransaction) {}
|
||||
|
||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||
if (tx.transactionId == tid && tx.cancelledReason != null) {
|
||||
cancelReason = tx.cancelledReason?.humanReadable
|
||||
if (tx.transactionId == tid && tx.state is VerificationTxState.Cancelled) {
|
||||
cancelReason = (tx.state as VerificationTxState.Cancelled).cancelCode
|
||||
cancelLatch.countDown()
|
||||
}
|
||||
}
|
||||
|
@ -185,13 +201,14 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
mTestHelper.await(cancelLatch)
|
||||
|
||||
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReason)
|
||||
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod, cancelReason)
|
||||
|
||||
cryptoTestData.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_key_agreement_macs_Must_include_hmac_sha256() {
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
@ -229,6 +246,7 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_key_agreement_short_code_include_decimal() {
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
@ -315,7 +333,7 @@ class SASTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||
if ((tx as SASDefaultVerificationTransaction).state === VerificationTxState.OnCancelled) {
|
||||
if ((tx as SASDefaultVerificationTransaction).state is VerificationTxState.Cancelled && !(tx.state as VerificationTxState.Cancelled).byMe) {
|
||||
aliceCancelledLatch.countDown()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2020 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.extensions
|
||||
|
||||
fun Boolean?.orTrue() = this ?: true
|
||||
|
||||
fun Boolean?.orFalse() = this ?: false
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -35,95 +35,111 @@ import timber.log.Timber
|
|||
* Parameter to create a room, with facilities functions to configure it
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
class CreateRoomParams {
|
||||
data class CreateRoomParams(
|
||||
/**
|
||||
* A public visibility indicates that the room will be shown in the published room list.
|
||||
* A private visibility will hide the room from the published room list.
|
||||
* Rooms default to private visibility if this key is not included.
|
||||
* NB: This should not be confused with join_rules which also uses the word public. One of: ["public", "private"]
|
||||
*/
|
||||
@Json(name = "visibility")
|
||||
val visibility: RoomDirectoryVisibility? = null,
|
||||
|
||||
/**
|
||||
* A public visibility indicates that the room will be shown in the published room list.
|
||||
* A private visibility will hide the room from the published room list.
|
||||
* Rooms default to private visibility if this key is not included.
|
||||
* NB: This should not be confused with join_rules which also uses the word public. One of: ["public", "private"]
|
||||
*/
|
||||
var visibility: RoomDirectoryVisibility? = null
|
||||
/**
|
||||
* The desired room alias local part. If this is included, a room alias will be created and mapped to the newly created room.
|
||||
* The alias will belong on the same homeserver which created the room.
|
||||
* For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be #foo:example.com.
|
||||
*/
|
||||
@Json(name = "room_alias_name")
|
||||
val roomAliasName: String? = null,
|
||||
|
||||
/**
|
||||
* The desired room alias local part. If this is included, a room alias will be created and mapped to the newly created room.
|
||||
* The alias will belong on the same homeserver which created the room.
|
||||
* For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be #foo:example.com.
|
||||
*/
|
||||
@Json(name = "room_alias_name")
|
||||
var roomAliasName: String? = null
|
||||
/**
|
||||
* If this is included, an m.room.name event will be sent into the room to indicate the name of the room.
|
||||
* See Room Events for more information on m.room.name.
|
||||
*/
|
||||
@Json(name = "name")
|
||||
val name: String? = null,
|
||||
|
||||
/**
|
||||
* If this is included, an m.room.name event will be sent into the room to indicate the name of the room.
|
||||
* See Room Events for more information on m.room.name.
|
||||
*/
|
||||
var name: String? = null
|
||||
/**
|
||||
* If this is included, an m.room.topic event will be sent into the room to indicate the topic for the room.
|
||||
* See Room Events for more information on m.room.topic.
|
||||
*/
|
||||
@Json(name = "topic")
|
||||
val topic: String? = null,
|
||||
|
||||
/**
|
||||
* If this is included, an m.room.topic event will be sent into the room to indicate the topic for the room.
|
||||
* See Room Events for more information on m.room.topic.
|
||||
*/
|
||||
var topic: String? = null
|
||||
/**
|
||||
* A list of user IDs to invite to the room.
|
||||
* This will tell the server to invite everyone in the list to the newly created room.
|
||||
*/
|
||||
@Json(name = "invite")
|
||||
val invitedUserIds: List<String>? = null,
|
||||
|
||||
/**
|
||||
* A list of user IDs to invite to the room.
|
||||
* This will tell the server to invite everyone in the list to the newly created room.
|
||||
*/
|
||||
@Json(name = "invite")
|
||||
var invitedUserIds: MutableList<String>? = null
|
||||
/**
|
||||
* A list of objects representing third party IDs to invite into the room.
|
||||
*/
|
||||
@Json(name = "invite_3pid")
|
||||
val invite3pids: List<Invite3Pid>? = null,
|
||||
|
||||
/**
|
||||
* A list of objects representing third party IDs to invite into the room.
|
||||
*/
|
||||
@Json(name = "invite_3pid")
|
||||
var invite3pids: MutableList<Invite3Pid>? = null
|
||||
/**
|
||||
* Extra keys to be added to the content of the m.room.create.
|
||||
* The server will clobber the following keys: creator.
|
||||
* Future versions of the specification may allow the server to clobber other keys.
|
||||
*/
|
||||
@Json(name = "creation_content")
|
||||
val creationContent: Any? = null,
|
||||
|
||||
/**
|
||||
* Extra keys to be added to the content of the m.room.create.
|
||||
* The server will clobber the following keys: creator.
|
||||
* Future versions of the specification may allow the server to clobber other keys.
|
||||
*/
|
||||
@Json(name = "creation_content")
|
||||
var creationContent: Any? = null
|
||||
/**
|
||||
* A list of state events to set in the new room.
|
||||
* This allows the user to override the default state events set in the new room.
|
||||
* The expected format of the state events are an object with type, state_key and content keys set.
|
||||
* Takes precedence over events set by presets, but gets overridden by name and topic keys.
|
||||
*/
|
||||
@Json(name = "initial_state")
|
||||
val initialStates: List<Event>? = null,
|
||||
|
||||
/**
|
||||
* A list of state events to set in the new room.
|
||||
* This allows the user to override the default state events set in the new room.
|
||||
* The expected format of the state events are an object with type, state_key and content keys set.
|
||||
* Takes precedence over events set by presets, but gets overridden by name and topic keys.
|
||||
*/
|
||||
@Json(name = "initial_state")
|
||||
var initialStates: MutableList<Event>? = null
|
||||
/**
|
||||
* Convenience parameter for setting various default state events based on a preset. Must be either:
|
||||
* private_chat => join_rules is set to invite. history_visibility is set to shared.
|
||||
* trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the
|
||||
* room creator.
|
||||
* public_chat: => join_rules is set to public. history_visibility is set to shared.
|
||||
*/
|
||||
@Json(name = "preset")
|
||||
val preset: CreateRoomPreset? = null,
|
||||
|
||||
/**
|
||||
* Convenience parameter for setting various default state events based on a preset. Must be either:
|
||||
* private_chat => join_rules is set to invite. history_visibility is set to shared.
|
||||
* trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the
|
||||
* room creator.
|
||||
* public_chat: => join_rules is set to public. history_visibility is set to shared.
|
||||
*/
|
||||
var preset: CreateRoomPreset? = null
|
||||
/**
|
||||
* This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid.
|
||||
* See Direct Messaging for more information.
|
||||
*/
|
||||
@Json(name = "is_direct")
|
||||
val isDirect: Boolean? = null,
|
||||
|
||||
/**
|
||||
* The power level content to override in the default power level event
|
||||
*/
|
||||
@Json(name = "power_level_content_override")
|
||||
val powerLevelContentOverride: PowerLevelsContent? = null
|
||||
) {
|
||||
/**
|
||||
* This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid.
|
||||
* See Direct Messaging for more information.
|
||||
* Set to true means that if cross-signing is enabled and we can get keys for every invited users,
|
||||
* the encryption will be enabled on the created room
|
||||
*/
|
||||
@Json(name = "is_direct")
|
||||
var isDirect: Boolean? = null
|
||||
@Transient
|
||||
internal var enableEncryptionIfInvitedUsersSupportIt: Boolean = false
|
||||
private set
|
||||
|
||||
/**
|
||||
* The power level content to override in the default power level event
|
||||
*/
|
||||
@Json(name = "power_level_content_override")
|
||||
var powerLevelContentOverride: PowerLevelsContent? = null
|
||||
fun enableEncryptionIfInvitedUsersSupportIt(): CreateRoomParams {
|
||||
enableEncryptionIfInvitedUsersSupportIt = true
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the crypto algorithm to the room creation parameters.
|
||||
*
|
||||
* @param algorithm the algorithm
|
||||
*/
|
||||
fun enableEncryptionWithAlgorithm(algorithm: String) {
|
||||
if (algorithm == MXCRYPTO_ALGORITHM_MEGOLM) {
|
||||
fun enableEncryptionWithAlgorithm(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM): CreateRoomParams {
|
||||
return if (algorithm == MXCRYPTO_ALGORITHM_MEGOLM) {
|
||||
val contentMap = mapOf("algorithm" to algorithm)
|
||||
|
||||
val algoEvent = Event(
|
||||
|
@ -132,13 +148,12 @@ class CreateRoomParams {
|
|||
content = contentMap.toContent()
|
||||
)
|
||||
|
||||
if (null == initialStates) {
|
||||
initialStates = mutableListOf(algoEvent)
|
||||
} else {
|
||||
initialStates!!.add(algoEvent)
|
||||
}
|
||||
copy(
|
||||
initialStates = initialStates.orEmpty().filter { it.type != EventType.STATE_ROOM_ENCRYPTION } + algoEvent
|
||||
)
|
||||
} else {
|
||||
Timber.e("Unsupported algorithm: $algorithm")
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,9 +162,10 @@ class CreateRoomParams {
|
|||
*
|
||||
* @param historyVisibility the expected history visibility, set null to remove any existing value.
|
||||
*/
|
||||
fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?) {
|
||||
fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?): CreateRoomParams {
|
||||
// Remove the existing value if any.
|
||||
initialStates?.removeAll { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }
|
||||
val newInitialStates = initialStates
|
||||
?.filter { it.type != EventType.STATE_ROOM_HISTORY_VISIBILITY }
|
||||
|
||||
if (historyVisibility != null) {
|
||||
val contentMap = mapOf("history_visibility" to historyVisibility)
|
||||
|
@ -159,20 +175,24 @@ class CreateRoomParams {
|
|||
stateKey = "",
|
||||
content = contentMap.toContent())
|
||||
|
||||
if (null == initialStates) {
|
||||
initialStates = mutableListOf(historyVisibilityEvent)
|
||||
} else {
|
||||
initialStates!!.add(historyVisibilityEvent)
|
||||
}
|
||||
return copy(
|
||||
initialStates = newInitialStates.orEmpty() + historyVisibilityEvent
|
||||
)
|
||||
} else {
|
||||
return copy(
|
||||
initialStates = newInitialStates
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark as a direct message room.
|
||||
*/
|
||||
fun setDirectMessage() {
|
||||
preset = CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT
|
||||
isDirect = true
|
||||
fun setDirectMessage(): CreateRoomParams {
|
||||
return copy(
|
||||
preset = CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT,
|
||||
isDirect = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,28 +235,26 @@ class CreateRoomParams {
|
|||
*/
|
||||
fun addParticipantIds(hsConfig: HomeServerConnectionConfig,
|
||||
userId: String,
|
||||
ids: List<String>) {
|
||||
for (id in ids) {
|
||||
if (Patterns.EMAIL_ADDRESS.matcher(id).matches() && hsConfig.identityServerUri != null) {
|
||||
if (null == invite3pids) {
|
||||
invite3pids = ArrayList()
|
||||
}
|
||||
val pid = Invite3Pid(idServer = hsConfig.identityServerUri.host!!,
|
||||
medium = ThreePidMedium.EMAIL,
|
||||
address = id)
|
||||
|
||||
invite3pids!!.add(pid)
|
||||
} else if (isUserId(id)) {
|
||||
// do not invite oneself
|
||||
if (userId != id) {
|
||||
if (null == invitedUserIds) {
|
||||
invitedUserIds = ArrayList()
|
||||
}
|
||||
|
||||
invitedUserIds!!.add(id)
|
||||
}
|
||||
}
|
||||
// TODO add phonenumbers when it will be available
|
||||
}
|
||||
ids: List<String>): CreateRoomParams {
|
||||
return copy(
|
||||
invite3pids = (invite3pids.orEmpty() + ids
|
||||
.takeIf { hsConfig.identityServerUri != null }
|
||||
?.filter { id -> Patterns.EMAIL_ADDRESS.matcher(id).matches() }
|
||||
?.map { id ->
|
||||
Invite3Pid(
|
||||
idServer = hsConfig.identityServerUri!!.host!!,
|
||||
medium = ThreePidMedium.EMAIL,
|
||||
address = id
|
||||
)
|
||||
}
|
||||
.orEmpty())
|
||||
.distinct(),
|
||||
invitedUserIds = (invitedUserIds.orEmpty() + ids
|
||||
.filter { id -> isUserId(id) }
|
||||
// do not invite oneself
|
||||
.filter { id -> id != userId })
|
||||
.distinct()
|
||||
)
|
||||
// TODO add phonenumbers when it will be available
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
|||
import im.vector.matrix.android.internal.crypto.tasks.DownloadKeysForUsersTask
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||
import okhttp3.internal.toImmutableList
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -235,7 +234,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
|||
}
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
|
||||
dispatchDeviceChange(userIds.toImmutableList())
|
||||
dispatchDeviceChange(userIds)
|
||||
return usersDevicesInfoMap
|
||||
}
|
||||
|
||||
|
@ -294,7 +293,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
|||
*
|
||||
* @param downloadUsers the user ids list
|
||||
*/
|
||||
private suspend fun doKeyDownloadForUsers(downloadUsers: MutableList<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
|
||||
private suspend fun doKeyDownloadForUsers(downloadUsers: List<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
|
||||
Timber.v("## doKeyDownloadForUsers() : doKeyDownloadForUsers $downloadUsers")
|
||||
// get the user ids which did not already trigger a keys download
|
||||
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,13 @@ import im.vector.matrix.android.internal.session.room.timeline.EventContextRespo
|
|||
import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse
|
||||
import im.vector.matrix.android.internal.session.room.typing.TypingBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.*
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
internal interface RoomAPI {
|
||||
|
||||
|
@ -60,9 +66,12 @@ internal interface RoomAPI {
|
|||
/**
|
||||
* Create a room.
|
||||
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-createroom
|
||||
* Set all the timeouts to 1 minute, because if the server takes time to answer, we will not execute the
|
||||
* create direct chat request if any
|
||||
*
|
||||
* @param param the creation room parameter
|
||||
*/
|
||||
@Headers("CONNECT_TIMEOUT:60000", "READ_TIMEOUT:60000", "WRITE_TIMEOUT:60000")
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "createRoom")
|
||||
fun createRoom(@Body param: CreateRoomParams): Call<CreateRoomResponse>
|
||||
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
package im.vector.matrix.android.internal.session.room.create
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.extensions.orTrue
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService
|
||||
import im.vector.matrix.android.api.session.room.failure.CreateRoomFailure
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.database.awaitNotEmptyResult
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntityFields
|
||||
|
@ -49,12 +52,41 @@ internal class DefaultCreateRoomTask @Inject constructor(
|
|||
private val readMarkersTask: SetReadMarkersTask,
|
||||
@SessionDatabase
|
||||
private val realmConfiguration: RealmConfiguration,
|
||||
private val crossSigningService: CrossSigningService,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val eventBus: EventBus
|
||||
) : CreateRoomTask {
|
||||
|
||||
override suspend fun execute(params: CreateRoomParams): String {
|
||||
val createRoomParams = params
|
||||
.takeIf { it.enableEncryptionIfInvitedUsersSupportIt }
|
||||
?.takeIf { crossSigningService.isCrossSigningEnabled() }
|
||||
?.takeIf { it.invite3pids.isNullOrEmpty() }
|
||||
?.invitedUserIds
|
||||
?.let { userIds ->
|
||||
val keys = deviceListManager.downloadKeys(userIds, forceDownload = false)
|
||||
|
||||
userIds.any { userId ->
|
||||
if (keys.map[userId].isNullOrEmpty()) {
|
||||
// A user has no device, so do not enable encryption
|
||||
true
|
||||
} else {
|
||||
// Check that every user's device have at least one key
|
||||
keys.map[userId]?.values?.any { it.keys.isNullOrEmpty() } ?: true
|
||||
}
|
||||
}
|
||||
}
|
||||
.orTrue()
|
||||
.let { cannotEnableEncryption ->
|
||||
if (!cannotEnableEncryption) {
|
||||
params.enableEncryptionWithAlgorithm()
|
||||
} else {
|
||||
params
|
||||
}
|
||||
}
|
||||
|
||||
val createRoomResponse = executeRequest<CreateRoomResponse>(eventBus) {
|
||||
apiCall = roomAPI.createRoom(params)
|
||||
apiCall = roomAPI.createRoom(createRoomParams)
|
||||
}
|
||||
val roomId = createRoomResponse.roomId!!
|
||||
// Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before)
|
||||
|
@ -66,8 +98,8 @@ internal class DefaultCreateRoomTask @Inject constructor(
|
|||
} catch (exception: TimeoutCancellationException) {
|
||||
throw CreateRoomFailure.CreatedWithTimeout
|
||||
}
|
||||
if (params.isDirect()) {
|
||||
handleDirectChatCreation(params, roomId)
|
||||
if (createRoomParams.isDirect()) {
|
||||
handleDirectChatCreation(createRoomParams, roomId)
|
||||
}
|
||||
setReadMarkers(roomId)
|
||||
return roomId
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package im.vector.matrix.android.internal.task
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -92,13 +92,12 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
|||
}
|
||||
|
||||
private fun createRoomAndInviteSelectedUsers() = withState { currentState ->
|
||||
val isDirect = currentState.selectedUsers.size == 1
|
||||
val roomParams = CreateRoomParams().apply {
|
||||
invitedUserIds = ArrayList(currentState.selectedUsers.map { it.userId })
|
||||
if (isDirect) {
|
||||
setDirectMessage()
|
||||
}
|
||||
}
|
||||
val roomParams = CreateRoomParams(
|
||||
invitedUserIds = currentState.selectedUsers.map { it.userId }
|
||||
)
|
||||
.setDirectMessage()
|
||||
.enableEncryptionIfInvitedUsersSupportIt()
|
||||
|
||||
session.rx()
|
||||
.createRoom(roomParams)
|
||||
.execute {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
@ -129,10 +127,12 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||
pendingRequest = Loading()
|
||||
)
|
||||
}
|
||||
val roomParams = CreateRoomParams().apply {
|
||||
invitedUserIds = listOf(otherUserId).toMutableList()
|
||||
setDirectMessage()
|
||||
}
|
||||
val roomParams = CreateRoomParams(
|
||||
invitedUserIds = listOf(otherUserId)
|
||||
)
|
||||
.setDirectMessage()
|
||||
.enableEncryptionIfInvitedUsersSupportIt()
|
||||
|
||||
session.createRoom(roomParams, object : MatrixCallback<String> {
|
||||
override fun onSuccess(data: String) {
|
||||
setState {
|
||||
|
@ -217,19 +217,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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -81,15 +81,13 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
|
|||
copy(asyncCreateRoomRequest = Loading())
|
||||
}
|
||||
|
||||
val createRoomParams = CreateRoomParams().apply {
|
||||
name = state.roomName.takeIf { it.isNotBlank() }
|
||||
|
||||
// Directory visibility
|
||||
visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE
|
||||
|
||||
// Public room
|
||||
preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
|
||||
}
|
||||
val createRoomParams = CreateRoomParams(
|
||||
name = state.roomName.takeIf { it.isNotBlank() },
|
||||
// Directory visibility
|
||||
visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE,
|
||||
// Public room
|
||||
preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
|
||||
)
|
||||
|
||||
session.createRoom(createRoomParams, object : MatrixCallback<String> {
|
||||
override fun onSuccess(data: String) {
|
||||
|
|
Loading…
Add table
Reference in a new issue