Merge branch 'develop' into feature/fga/knock_requests_sdk

This commit is contained in:
ganfra 2024-12-18 17:21:16 +01:00
commit 5275a3e5d3
391 changed files with 6199 additions and 1991 deletions

View file

@ -109,9 +109,7 @@ class RustMatrixClientFactory @Inject constructor(
.addRootCertificates(userCertificatesProvider.provides())
.autoEnableBackups(true)
.autoEnableCrossSigning(true)
// TODO Add a feature flag to enable persistent storage
// See https://github.com/matrix-org/matrix-rust-sdk/pull/4396
.useEventCachePersistentStorage(false)
.useEventCachePersistentStorage(featureFlagService.isFeatureEnabled(FeatureFlags.EventCache))
.roomKeyRecipientStrategy(
strategy = if (featureFlagService.isFeatureEnabled(FeatureFlags.OnlySignedDeviceIsolationMode)) {
CollectStrategy.IdentityBasedStrategy

View file

@ -27,7 +27,9 @@ class UtdTracker(
UtdCause.UNKNOWN_DEVICE -> {
Error.Name.ExpectedSentByInsecureDevice
}
UtdCause.HISTORICAL_MESSAGE -> Error.Name.HistoricalMessage
UtdCause.HISTORICAL_MESSAGE_AND_BACKUP_IS_DISABLED,
UtdCause.HISTORICAL_MESSAGE_AND_DEVICE_IS_UNVERIFIED,
-> Error.Name.HistoricalMessage
UtdCause.WITHHELD_FOR_UNVERIFIED_OR_INSECURE_DEVICE -> Error.Name.RoomKeysWithheldForUnverifiedDevice
UtdCause.WITHHELD_BY_SENDER -> Error.Name.OlmKeysNotSentError
}
@ -39,6 +41,10 @@ class UtdTracker(
timeToDecryptMillis = info.timeToDecryptMs?.toInt() ?: -1,
domain = Error.Domain.E2EE,
name = name,
eventLocalAgeMillis = info.eventLocalAgeMillis.toInt(),
userTrustsOwnIdentity = info.userTrustsOwnIdentity,
isFederated = info.ownHomeserver != info.senderHomeserver,
isMatrixDotOrg = info.ownHomeserver == "matrix.org",
)
analyticsService.capture(event)
}

View file

@ -69,6 +69,7 @@ fun RustMembership.map(): CurrentUserMembership = when (this) {
RustMembership.JOINED -> CurrentUserMembership.JOINED
RustMembership.LEFT -> CurrentUserMembership.LEFT
Membership.KNOCKED -> CurrentUserMembership.KNOCKED
RustMembership.BANNED -> CurrentUserMembership.BANNED
}
fun RustRoomNotificationMode.map(): RoomNotificationMode = when (this) {

View file

@ -248,7 +248,7 @@ class RustMatrixRoom(
RoomMessageEventMessageType.VIDEO,
RoomMessageEventMessageType.AUDIO,
),
dateDividerMode = DateDividerMode.DAILY,
dateDividerMode = DateDividerMode.MONTHLY,
).let { inner ->
createTimeline(inner, mode = Timeline.Mode.MEDIA)
}
@ -582,6 +582,12 @@ class RustMatrixRoom(
}
}
override suspend fun clearEventCacheStorage(): Result<Unit> = withContext(roomDispatcher) {
runCatching {
innerRoom.clearEventCacheStorage()
}
}
override suspend fun kickUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
runCatching {
innerRoom.kickUser(userId.value, reason)

View file

@ -7,6 +7,7 @@
package io.element.android.libraries.matrix.impl.roomlist
import io.element.android.libraries.core.extensions.withoutAccents
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
@ -30,7 +31,7 @@ val RoomListFilter.predicate
!roomSummary.isInvited() && (roomSummary.info.numUnreadNotifications > 0 || roomSummary.info.isMarkedUnread)
}
is RoomListFilter.NormalizedMatchRoomName -> { roomSummary: RoomSummary ->
roomSummary.info.name.orEmpty().contains(pattern, ignoreCase = true)
roomSummary.info.name?.withoutAccents().orEmpty().contains(normalizedPattern, ignoreCase = true)
}
RoomListFilter.Invite -> { roomSummary: RoomSummary ->
roomSummary.isInvited()

View file

@ -145,7 +145,8 @@ private fun RustUtdCause.map(): UtdCause {
RustUtdCause.VERIFICATION_VIOLATION -> UtdCause.VerificationViolation
RustUtdCause.UNSIGNED_DEVICE -> UtdCause.UnsignedDevice
RustUtdCause.UNKNOWN_DEVICE -> UtdCause.UnknownDevice
RustUtdCause.HISTORICAL_MESSAGE -> UtdCause.HistoricalMessage
RustUtdCause.HISTORICAL_MESSAGE_AND_BACKUP_IS_DISABLED -> UtdCause.HistoricalMessageAndBackupIsDisabled
RustUtdCause.HISTORICAL_MESSAGE_AND_DEVICE_IS_UNVERIFIED -> UtdCause.HistoricalMessageAndDeviceIsUnverified
RustUtdCause.WITHHELD_FOR_UNVERIFIED_OR_INSECURE_DEVICE -> UtdCause.WithheldUnverifiedOrInsecureDevice
RustUtdCause.WITHHELD_BY_SENDER -> UtdCause.WithheldBySender
}

View file

@ -9,10 +9,10 @@ package io.element.android.libraries.matrix.impl.analytics
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.Error
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustUnableToDecryptInfo
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.services.analytics.test.FakeAnalyticsService
import org.junit.Test
import org.matrix.rustcomponents.sdk.UnableToDecryptInfo
import uniffi.matrix_sdk_crypto.UtdCause
class UtdTrackerTest {
@ -21,10 +21,11 @@ class UtdTrackerTest {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = null,
cause = UtdCause.UNKNOWN,
eventLocalAgeMillis = 100L,
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
@ -34,7 +35,11 @@ class UtdTrackerTest {
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = -1,
domain = Error.Domain.E2EE,
name = Error.Name.OlmKeysNotSentError
name = Error.Name.OlmKeysNotSentError,
isFederated = false,
isMatrixDotOrg = false,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 100,
)
)
assertThat(fakeAnalyticsService.screenEvents).isEmpty()
@ -46,7 +51,7 @@ class UtdTrackerTest {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.UNKNOWN,
@ -59,7 +64,11 @@ class UtdTrackerTest {
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = 123,
domain = Error.Domain.E2EE,
name = Error.Name.OlmKeysNotSentError
name = Error.Name.OlmKeysNotSentError,
isFederated = false,
isMatrixDotOrg = false,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 0,
)
)
assertThat(fakeAnalyticsService.screenEvents).isEmpty()
@ -71,7 +80,7 @@ class UtdTrackerTest {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.SENT_BEFORE_WE_JOINED,
@ -84,7 +93,11 @@ class UtdTrackerTest {
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = 123,
domain = Error.Domain.E2EE,
name = Error.Name.ExpectedDueToMembership
name = Error.Name.ExpectedDueToMembership,
isFederated = false,
isMatrixDotOrg = false,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 0,
)
)
assertThat(fakeAnalyticsService.screenEvents).isEmpty()
@ -96,7 +109,7 @@ class UtdTrackerTest {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.UNSIGNED_DEVICE,
@ -109,7 +122,11 @@ class UtdTrackerTest {
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = 123,
domain = Error.Domain.E2EE,
name = Error.Name.ExpectedSentByInsecureDevice
name = Error.Name.ExpectedSentByInsecureDevice,
isFederated = false,
isMatrixDotOrg = false,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 0,
)
)
}
@ -119,7 +136,7 @@ class UtdTrackerTest {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.VERIFICATION_VIOLATION,
@ -132,7 +149,90 @@ class UtdTrackerTest {
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = 123,
domain = Error.Domain.E2EE,
name = Error.Name.ExpectedVerificationViolation
name = Error.Name.ExpectedVerificationViolation,
isFederated = false,
isMatrixDotOrg = false,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 0,
)
)
}
@Test
fun `when onUtd is called with different sender and receiver servers, the expected analytics Event is sent`() {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
ownHomeserver = "example.com",
senderHomeserver = "matrix.org",
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
Error(
context = null,
cryptoModule = Error.CryptoModule.Rust,
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = -1,
domain = Error.Domain.E2EE,
name = Error.Name.OlmKeysNotSentError,
isFederated = true,
isMatrixDotOrg = false,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 0,
)
)
}
@Test
fun `when onUtd is called from a matrix-org user, the expected analytics Event is sent`() {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
ownHomeserver = "matrix.org",
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
Error(
context = null,
cryptoModule = Error.CryptoModule.Rust,
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = -1,
domain = Error.Domain.E2EE,
name = Error.Name.OlmKeysNotSentError,
isFederated = true,
isMatrixDotOrg = true,
userTrustsOwnIdentity = false,
eventLocalAgeMillis = 0,
)
)
}
@Test
fun `when onUtd is called from a verified device, the expected analytics Event is sent`() {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
aRustUnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
userTrustsOwnIdentity = true,
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
Error(
context = null,
cryptoModule = Error.CryptoModule.Rust,
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = -1,
domain = Error.Domain.E2EE,
name = Error.Name.OlmKeysNotSentError,
isFederated = false,
isMatrixDotOrg = false,
userTrustsOwnIdentity = true,
eventLocalAgeMillis = 0,
)
)
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.fixtures.factories
import org.matrix.rustcomponents.sdk.UnableToDecryptInfo
import uniffi.matrix_sdk_crypto.UtdCause
internal fun aRustUnableToDecryptInfo(
eventId: String,
timeToDecryptMs: ULong? = null,
cause: UtdCause = UtdCause.UNKNOWN,
eventLocalAgeMillis: Long = 0L,
userTrustsOwnIdentity: Boolean = false,
senderHomeserver: String = "",
ownHomeserver: String = "",
): UnableToDecryptInfo {
return UnableToDecryptInfo(
eventId = eventId,
timeToDecryptMs = timeToDecryptMs,
cause = cause,
eventLocalAgeMillis = eventLocalAgeMillis,
userTrustsOwnIdentity = userTrustsOwnIdentity,
senderHomeserver = senderHomeserver,
ownHomeserver = ownHomeserver,
)
}

