Skip to content

Commit

Permalink
Merge pull request #3729 from element-hq/feature/valere/support_new_u…
Browse files Browse the repository at this point in the history
…td_causes

Trust & Decoration | Support new expected UTD causes
  • Loading branch information
BillCarsonFr authored Oct 24, 2024
2 parents 59c92ed + c82357c commit f30a860
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -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)
),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,28 @@ fun TimelineItemEncryptedView(
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
modifier: Modifier = Modifier
) {
val isMembershipUtd = (content.data as? UnableToDecryptContent.Data.MegolmV1AesSha2)?.utdCause == UtdCause.Membership
val (textId, iconId) = if (isMembershipUtd) {
CommonStrings.common_unable_to_decrypt_no_access to CompoundDrawables.ic_compound_block
} else {
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
val (textId, iconId) = when (content.data) {
is UnableToDecryptContent.Data.MegolmV1AesSha2 -> {
when (content.data.utdCause) {
UtdCause.SentBeforeWeJoined -> {
CommonStrings.common_unable_to_decrypt_no_access to CompoundDrawables.ic_compound_block
}
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
}
}
}
else -> {
// Should not happen, we only supports megolm in rooms
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
}
}
TimelineItemInformativeView(
text = stringResource(id = textId),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ open class TimelineItemEncryptedContentProvider : PreviewParameterProvider<Timel
aTimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
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(
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ zxing_cpp = "io.github.zxing-cpp:android:2.2.0"
posthog = "com.posthog:posthog-android:3.8.2"
sentry = "io.sentry:sentry-android:7.15.0"
# 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
matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ package io.element.android.libraries.matrix.api.timeline.item.event

enum class UtdCause {
Unknown,
Membership,
SentBeforeWeJoined,
VerificationViolation,
UnsignedDevice,
UnknownDevice
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ class UtdTracker(
Timber.d("onUtd for event ${info.eventId}, timeToDecryptMs: ${info.timeToDecryptMs}")
val name = when (info.cause) {
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(
context = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,11 @@ private fun RustMembershipChange.map(): MembershipChange {

private fun RustUtdCause.map(): UtdCause {
return when (this) {
RustUtdCause.MEMBERSHIP -> UtdCause.Membership
RustUtdCause.SENT_BEFORE_WE_JOINED -> UtdCause.SentBeforeWeJoined
RustUtdCause.UNKNOWN -> UtdCause.Unknown
RustUtdCause.VERIFICATION_VIOLATION -> UtdCause.VerificationViolation
RustUtdCause.UNSIGNED_DEVICE -> UtdCause.UnsignedDevice
RustUtdCause.UNKNOWN_DEVICE -> UtdCause.UnknownDevice
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class UtdTrackerTest {
UnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.MEMBERSHIP,
cause = UtdCause.SENT_BEFORE_WE_JOINED,
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
Expand All @@ -90,4 +90,50 @@ class UtdTrackerTest {
assertThat(fakeAnalyticsService.screenEvents).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
)
)
}
}
2 changes: 2 additions & 0 deletions libraries/ui-strings/src/main/res/values/localazy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ Reason: %1$s."</string>
<string name="common_topic">"Topic"</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_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_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_title">"Unable to send invite(s)"</string>
<string name="common_unlock">"Unlock"</string>
Expand Down

0 comments on commit f30a860

Please sign in to comment.