Merge branch 'release/1.6.1' into main

This commit is contained in:
Benoit Marty 2023-05-25 11:20:18 +02:00
commit b9cc1b6dab
32 changed files with 157 additions and 115 deletions

View File

@ -1,3 +1,20 @@
Changes in Element v1.6.1 (2023-05-25)
======================================
Corrective release for 1.6.0
Bugfixes 🐛
----------
- Allow stateloss on verification dialogfragment ([#8439](https://github.com/vector-im/element-android/issues/8439))
- Fix: Update verification popup text when a re-verification is needed after rust migration (read only sessions) ([#8445](https://github.com/vector-im/element-android/issues/8445))
- Fix several performance issues causing app non responsive issues. ([#8454](https://github.com/vector-im/element-android/issues/8454))
- Fix: The device list screen from the member profile page was always showing the current user devices (rust crypto). ([#8457](https://github.com/vector-im/element-android/issues/8457))
Other changes
-------------
- Remove UI option to manually verify a specific device of another user (deprecated behaviour) ([#8458](https://github.com/vector-im/element-android/issues/8458))
Changes in Element v1.6.0 (2023-05-17) Changes in Element v1.6.0 (2023-05-17)
====================================== ======================================

View File

@ -28,7 +28,7 @@ buildscript {
classpath 'com.google.gms:google-services:4.3.15' classpath 'com.google.gms:google-services:4.3.15'
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6'
classpath "com.likethesalad.android:stem-plugin:2.4.0" classpath "com.likethesalad.android:stem-plugin:2.4.1"
classpath 'org.owasp:dependency-check-gradle:8.2.1' classpath 'org.owasp:dependency-check-gradle:8.2.1'
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.8.10" classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.8.10"
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0" classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"

View File

@ -101,7 +101,7 @@ ext.libs = [
], ],
element : [ element : [
'opusencoder' : "io.element.android:opusencoder:1.1.0", 'opusencoder' : "io.element.android:opusencoder:1.1.0",
'wysiwyg' : "io.element.android:wysiwyg:1.2.2" 'wysiwyg' : "io.element.android:wysiwyg:2.2.1"
], ],
squareup : [ squareup : [
'moshi' : "com.squareup.moshi:moshi:$moshi", 'moshi' : "com.squareup.moshi:moshi:$moshi",

View File

@ -0,0 +1,2 @@
Main changes in this version: Element Android is now using the Crypto Rust SDK.
Full changelog: https://github.com/vector-im/element-android/releases

View File

@ -2446,6 +2446,7 @@
</plurals> </plurals>
<string name="crosssigning_verify_this_session">Verify this device</string> <string name="crosssigning_verify_this_session">Verify this device</string>
<string name="crosssigning_verify_after_update">App updated</string>
<string name="crosssigning_cannot_verify_this_session">Unable to verify this device</string> <string name="crosssigning_cannot_verify_this_session">Unable to verify this device</string>
<string name="crosssigning_cannot_verify_this_session_desc">You wont be able to access encrypted message history. Reset your Secure Message Backup and verification keys to start fresh.</string> <string name="crosssigning_cannot_verify_this_session_desc">You wont be able to access encrypted message history. Reset your Secure Message Backup and verification keys to start fresh.</string>
@ -2465,7 +2466,9 @@
<string name="verification_profile_device_verified_because">This session is trusted for secure messaging because %1$s (%2$s) verified it:</string> <string name="verification_profile_device_verified_because">This session is trusted for secure messaging because %1$s (%2$s) verified it:</string>
<string name="verification_profile_device_new_signing">%1$s (%2$s) signed in using a new session:</string> <string name="verification_profile_device_new_signing">%1$s (%2$s) signed in using a new session:</string>
<string name="verification_profile_device_untrust_info">Until this user trusts this session, messages sent to and from it are labeled with warnings. Alternatively, you can manually verify it.</string> <!-- TODO TO BE REMOVED -->
<string tools:ignore="UnusedResources" name="verification_profile_device_untrust_info">Until this user trusts this session, messages sent to and from it are labeled with warnings. Alternatively, you can manually verify it.</string>
<string name="verification_profile_other_device_untrust_info">Until this user trusts this session, messages sent to and from it are labeled with warnings.</string>
<string name="initialize_cross_signing">Initialize CrossSigning</string> <string name="initialize_cross_signing">Initialize CrossSigning</string>
@ -2707,6 +2710,7 @@
<string tools:ignore="UnusedResources" name="crosssigning_verify_session">Verify login</string> <string tools:ignore="UnusedResources" name="crosssigning_verify_session">Verify login</string>
<string name="cross_signing_verify_by_emoji">Interactively Verify by Emoji</string> <string name="cross_signing_verify_by_emoji">Interactively Verify by Emoji</string>
<string name="confirm_your_identity">Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.</string> <string name="confirm_your_identity">Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.</string>
<string name="confirm_your_identity_after_update">Secure messaging has been improved with the latest update. Please re-verify your device.</string>
<string name="confirm_your_identity_quad_s">Confirm your identity by verifying this login, granting it access to encrypted messages.</string> <string name="confirm_your_identity_quad_s">Confirm your identity by verifying this login, granting it access to encrypted messages.</string>
<string name="failed_to_initialize_cross_signing">Failed to set up Cross Signing</string> <string name="failed_to_initialize_cross_signing">Failed to set up Cross Signing</string>

View File

@ -63,7 +63,7 @@ android {
// that the app's state is completely cleared between tests. // that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true' testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.6.0\"" buildConfigField "String", "SDK_VERSION", "\"1.6.1\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""

View File

@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.session.room.read
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.events.model.LocalEcho import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
@ -64,9 +66,10 @@ internal class DefaultSetReadMarkersTask @Inject constructor(
private val globalErrorReceiver: GlobalErrorReceiver, private val globalErrorReceiver: GlobalErrorReceiver,
private val clock: Clock, private val clock: Clock,
private val homeServerCapabilitiesService: HomeServerCapabilitiesService, private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
) : SetReadMarkersTask { ) : SetReadMarkersTask {
override suspend fun execute(params: SetReadMarkersTask.Params) { override suspend fun execute(params: SetReadMarkersTask.Params) = withContext(coroutineDispatchers.io) {
val markers = mutableMapOf<String, String>() val markers = mutableMapOf<String, String>()
Timber.v("Execute set read marker with params: $params") Timber.v("Execute set read marker with params: $params")
val latestSyncedEventId = latestSyncedEventId(params.roomId) val latestSyncedEventId = latestSyncedEventId(params.roomId)

View File

@ -360,9 +360,7 @@ internal class RustCryptoService @Inject constructor(
} }
override fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>> { override fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>> {
return olmMachine.getLiveDevices(listOf(myUserId)).map { return olmMachine.getLiveDevices(userIds)
it.filter { it.userId == myUserId }
}
} }
override fun getLiveCryptoDeviceInfoWithId(deviceId: String): LiveData<Optional<CryptoDeviceInfo>> { override fun getLiveCryptoDeviceInfoWithId(deviceId: String): LiveData<Optional<CryptoDeviceInfo>> {

View File

@ -71,6 +71,10 @@ fun RealmToMigrate.getPickledAccount(pickleKey: ByteArray): MigrationData {
val userKey = metadataEntity.xSignUserPrivateKey val userKey = metadataEntity.xSignUserPrivateKey
val selfSignedKey = metadataEntity.xSignSelfSignedPrivateKey val selfSignedKey = metadataEntity.xSignSelfSignedPrivateKey
Timber.i("## Migration: has private MSK ${masterKey.isNullOrBlank().not()}")
Timber.i("## Migration: has private USK ${userKey.isNullOrBlank().not()}")
Timber.i("## Migration: has private SSK ${selfSignedKey.isNullOrBlank().not()}")
val userId = metadataEntity.userId val userId = metadataEntity.userId
?: throw java.lang.IllegalArgumentException("Rust db migration: userId is null") ?: throw java.lang.IllegalArgumentException("Rust db migration: userId is null")
val deviceId = metadataEntity.deviceId val deviceId = metadataEntity.deviceId
@ -79,6 +83,8 @@ fun RealmToMigrate.getPickledAccount(pickleKey: ByteArray): MigrationData {
val backupVersion = metadataEntity.backupVersion val backupVersion = metadataEntity.backupVersion
val backupRecoveryKey = metadataEntity.keyBackupRecoveryKey val backupRecoveryKey = metadataEntity.keyBackupRecoveryKey
Timber.i("## Migration: has private backup key ${backupRecoveryKey != null} for version $backupVersion")
val isOlmAccountShared = metadataEntity.deviceKeysSentToServer val isOlmAccountShared = metadataEntity.deviceKeysSentToServer
val olmAccount = metadataEntity.getOlmAccount() val olmAccount = metadataEntity.getOlmAccount()

View File

@ -267,7 +267,7 @@ fi
printf "\n================================================================================\n" printf "\n================================================================================\n"
printf "Wait for the GitHub action https://github.com/vector-im/element-android/actions/workflows/build.yml?query=branch%%3Amain to build the 'main' branch.\n" printf "Wait for the GitHub action https://github.com/vector-im/element-android/actions/workflows/build.yml?query=branch%%3Amain to build the 'main' branch.\n"
read -p "After GHA is finished, please enter the artifact URL (for 'vector-gplay-rustCrypto-release-unsigned'): " artifactUrl read -p "After GHA is finished, please enter the artifact URL (for 'vector-gplay-release-unsigned'): " artifactUrl
printf "\n================================================================================\n" printf "\n================================================================================\n"
printf "Downloading the artifact...\n" printf "Downloading the artifact...\n"
@ -290,7 +290,7 @@ set -e
printf "\n================================================================================\n" printf "\n================================================================================\n"
printf "Unzipping the artifact...\n" printf "Unzipping the artifact...\n"
unzip ${targetPath}/vector-gplay-rustCrypto-release-unsigned.zip -d ${targetPath} unzip ${targetPath}/vector-gplay-release-unsigned.zip -d ${targetPath}
# Flatten folder hierarchy # Flatten folder hierarchy
mv ${targetPath}/gplayRustCrypto/release/* ${targetPath} mv ${targetPath}/gplayRustCrypto/release/* ${targetPath}

View File

@ -37,7 +37,7 @@ ext.versionMinor = 6
// Note: even values are reserved for regular release, odd values for hotfix release. // Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value // When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release. // is the value for the next regular release.
ext.versionPatch = 0 ext.versionPatch = 1
static def getGitTimestamp() { static def getGitTimestamp() {
def cmd = 'git show -s --format=%ct' def cmd = 'git show -s --format=%ct'

View File

@ -23,7 +23,7 @@ import android.text.Spanned
import android.text.style.StrikethroughSpan import android.text.style.StrikethroughSpan
import androidx.core.text.getSpans import androidx.core.text.getSpans
import im.vector.app.features.html.HtmlCodeSpan import im.vector.app.features.html.HtmlCodeSpan
import io.element.android.wysiwyg.spans.InlineCodeSpan import io.element.android.wysiwyg.view.spans.InlineCodeSpan
import io.mockk.justRun import io.mockk.justRun
import io.mockk.mockk import io.mockk.mockk
import io.mockk.slot import io.mockk.slot

View File

@ -17,6 +17,7 @@
package im.vector.app.core.session.clientinfo package im.vector.app.core.session.clientinfo
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import javax.inject.Inject import javax.inject.Inject
@ -27,16 +28,19 @@ class DeleteUnusedClientInformationUseCase @Inject constructor(
suspend fun execute(deviceInfoList: List<DeviceInfo>): Result<Unit> = runCatching { suspend fun execute(deviceInfoList: List<DeviceInfo>): Result<Unit> = runCatching {
// A defensive approach against local storage reports an empty device list (although it is not a seen situation). // A defensive approach against local storage reports an empty device list (although it is not a seen situation).
if (deviceInfoList.isEmpty()) return Result.success(Unit) if (deviceInfoList.isEmpty()) return Result.success(Unit)
val dispatcher = activeSessionHolder.getSafeActiveSession()?.coroutineDispatchers?.io
val expectedClientInfoKeyList = deviceInfoList.map { MATRIX_CLIENT_INFO_KEY_PREFIX + it.deviceId } ?: return@runCatching
activeSessionHolder withContext(dispatcher) {
.getSafeActiveSession() val expectedClientInfoKeyList = deviceInfoList.map { MATRIX_CLIENT_INFO_KEY_PREFIX + it.deviceId }
?.accountDataService() activeSessionHolder
?.getUserAccountDataEventsStartWith(MATRIX_CLIENT_INFO_KEY_PREFIX) .getSafeActiveSession()
?.map { it.type } ?.accountDataService()
?.subtract(expectedClientInfoKeyList.toSet()) ?.getUserAccountDataEventsStartWith(MATRIX_CLIENT_INFO_KEY_PREFIX)
?.forEach { userAccountDataKeyToDelete -> ?.map { it.type }
activeSessionHolder.getSafeActiveSession()?.accountDataService()?.deleteUserAccountData(userAccountDataKeyToDelete) ?.subtract(expectedClientInfoKeyList.toSet())
} ?.forEach { userAccountDataKeyToDelete ->
activeSessionHolder.getSafeActiveSession()?.accountDataService()?.deleteUserAccountData(userAccountDataKeyToDelete)
}
}
} }
} }

View File

@ -29,6 +29,7 @@ import com.airbnb.mvrx.viewModel
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.startSyncing import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.extensions.vectorStore import im.vector.app.core.extensions.vectorStore
@ -170,6 +171,19 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
} }
private fun handleAppStarted() { private fun handleAppStarted() {
// On the first run with rust crypto this would be false
if (!vectorPreferences.isOnRustCrypto()) {
if (activeSessionHolder.hasActiveSession()) {
vectorPreferences.setHadExistingLegacyData(activeSessionHolder.getActiveSession().isOpenable)
} else {
vectorPreferences.setHadExistingLegacyData(false)
}
}
if (BuildConfig.FLAVOR == "rustCrypto") {
vectorPreferences.setIsOnRustCrypto(true)
}
if (intent.hasExtra(EXTRA_NEXT_INTENT)) { if (intent.hasExtra(EXTRA_NEXT_INTENT)) {
// Start the next Activity // Start the next Activity
startSyncing() startSyncing()

View File

@ -52,7 +52,7 @@ class SharedSecuredStorageResetAllFragment :
views.ssssResetOtherDevices.debouncedClicks { views.ssssResetOtherDevices.debouncedClicks {
withState(sharedViewModel) { withState(sharedViewModel) {
DeviceListBottomSheet.newInstance(it.userId, false).show(childFragmentManager, "DEV_LIST") DeviceListBottomSheet.newInstance(it.userId).show(childFragmentManager, "DEV_LIST")
} }
} }

View File

@ -469,11 +469,21 @@ class HomeActivity :
private fun handleOnNewSession(event: HomeActivityViewEvents.CurrentSessionNotVerified) { private fun handleOnNewSession(event: HomeActivityViewEvents.CurrentSessionNotVerified) {
// We need to ask // We need to ask
val titleRes = if (event.afterMigration) {
R.string.crosssigning_verify_after_update
} else {
R.string.crosssigning_verify_this_session
}
val descRes = if (event.afterMigration) {
R.string.confirm_your_identity_after_update
} else {
R.string.confirm_your_identity
}
promptSecurityEvent( promptSecurityEvent(
uid = PopupAlertManager.VERIFY_SESSION_UID, uid = PopupAlertManager.VERIFY_SESSION_UID,
userItem = event.userItem, userItem = event.userItem,
titleRes = R.string.crosssigning_verify_this_session, titleRes = titleRes,
descRes = R.string.confirm_your_identity, descRes = descRes,
) { ) {
it.navigator.requestSelfSessionVerification(it) it.navigator.requestSelfSessionVerification(it)
} }

View File

@ -23,7 +23,7 @@ sealed interface HomeActivityViewEvents : VectorViewEvents {
data class AskPasswordToInitCrossSigning(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents data class AskPasswordToInitCrossSigning(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents
data class CurrentSessionNotVerified( data class CurrentSessionNotVerified(
val userItem: MatrixItem.UserItem, val userItem: MatrixItem.UserItem,
// val waitForIncomingRequest: Boolean = true, val afterMigration: Boolean
) : HomeActivityViewEvents ) : HomeActivityViewEvents
data class CurrentSessionCannotBeVerified( data class CurrentSessionCannotBeVerified(

View File

@ -453,6 +453,7 @@ class HomeActivityViewModel @AssistedInject constructor(
_viewEvents.post( _viewEvents.post(
HomeActivityViewEvents.CurrentSessionNotVerified( HomeActivityViewEvents.CurrentSessionNotVerified(
session.getUserOrDefault(session.myUserId).toMatrixItem(), session.getUserOrDefault(session.myUserId).toMatrixItem(),
vectorPreferences.isOnRustCrypto() && vectorPreferences.hadExistingLegacyData()
) )
) )
} else { } else {

View File

@ -50,9 +50,9 @@ import im.vector.app.databinding.ComposerRichTextLayoutBinding
import im.vector.app.databinding.ViewRichTextMenuButtonBinding import im.vector.app.databinding.ViewRichTextMenuButtonBinding
import im.vector.app.features.home.room.detail.composer.images.UriContentListener import im.vector.app.features.home.room.detail.composer.images.UriContentListener
import io.element.android.wysiwyg.EditorEditText import io.element.android.wysiwyg.EditorEditText
import io.element.android.wysiwyg.inputhandlers.models.InlineFormat
import io.element.android.wysiwyg.inputhandlers.models.LinkAction
import io.element.android.wysiwyg.utils.RustErrorCollector import io.element.android.wysiwyg.utils.RustErrorCollector
import io.element.android.wysiwyg.view.models.InlineFormat
import io.element.android.wysiwyg.view.models.LinkAction
import uniffi.wysiwyg_composer.ActionState import uniffi.wysiwyg_composer.ActionState
import uniffi.wysiwyg_composer.ComposerAction import uniffi.wysiwyg_composer.ComposerAction
@ -269,7 +269,7 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
views.richTextComposerEditText.getLinkAction()?.let { views.richTextComposerEditText.getLinkAction()?.let {
when (it) { when (it) {
LinkAction.InsertLink -> callback?.onSetLink(isTextSupported = true, initialLink = null) LinkAction.InsertLink -> callback?.onSetLink(isTextSupported = true, initialLink = null)
is LinkAction.SetLink -> callback?.onSetLink(isTextSupported = false, initialLink = it.currentLink) is LinkAction.SetLink -> callback?.onSetLink(isTextSupported = false, initialLink = it.currentUrl)
} }
} }
} }

View File

@ -322,11 +322,10 @@ class RoomListViewModel @AssistedInject constructor(
} }
private fun handleDeleteLocalRooms() { private fun handleDeleteLocalRooms() {
val localRoomIds = session.roomService() viewModelScope.launch(session.coroutineDispatchers.io) {
.getRoomSummaries(roomSummaryQueryParams { roomId = QueryStringValue.Contains(RoomLocalEcho.PREFIX) }) val localRoomIds = session.roomService()
.map { it.roomId } .getRoomSummaries(roomSummaryQueryParams { roomId = QueryStringValue.Contains(RoomLocalEcho.PREFIX) })
.map { it.roomId }
viewModelScope.launch {
localRoomIds.forEach { localRoomIds.forEach {
session.roomService().deleteLocalRoom(it) session.roomService().deleteLocalRoom(it)
} }

View File

@ -43,7 +43,7 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.element.android.wysiwyg.spans.InlineCodeSpan import io.element.android.wysiwyg.view.spans.InlineCodeSpan
import io.noties.markwon.AbstractMarkwonPlugin import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonPlugin import io.noties.markwon.MarkwonPlugin

View File

@ -18,8 +18,8 @@ package im.vector.app.features.html
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.element.android.wysiwyg.spans.CodeBlockSpan import io.element.android.wysiwyg.view.spans.CodeBlockSpan
import io.element.android.wysiwyg.spans.InlineCodeSpan import io.element.android.wysiwyg.view.spans.InlineCodeSpan
import io.noties.markwon.MarkwonVisitor import io.noties.markwon.MarkwonVisitor
import io.noties.markwon.SpannableBuilder import io.noties.markwon.SpannableBuilder
import io.noties.markwon.core.MarkwonTheme import io.noties.markwon.core.MarkwonTheme

View File

@ -38,6 +38,7 @@ import im.vector.app.config.OnboardingVariant
import im.vector.app.core.debug.DebugNavigator import im.vector.app.core.debug.DebugNavigator
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.error.fatalError import im.vector.app.core.error.fatalError
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.features.VectorFeatures import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.extensions.toAnalyticsViewRoom import im.vector.app.features.analytics.extensions.toAnalyticsViewRoom
@ -256,8 +257,9 @@ class DefaultNavigator @Inject constructor(
otherSessionId otherSessionId
) )
if (context is AppCompatActivity) { if (context is AppCompatActivity) {
SelfVerificationBottomSheet.forTransaction(request.transactionId) context.supportFragmentManager.commitTransaction(allowStateLoss = true) {
.show(context.supportFragmentManager, "VERIF") add(SelfVerificationBottomSheet.forTransaction(request.transactionId), "VERIF")
}
} }
} }
} }
@ -271,8 +273,9 @@ class DefaultNavigator @Inject constructor(
// .filter { it.deviceId != session.sessionParams.deviceId } // .filter { it.deviceId != session.sessionParams.deviceId }
// .map { it.deviceId } // .map { it.deviceId }
if (context is AppCompatActivity) { if (context is AppCompatActivity) {
SelfVerificationBottomSheet.verifyOwnUntrustedDevice() context.supportFragmentManager.commitTransaction(allowStateLoss = true) {
.show(context.supportFragmentManager, "VERIF") add(SelfVerificationBottomSheet.verifyOwnUntrustedDevice(), "VERIF")
}
// if (otherSessions.isNotEmpty()) { // if (otherSessions.isNotEmpty()) {
// val pr = session.cryptoService().verificationService().requestSelfKeyVerification( // val pr = session.cryptoService().verificationService().requestSelfKeyVerification(
// supportedVerificationMethodsProvider.provide()) // supportedVerificationMethodsProvider.provide())

View File

@ -24,7 +24,9 @@ import im.vector.app.R
import im.vector.app.core.resources.BuildMeta import im.vector.app.core.resources.BuildMeta
import im.vector.app.core.utils.FirstThrottler import im.vector.app.core.utils.FirstThrottler
import im.vector.app.features.displayname.getBestName import im.vector.app.features.displayname.getBestName
import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.api.session.content.ContentUrlResolver
import org.matrix.android.sdk.api.session.getUserOrDefault import org.matrix.android.sdk.api.session.getUserOrDefault
@ -121,11 +123,15 @@ class NotificationDrawerManager @Inject constructor(
* Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room. * Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
*/ */
fun setCurrentRoom(roomId: String?) { fun setCurrentRoom(roomId: String?) {
updateEvents { val dispatcher = currentSession?.coroutineDispatchers?.io ?: return
val hasChanged = roomId != currentRoomId val scope = currentSession?.coroutineScope ?: return
currentRoomId = roomId scope.launch(dispatcher) {
if (hasChanged && roomId != null) { updateEvents {
it.clearMessagesForRoom(roomId) val hasChanged = roomId != currentRoomId
currentRoomId = roomId
if (hasChanged && roomId != null) {
it.clearMessagesForRoom(roomId)
}
} }
} }
} }
@ -135,12 +141,16 @@ class NotificationDrawerManager @Inject constructor(
* Used to ignore events related to that thread (no need to display notification) and clean any existing notification on this room. * Used to ignore events related to that thread (no need to display notification) and clean any existing notification on this room.
*/ */
fun setCurrentThread(threadId: String?) { fun setCurrentThread(threadId: String?) {
updateEvents { val dispatcher = currentSession?.coroutineDispatchers?.io ?: return
val hasChanged = threadId != currentThreadId val scope = currentSession?.coroutineScope ?: return
currentThreadId = threadId scope.launch(dispatcher) {
currentRoomId?.let { roomId -> updateEvents {
if (hasChanged && threadId != null) { val hasChanged = threadId != currentThreadId
it.clearMessagesForThread(roomId, threadId) currentThreadId = threadId
currentRoomId?.let { roomId ->
if (hasChanged && threadId != null) {
it.clearMessagesForThread(roomId, threadId)
}
} }
} }
} }

View File

@ -22,6 +22,4 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
sealed class DeviceListAction : VectorViewModelAction { sealed class DeviceListAction : VectorViewModelAction {
data class SelectDevice(val device: CryptoDeviceInfo) : DeviceListAction() data class SelectDevice(val device: CryptoDeviceInfo) : DeviceListAction()
object DeselectDevice : DeviceListAction() object DeselectDevice : DeviceListAction()
data class ManuallyVerify(val deviceId: String) : DeviceListAction()
} }

View File

@ -47,16 +47,7 @@ class DeviceListBottomSheet :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.observeViewEvents { viewModel.observeViewEvents {
when (it) { // nop
is DeviceListBottomSheetViewEvents.Verify -> {
// TODO selfverif
// VerificationBottomSheet.withArgs(
// // roomId = null,
// otherUserId = it.userId,
// transactionId = it.txID
// ).show(requireActivity().supportFragmentManager, "REQPOP")
}
}
} }
} }
@ -109,13 +100,12 @@ class DeviceListBottomSheet :
@Parcelize @Parcelize
data class Args( data class Args(
val userId: String, val userId: String,
val allowDeviceAction: Boolean
) : Parcelable ) : Parcelable
companion object { companion object {
fun newInstance(userId: String, allowDeviceAction: Boolean = true): DeviceListBottomSheet { fun newInstance(userId: String): DeviceListBottomSheet {
return DeviceListBottomSheet().apply { return DeviceListBottomSheet().apply {
setArguments(Args(userId, allowDeviceAction)) setArguments(Args(userId))
} }
} }
} }

View File

@ -21,6 +21,4 @@ import im.vector.app.core.platform.VectorViewEvents
/** /**
* Transient events for device list screen. * Transient events for device list screen.
*/ */
sealed class DeviceListBottomSheetViewEvents : VectorViewEvents { sealed class DeviceListBottomSheetViewEvents : VectorViewEvents
data class Verify(val userId: String, val txID: String) : DeviceListBottomSheetViewEvents()
}

View File

@ -34,7 +34,6 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
import org.matrix.android.sdk.api.session.getUserOrDefault import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
@ -42,7 +41,7 @@ import org.matrix.android.sdk.flow.flow
data class DeviceListViewState( data class DeviceListViewState(
val userId: String, val userId: String,
val allowDeviceAction: Boolean, val myUserId: String,
val userItem: MatrixItem? = null, val userItem: MatrixItem? = null,
val memberCrossSigningKey: MXCrossSigningInfo? = null, val memberCrossSigningKey: MXCrossSigningInfo? = null,
val myDeviceId: String = "", val myDeviceId: String = "",
@ -69,7 +68,7 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession() val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
return DeviceListViewState( return DeviceListViewState(
userId = userId, userId = userId,
allowDeviceAction = args.allowDeviceAction, myUserId = session.myUserId,
userItem = session.getUserOrDefault(userId).toMatrixItem(), userItem = session.getUserOrDefault(userId).toMatrixItem(),
myDeviceId = session.sessionParams.deviceId, myDeviceId = session.sessionParams.deviceId,
) )
@ -104,7 +103,6 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(
when (action) { when (action) {
is DeviceListAction.SelectDevice -> selectDevice(action) is DeviceListAction.SelectDevice -> selectDevice(action)
is DeviceListAction.DeselectDevice -> deselectDevice() is DeviceListAction.DeselectDevice -> deselectDevice()
is DeviceListAction.ManuallyVerify -> manuallyVerify(action)
} }
} }
@ -121,7 +119,6 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(
} }
private fun selectDevice(action: DeviceListAction.SelectDevice) { private fun selectDevice(action: DeviceListAction.SelectDevice) {
if (!initialState.allowDeviceAction) return
setState { setState {
copy(selectedDevice = action.device) copy(selectedDevice = action.device)
} }
@ -132,18 +129,4 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(
copy(selectedDevice = null) copy(selectedDevice = null)
} }
} }
private fun manuallyVerify(action: DeviceListAction.ManuallyVerify) {
if (!initialState.allowDeviceAction) return
viewModelScope.launch {
session.cryptoService().verificationService().requestDeviceVerification(
methods = listOf(VerificationMethod.SAS),
otherUserId = initialState.userId,
otherDeviceId = action.deviceId,
).transactionId
.let { txID ->
_viewEvents.post(DeviceListBottomSheetViewEvents.Verify(initialState.userId, txID))
}
}
}
} }

View File

@ -28,7 +28,6 @@ import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.databinding.BottomSheetGenericListBinding import im.vector.app.databinding.BottomSheetGenericListBinding
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -63,8 +62,4 @@ class DeviceTrustInfoActionFragment :
override fun invalidate() = withState(viewModel) { override fun invalidate() = withState(viewModel) {
epoxyController.setData(it) epoxyController.setData(it)
} }
override fun onVerifyManually(device: CryptoDeviceInfo) {
viewModel.handle(DeviceListAction.ManuallyVerify(device.deviceId))
}
} }

View File

@ -25,13 +25,10 @@ import im.vector.app.core.ui.list.genericFooterItem
import im.vector.app.core.ui.list.genericItem import im.vector.app.core.ui.list.genericItem
import im.vector.app.core.ui.list.genericWithValueItem import im.vector.app.core.ui.list.genericWithValueItem
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.devices.TrustUtils import im.vector.app.features.settings.devices.TrustUtils
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
import me.gujun.android.span.span import me.gujun.android.span.span
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import javax.inject.Inject import javax.inject.Inject
@ -39,13 +36,10 @@ class DeviceTrustInfoEpoxyController @Inject constructor(
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val colorProvider: ColorProvider, private val colorProvider: ColorProvider,
private val dimensionConverter: DimensionConverter, private val dimensionConverter: DimensionConverter,
private val vectorPreferences: VectorPreferences
) : ) :
TypedEpoxyController<DeviceListViewState>() { TypedEpoxyController<DeviceListViewState>() {
interface InteractionListener { interface InteractionListener
fun onVerifyManually(device: CryptoDeviceInfo)
}
var interactionListener: InteractionListener? = null var interactionListener: InteractionListener? = null
@ -54,7 +48,7 @@ class DeviceTrustInfoEpoxyController @Inject constructor(
data?.selectedDevice?.let { cryptoDeviceInfo -> data?.selectedDevice?.let { cryptoDeviceInfo ->
val trustMSK = data.memberCrossSigningKey?.isTrusted().orFalse() val trustMSK = data.memberCrossSigningKey?.isTrusted().orFalse()
val legacyMode = data.memberCrossSigningKey == null val legacyMode = data.memberCrossSigningKey == null
val isMyDevice = data.myDeviceId == cryptoDeviceInfo.deviceId val isMyDevice = data.userId == data.myUserId && data.myDeviceId == cryptoDeviceInfo.deviceId
val trustLevel = TrustUtils.shieldForTrust( val trustLevel = TrustUtils.shieldForTrust(
isMyDevice, isMyDevice,
trustMSK, trustMSK,
@ -126,18 +120,7 @@ class DeviceTrustInfoEpoxyController @Inject constructor(
id("warn") id("warn")
centered(false) centered(false)
textColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary)) textColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
text(host.stringProvider.getString(R.string.verification_profile_device_untrust_info).toEpoxyCharSequence()) text(host.stringProvider.getString(R.string.verification_profile_other_device_untrust_info).toEpoxyCharSequence())
}
bottomSheetVerificationActionItem {
id("verify")
title(host.stringProvider.getString(R.string.cross_signing_verify_by_emoji))
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
iconRes(R.drawable.ic_arrow_right)
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
listener {
host.interactionListener?.onVerifyManually(cryptoDeviceInfo)
}
} }
} }
} }

View File

@ -254,6 +254,8 @@ class VectorPreferences @Inject constructor(
const val TAKE_PHOTO_VIDEO_MODE_PHOTO = 1 const val TAKE_PHOTO_VIDEO_MODE_PHOTO = 1
const val TAKE_PHOTO_VIDEO_MODE_VIDEO = 2 const val TAKE_PHOTO_VIDEO_MODE_VIDEO = 2
const val HAD_EXISTING_LEGACY_DATA = "HAD_EXISTING_LEGACY_DATA"
const val IS_ON_RUST_CRYPTO = "IS_ON_RUST_CRYPTO"
// Background sync modes // Background sync modes
// some preferences keys must be kept after a logout // some preferences keys must be kept after a logout
@ -1278,4 +1280,24 @@ class VectorPreferences @Inject constructor(
putBoolean(SETTINGS_NEW_LOGIN_ALERT_SHOWN_FOR_DEVICE + deviceId, true) putBoolean(SETTINGS_NEW_LOGIN_ALERT_SHOWN_FOR_DEVICE + deviceId, true)
} }
} }
fun hadExistingLegacyData(): Boolean {
return defaultPrefs.getBoolean(HAD_EXISTING_LEGACY_DATA, false)
}
fun setHadExistingLegacyData(had: Boolean) {
defaultPrefs.edit {
putBoolean(HAD_EXISTING_LEGACY_DATA, had)
}
}
fun isOnRustCrypto(): Boolean {
return defaultPrefs.getBoolean(IS_ON_RUST_CRYPTO, false)
}
fun setIsOnRustCrypto(boolean: Boolean) {
defaultPrefs.edit {
putBoolean(IS_ON_RUST_CRYPTO, boolean)
}
}
} }

View File

@ -25,6 +25,8 @@ class GetEncryptionTrustLevelForDeviceUseCase @Inject constructor(
private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase, private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase,
) { ) {
// XXX why is this using the RoomEncryptionTrustLevel?
// should be using a new DeviceTrustShield enum
fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel? { fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel? {
if (cryptoDeviceInfo == null) { if (cryptoDeviceInfo == null) {
return null return null