View file

@ -34,6 +34,9 @@ class RoomListFilterTest {
private val roomToSearch = aRoomSummary(
name = "Room to search"
)
private val roomWithAccent = aRoomSummary(
name = "Frédéric"
)
private val invitedRoom = aRoomSummary(
currentUserMembership = CurrentUserMembership.INVITED
)
@ -45,6 +48,7 @@ class RoomListFilterTest {
markedAsUnreadRoom,
unreadNotificationRoom,
roomToSearch,
roomWithAccent,
invitedRoom
)
@ -69,7 +73,14 @@ class RoomListFilterTest {
@Test
fun `Room list filter group`() = runTest {
val filter = RoomListFilter.Category.Group
assertThat(roomSummaries.filter(filter)).containsExactly(regularRoom, favoriteRoom, markedAsUnreadRoom, unreadNotificationRoom, roomToSearch)
assertThat(roomSummaries.filter(filter)).containsExactly(
regularRoom,
favoriteRoom,
markedAsUnreadRoom,
unreadNotificationRoom,
roomToSearch,
roomWithAccent,
)
}
@Test
@ -96,6 +107,18 @@ class RoomListFilterTest {
assertThat(roomSummaries.filter(filter)).containsExactly(roomToSearch)
}
@Test
fun `Room list filter normalized match room name with accent`() = runTest {
val filter = RoomListFilter.NormalizedMatchRoomName("Fred")
assertThat(roomSummaries.filter(filter)).containsExactly(roomWithAccent)
}
@Test
fun `Room list filter normalized match room name with accent when searching with accent`() = runTest {
val filter = RoomListFilter.NormalizedMatchRoomName("Fréd")
assertThat(roomSummaries.filter(filter)).containsExactly(roomWithAccent)
}
@Test
fun `Room list filter all with one match`() = runTest {
val filter = RoomListFilter.all(