Bump rust-sdk version to rust-sdk 0.2.57 (#3735)
* Bump rust-sdk version to rust-sdk 0.2.57 * rust sdk update: Support persisted WedgeQueueError * Trust & Decoration | Support new expected UTD causes * Room Subscribtion settings not needed anymore (see https://github.com/matrix-org/matrix-rust-sdk/pull/4159) * File/Attachement upload: update to support `storeInCache` * feat(knock): update API to use reason and serverNames * Add another `Konsist` exception * Update screenshots --------- Co-authored-by: Jorge Martín <jorgem@element.io> Co-authored-by: ElementBot <android@element.io> Co-authored-by: Benoit Marty <benoit@matrix.org>
This commit is contained in:
parent
6dd73b9578
commit
371799fdad
23 changed files with 223 additions and 58 deletions
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.features.messages.impl.timeline.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||||
|
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.UtdCause
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun TimelineItemEventRowUtdPreview() = ElementPreview {
|
||||||
|
Column {
|
||||||
|
ATimelineItemEventRow(
|
||||||
|
event = aTimelineItemEvent(
|
||||||
|
senderDisplayName = "Alice",
|
||||||
|
isMine = false,
|
||||||
|
content = TimelineItemEncryptedContent(
|
||||||
|
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
||||||
|
sessionId = "sessionId",
|
||||||
|
utdCause = UtdCause.UnsignedDevice,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
timelineItemReactions = aTimelineItemReactions(count = 0),
|
||||||
|
groupPosition = TimelineItemGroupPosition.First,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ATimelineItemEventRow(
|
||||||
|
event = aTimelineItemEvent(
|
||||||
|
senderDisplayName = "Bob",
|
||||||
|
isMine = false,
|
||||||
|
content = TimelineItemEncryptedContent(
|
||||||
|
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
||||||
|
sessionId = "sessionId",
|
||||||
|
utdCause = UtdCause.VerificationViolation,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
groupPosition = TimelineItemGroupPosition.First,
|
||||||
|
timelineItemReactions = aTimelineItemReactions(count = 0)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
ATimelineItemEventRow(
|
||||||
|
event = aTimelineItemEvent(
|
||||||
|
senderDisplayName = "Bob",
|
||||||
|
isMine = false,
|
||||||
|
content = TimelineItemEncryptedContent(
|
||||||
|
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
||||||
|
sessionId = "sessionId",
|
||||||
|
utdCause = UtdCause.SentBeforeWeJoined,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
groupPosition = TimelineItemGroupPosition.Last,
|
||||||
|
timelineItemReactions = aTimelineItemReactions(count = 0)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,12 +27,29 @@ fun TimelineItemEncryptedView(
|
||||||
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
|
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val isMembershipUtd = (content.data as? UnableToDecryptContent.Data.MegolmV1AesSha2)?.utdCause == UtdCause.Membership
|
val (textId, iconId) = when (content.data) {
|
||||||
val (textId, iconId) = if (isMembershipUtd) {
|
is UnableToDecryptContent.Data.MegolmV1AesSha2 -> {
|
||||||
|
when (content.data.utdCause) {
|
||||||
|
UtdCause.SentBeforeWeJoined -> {
|
||||||
CommonStrings.common_unable_to_decrypt_no_access to CompoundDrawables.ic_compound_block
|
CommonStrings.common_unable_to_decrypt_no_access to CompoundDrawables.ic_compound_block
|
||||||
} else {
|
}
|
||||||
|
UtdCause.VerificationViolation -> {
|
||||||
|
CommonStrings.common_unable_to_decrypt_verification_violation to CompoundDrawables.ic_compound_block
|
||||||
|
}
|
||||||
|
UtdCause.UnsignedDevice,
|
||||||
|
UtdCause.UnknownDevice -> {
|
||||||
|
CommonStrings.common_unable_to_decrypt_insecure_device to CompoundDrawables.ic_compound_block
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
|
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// Should not happen, we only supports megolm in rooms
|
||||||
|
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
|
||||||
|
}
|
||||||
|
}
|
||||||
TimelineItemInformativeView(
|
TimelineItemInformativeView(
|
||||||
text = stringResource(id = textId),
|
text = stringResource(id = textId),
|
||||||
iconDescription = stringResource(id = CommonStrings.dialog_title_warning),
|
iconDescription = stringResource(id = CommonStrings.dialog_title_warning),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,19 @@ open class TimelineItemEncryptedContentProvider : PreviewParameterProvider<Timel
|
||||||
aTimelineItemEncryptedContent(
|
aTimelineItemEncryptedContent(
|
||||||
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
||||||
sessionId = "sessionId",
|
sessionId = "sessionId",
|
||||||
utdCause = UtdCause.Membership,
|
utdCause = UtdCause.SentBeforeWeJoined,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
aTimelineItemEncryptedContent(
|
||||||
|
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
||||||
|
sessionId = "sessionId",
|
||||||
|
utdCause = UtdCause.VerificationViolation,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
aTimelineItemEncryptedContent(
|
||||||
|
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
|
||||||
|
sessionId = "sessionId",
|
||||||
|
utdCause = UtdCause.UnsignedDevice,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
aTimelineItemEncryptedContent(
|
aTimelineItemEncryptedContent(
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
|
||||||
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
||||||
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
|
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
|
||||||
timber = "com.jakewharton.timber:timber:5.0.1"
|
timber = "com.jakewharton.timber:timber:5.0.1"
|
||||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.56"
|
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.57"
|
||||||
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
||||||
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
||||||
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||||
|
|
@ -193,7 +193,7 @@ zxing_cpp = "io.github.zxing-cpp:android:2.2.0"
|
||||||
posthog = "com.posthog:posthog-android:3.8.2"
|
posthog = "com.posthog:posthog-android:3.8.2"
|
||||||
sentry = "io.sentry:sentry-android:7.15.0"
|
sentry = "io.sentry:sentry-android:7.15.0"
|
||||||
# main branch can be tested replacing the version with main-SNAPSHOT
|
# main branch can be tested replacing the version with main-SNAPSHOT
|
||||||
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.25.0"
|
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.27.0"
|
||||||
|
|
||||||
# Emojibase
|
# Emojibase
|
||||||
matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3"
|
matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3"
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ sealed interface LocalEventSendState {
|
||||||
data object Sending : LocalEventSendState
|
data object Sending : LocalEventSendState
|
||||||
sealed interface Failed : LocalEventSendState {
|
sealed interface Failed : LocalEventSendState {
|
||||||
data class Unknown(val error: String) : Failed
|
data class Unknown(val error: String) : Failed
|
||||||
data object CrossSigningNotSetup : Failed
|
|
||||||
data object SendingFromUnverifiedDevice : Failed
|
data object SendingFromUnverifiedDevice : Failed
|
||||||
|
|
||||||
sealed interface VerifiedUser : Failed
|
sealed interface VerifiedUser : Failed
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,8 @@ package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
enum class UtdCause {
|
enum class UtdCause {
|
||||||
Unknown,
|
Unknown,
|
||||||
Membership,
|
SentBeforeWeJoined,
|
||||||
|
VerificationViolation,
|
||||||
|
UnsignedDevice,
|
||||||
|
UnknownDevice
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ class RustMatrixClient(
|
||||||
sessionDispatcher
|
sessionDispatcher
|
||||||
) {
|
) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.knock(roomIdOrAlias.identifier).destroy()
|
client.knock(roomIdOrAlias.identifier, message, serverNames).destroy()
|
||||||
try {
|
try {
|
||||||
awaitRoom(roomIdOrAlias, 10.seconds, CurrentUserMembership.KNOCKED)
|
awaitRoom(roomIdOrAlias, 10.seconds, CurrentUserMembership.KNOCKED)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,12 @@ class UtdTracker(
|
||||||
Timber.d("onUtd for event ${info.eventId}, timeToDecryptMs: ${info.timeToDecryptMs}")
|
Timber.d("onUtd for event ${info.eventId}, timeToDecryptMs: ${info.timeToDecryptMs}")
|
||||||
val name = when (info.cause) {
|
val name = when (info.cause) {
|
||||||
UtdCause.UNKNOWN -> Error.Name.OlmKeysNotSentError
|
UtdCause.UNKNOWN -> Error.Name.OlmKeysNotSentError
|
||||||
UtdCause.MEMBERSHIP -> Error.Name.ExpectedDueToMembership
|
UtdCause.SENT_BEFORE_WE_JOINED -> Error.Name.ExpectedDueToMembership
|
||||||
|
UtdCause.VERIFICATION_VIOLATION -> Error.Name.ExpectedVerificationViolation
|
||||||
|
UtdCause.UNSIGNED_DEVICE,
|
||||||
|
UtdCause.UNKNOWN_DEVICE -> {
|
||||||
|
Error.Name.ExpectedSentByInsecureDevice
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val event = Error(
|
val event = Error(
|
||||||
context = null,
|
context = null,
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,13 @@ package io.element.android.libraries.matrix.impl.room
|
||||||
|
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.RequiredState
|
|
||||||
import org.matrix.rustcomponents.sdk.RoomListService
|
import org.matrix.rustcomponents.sdk.RoomListService
|
||||||
import org.matrix.rustcomponents.sdk.RoomSubscription
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
private const val DEFAULT_TIMELINE_LIMIT = 20u
|
|
||||||
|
|
||||||
class RoomSyncSubscriber(
|
class RoomSyncSubscriber(
|
||||||
private val roomListService: RoomListService,
|
private val roomListService: RoomListService,
|
||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
|
|
@ -28,28 +23,13 @@ class RoomSyncSubscriber(
|
||||||
private val subscribedRoomIds = mutableSetOf<RoomId>()
|
private val subscribedRoomIds = mutableSetOf<RoomId>()
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
private val settings = RoomSubscription(
|
|
||||||
requiredState = listOf(
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_NAME, value = ""),
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_TOPIC, value = ""),
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_AVATAR, value = ""),
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_CANONICAL_ALIAS, value = ""),
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_JOIN_RULES, value = ""),
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_POWER_LEVELS, value = ""),
|
|
||||||
RequiredState(key = EventType.STATE_ROOM_PINNED_EVENT, value = ""),
|
|
||||||
),
|
|
||||||
timelineLimit = DEFAULT_TIMELINE_LIMIT,
|
|
||||||
// We don't need heroes here as they're already included in the `all_rooms` list
|
|
||||||
includeHeroes = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
suspend fun subscribe(roomId: RoomId) {
|
suspend fun subscribe(roomId: RoomId) {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
withContext(dispatchers.io) {
|
withContext(dispatchers.io) {
|
||||||
try {
|
try {
|
||||||
if (!isSubscribedTo(roomId)) {
|
if (!isSubscribedTo(roomId)) {
|
||||||
Timber.d("Subscribing to room $roomId}")
|
Timber.d("Subscribing to room $roomId}")
|
||||||
roomListService.subscribeToRooms(listOf(roomId.value), settings)
|
roomListService.subscribeToRooms(listOf(roomId.value))
|
||||||
}
|
}
|
||||||
subscribedRoomIds.add(roomId)
|
subscribedRoomIds.add(roomId)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
@ -65,7 +45,7 @@ class RoomSyncSubscriber(
|
||||||
val roomIdsToSubscribeTo = roomIds.filterNot { isSubscribedTo(it) }
|
val roomIdsToSubscribeTo = roomIds.filterNot { isSubscribedTo(it) }
|
||||||
if (roomIdsToSubscribeTo.isNotEmpty()) {
|
if (roomIdsToSubscribeTo.isNotEmpty()) {
|
||||||
Timber.d("Subscribing to rooms: $roomIds")
|
Timber.d("Subscribing to rooms: $roomIds")
|
||||||
roomListService.subscribeToRooms(roomIdsToSubscribeTo.map { it.value }, settings)
|
roomListService.subscribeToRooms(roomIdsToSubscribeTo.map { it.value })
|
||||||
subscribedRoomIds.addAll(roomIds)
|
subscribedRoomIds.addAll(roomIds)
|
||||||
}
|
}
|
||||||
} catch (cancellationException: CancellationException) {
|
} catch (cancellationException: CancellationException) {
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,7 @@ class RustTimeline(
|
||||||
formattedCaption = formattedBody?.let {
|
formattedCaption = formattedBody?.let {
|
||||||
FormattedBody(body = it, format = MessageFormat.Html)
|
FormattedBody(body = it, format = MessageFormat.Html)
|
||||||
},
|
},
|
||||||
|
storeInCache = true,
|
||||||
progressWatcher = progressCallback?.toProgressWatcher()
|
progressWatcher = progressCallback?.toProgressWatcher()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -361,6 +362,7 @@ class RustTimeline(
|
||||||
formattedCaption = formattedBody?.let {
|
formattedCaption = formattedBody?.let {
|
||||||
FormattedBody(body = it, format = MessageFormat.Html)
|
FormattedBody(body = it, format = MessageFormat.Html)
|
||||||
},
|
},
|
||||||
|
storeInCache = true,
|
||||||
progressWatcher = progressCallback?.toProgressWatcher()
|
progressWatcher = progressCallback?.toProgressWatcher()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -374,6 +376,7 @@ class RustTimeline(
|
||||||
// Maybe allow a caption in the future?
|
// Maybe allow a caption in the future?
|
||||||
caption = null,
|
caption = null,
|
||||||
formattedCaption = null,
|
formattedCaption = null,
|
||||||
|
storeInCache = true,
|
||||||
progressWatcher = progressCallback?.toProgressWatcher()
|
progressWatcher = progressCallback?.toProgressWatcher()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +384,7 @@ class RustTimeline(
|
||||||
|
|
||||||
override suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
|
override suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
|
||||||
return sendAttachment(listOf(file)) {
|
return sendAttachment(listOf(file)) {
|
||||||
inner.sendFile(file.path, fileInfo.map(), progressCallback?.toProgressWatcher())
|
inner.sendFile(file.path, fileInfo.map(), false, progressCallback?.toProgressWatcher())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,6 +499,7 @@ class RustTimeline(
|
||||||
// Maybe allow a caption in the future?
|
// Maybe allow a caption in the future?
|
||||||
caption = null,
|
caption = null,
|
||||||
formattedCaption = null,
|
formattedCaption = null,
|
||||||
|
storeInCache = true,
|
||||||
progressWatcher = progressCallback?.toProgressWatcher(),
|
progressWatcher = progressCallback?.toProgressWatcher(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import org.matrix.rustcomponents.sdk.EventOrTransactionId
|
import org.matrix.rustcomponents.sdk.EventOrTransactionId
|
||||||
import org.matrix.rustcomponents.sdk.EventSendState
|
import org.matrix.rustcomponents.sdk.QueueWedgeError
|
||||||
import org.matrix.rustcomponents.sdk.Reaction
|
import org.matrix.rustcomponents.sdk.Reaction
|
||||||
import org.matrix.rustcomponents.sdk.ShieldState
|
import org.matrix.rustcomponents.sdk.ShieldState
|
||||||
import uniffi.matrix_sdk_common.ShieldStateCode
|
import uniffi.matrix_sdk_common.ShieldStateCode
|
||||||
|
|
@ -78,25 +78,31 @@ fun RustEventSendState?.map(): LocalEventSendState? {
|
||||||
null -> null
|
null -> null
|
||||||
RustEventSendState.NotSentYet -> LocalEventSendState.Sending
|
RustEventSendState.NotSentYet -> LocalEventSendState.Sending
|
||||||
is RustEventSendState.SendingFailed -> {
|
is RustEventSendState.SendingFailed -> {
|
||||||
if (isRecoverable) {
|
when (val queueWedgeError = error) {
|
||||||
LocalEventSendState.Sending
|
QueueWedgeError.CrossVerificationRequired -> {
|
||||||
} else {
|
// The current device is not cross-signed (or cross signing is not setup)
|
||||||
LocalEventSendState.Failed.Unknown(error)
|
LocalEventSendState.Failed.SendingFromUnverifiedDevice
|
||||||
}
|
}
|
||||||
|
is QueueWedgeError.IdentityViolations -> {
|
||||||
|
LocalEventSendState.Failed.VerifiedUserChangedIdentity(queueWedgeError.users.map { UserId(it) })
|
||||||
}
|
}
|
||||||
is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId))
|
is QueueWedgeError.InsecureDevices -> {
|
||||||
is RustEventSendState.VerifiedUserChangedIdentity -> {
|
|
||||||
LocalEventSendState.Failed.VerifiedUserChangedIdentity(users.map { UserId(it) })
|
|
||||||
}
|
|
||||||
is RustEventSendState.VerifiedUserHasUnsignedDevice -> {
|
|
||||||
LocalEventSendState.Failed.VerifiedUserHasUnsignedDevice(
|
LocalEventSendState.Failed.VerifiedUserHasUnsignedDevice(
|
||||||
devices = devices.entries.associate { entry ->
|
devices = queueWedgeError.userDeviceMap.entries.associate { entry ->
|
||||||
UserId(entry.key) to entry.value.map { DeviceId(it) }
|
UserId(entry.key) to entry.value.map { DeviceId(it) }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
EventSendState.CrossSigningNotSetup -> LocalEventSendState.Failed.CrossSigningNotSetup
|
is QueueWedgeError.GenericApiError -> {
|
||||||
EventSendState.SendingFromUnverifiedDevice -> LocalEventSendState.Failed.SendingFromUnverifiedDevice
|
if (isRecoverable) {
|
||||||
|
LocalEventSendState.Sending
|
||||||
|
} else {
|
||||||
|
LocalEventSendState.Failed.Unknown(queueWedgeError.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,11 @@ private fun RustMembershipChange.map(): MembershipChange {
|
||||||
|
|
||||||
private fun RustUtdCause.map(): UtdCause {
|
private fun RustUtdCause.map(): UtdCause {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
RustUtdCause.MEMBERSHIP -> UtdCause.Membership
|
RustUtdCause.SENT_BEFORE_WE_JOINED -> UtdCause.SentBeforeWeJoined
|
||||||
RustUtdCause.UNKNOWN -> UtdCause.Unknown
|
RustUtdCause.UNKNOWN -> UtdCause.Unknown
|
||||||
|
RustUtdCause.VERIFICATION_VIOLATION -> UtdCause.VerificationViolation
|
||||||
|
RustUtdCause.UNSIGNED_DEVICE -> UtdCause.UnsignedDevice
|
||||||
|
RustUtdCause.UNKNOWN_DEVICE -> UtdCause.UnknownDevice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class UtdTrackerTest {
|
||||||
UnableToDecryptInfo(
|
UnableToDecryptInfo(
|
||||||
eventId = AN_EVENT_ID.value,
|
eventId = AN_EVENT_ID.value,
|
||||||
timeToDecryptMs = 123.toULong(),
|
timeToDecryptMs = 123.toULong(),
|
||||||
cause = UtdCause.MEMBERSHIP,
|
cause = UtdCause.SENT_BEFORE_WE_JOINED,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
|
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
|
||||||
|
|
@ -90,4 +90,50 @@ class UtdTrackerTest {
|
||||||
assertThat(fakeAnalyticsService.screenEvents).isEmpty()
|
assertThat(fakeAnalyticsService.screenEvents).isEmpty()
|
||||||
assertThat(fakeAnalyticsService.trackedErrors).isEmpty()
|
assertThat(fakeAnalyticsService.trackedErrors).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when onUtd is called with insecure cause, the expected analytics Event is sent`() {
|
||||||
|
val fakeAnalyticsService = FakeAnalyticsService()
|
||||||
|
val sut = UtdTracker(fakeAnalyticsService)
|
||||||
|
sut.onUtd(
|
||||||
|
UnableToDecryptInfo(
|
||||||
|
eventId = AN_EVENT_ID.value,
|
||||||
|
timeToDecryptMs = 123.toULong(),
|
||||||
|
cause = UtdCause.UNSIGNED_DEVICE,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
|
||||||
|
Error(
|
||||||
|
context = null,
|
||||||
|
cryptoModule = Error.CryptoModule.Rust,
|
||||||
|
cryptoSDK = Error.CryptoSDK.Rust,
|
||||||
|
timeToDecryptMillis = 123,
|
||||||
|
domain = Error.Domain.E2EE,
|
||||||
|
name = Error.Name.ExpectedSentByInsecureDevice
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when onUtd is called with verification violation cause, the expected analytics Event is sent`() {
|
||||||
|
val fakeAnalyticsService = FakeAnalyticsService()
|
||||||
|
val sut = UtdTracker(fakeAnalyticsService)
|
||||||
|
sut.onUtd(
|
||||||
|
UnableToDecryptInfo(
|
||||||
|
eventId = AN_EVENT_ID.value,
|
||||||
|
timeToDecryptMs = 123.toULong(),
|
||||||
|
cause = UtdCause.VERIFICATION_VIOLATION,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
|
||||||
|
Error(
|
||||||
|
context = null,
|
||||||
|
cryptoModule = Error.CryptoModule.Rust,
|
||||||
|
cryptoSDK = Error.CryptoSDK.Rust,
|
||||||
|
timeToDecryptMillis = 123,
|
||||||
|
domain = Error.Domain.E2EE,
|
||||||
|
name = Error.Name.ExpectedVerificationViolation
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,9 @@ Reason: %1$s."</string>
|
||||||
<string name="common_topic">"Topic"</string>
|
<string name="common_topic">"Topic"</string>
|
||||||
<string name="common_topic_placeholder">"What is this room about?"</string>
|
<string name="common_topic_placeholder">"What is this room about?"</string>
|
||||||
<string name="common_unable_to_decrypt">"Unable to decrypt"</string>
|
<string name="common_unable_to_decrypt">"Unable to decrypt"</string>
|
||||||
|
<string name="common_unable_to_decrypt_insecure_device">"Sent from an insecure device"</string>
|
||||||
<string name="common_unable_to_decrypt_no_access">"You don\'t have access to this message"</string>
|
<string name="common_unable_to_decrypt_no_access">"You don\'t have access to this message"</string>
|
||||||
|
<string name="common_unable_to_decrypt_verification_violation">"Sender\'s verified identity has changed"</string>
|
||||||
<string name="common_unable_to_invite_message">"Invites couldn\'t be sent to one or more users."</string>
|
<string name="common_unable_to_invite_message">"Invites couldn\'t be sent to one or more users."</string>
|
||||||
<string name="common_unable_to_invite_title">"Unable to send invite(s)"</string>
|
<string name="common_unable_to_invite_title">"Unable to send invite(s)"</string>
|
||||||
<string name="common_unlock">"Unlock"</string>
|
<string name="common_unlock">"Unlock"</string>
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ class KonsistPreviewTest {
|
||||||
"TimelineItemEventRowForDirectRoomPreview",
|
"TimelineItemEventRowForDirectRoomPreview",
|
||||||
"TimelineItemEventRowShieldPreview",
|
"TimelineItemEventRowShieldPreview",
|
||||||
"TimelineItemEventRowTimestampPreview",
|
"TimelineItemEventRowTimestampPreview",
|
||||||
|
"TimelineItemEventRowUtdPreview",
|
||||||
"TimelineItemEventRowWithManyReactionsPreview",
|
"TimelineItemEventRowWithManyReactionsPreview",
|
||||||
"TimelineItemEventRowWithRRPreview",
|
"TimelineItemEventRowWithRRPreview",
|
||||||
"TimelineItemEventRowWithReplyPreview",
|
"TimelineItemEventRowWithReplyPreview",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:fee2af8462597d58274b7168c5cfe1f6d6b0909b048adc0f4fc5b3c12a90b859
|
oid sha256:cfc3dc1420a58d25b5fd248f0b77c3c336bb03c402c904d0678c35a5abe291f2
|
||||||
size 8861
|
size 10753
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:8beabd7aadf0324e9b66278c49fdd896b1451a805fd15e69aa6c4af37cb7c150
|
||||||
|
size 9055
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:fee2af8462597d58274b7168c5cfe1f6d6b0909b048adc0f4fc5b3c12a90b859
|
||||||
|
size 8861
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d4f48cd7dc7e2bbf7363d1127e46721c25bb8dd887927dbcffe525f5bb5bae01
|
oid sha256:d4d9879eda9ffa9c171c5351d9ef8e7b32cad50996717445c9b87cdad8a3d973
|
||||||
size 8781
|
size 10634
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:077f898ad7822b6a5ff54429bc91e4faef377fb06de28a4cea73483e6adc5ffd
|
||||||
|
size 9025
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:d4f48cd7dc7e2bbf7363d1127e46721c25bb8dd887927dbcffe525f5bb5bae01
|
||||||
|
size 8781
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b1f04171ef894f299b58cc15158daf9655cc04f9ab2418973e7e6e78e22884e8
|
||||||
|
size 31693
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:8ce15bbbb3bc562f92a7d07a0f2f907d4e351e0b7133a61b7ef49540ef622c15
|
||||||
|
size 30613
|
||||||
Loading…
Add table
Add a link
Reference in a new issue