diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationCancelContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationCancelContent.kt index 2070845f46..fe2c958703 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationCancelContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationCancelContent.kt @@ -24,7 +24,7 @@ import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultC import im.vector.matrix.android.internal.crypto.verification.VerificationInfoCancel @JsonClass(generateAdapter = true) -internal data class MessageVerificationCancelContent( +data class MessageVerificationCancelContent( @Json(name = "code") override val code: String? = null, @Json(name = "reason") override val reason: String? = null, @Json(name = "m.relates_to") val relatesTo: RelationDefaultContent? diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt index 5c38fcf797..bdf4b400ef 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.crypto.MXCryptoError +import im.vector.matrix.android.api.session.crypto.sas.CancelCode import im.vector.matrix.android.api.session.events.model.* import im.vector.matrix.android.api.session.room.model.ReferencesAggregatedContent import im.vector.matrix.android.api.session.room.model.message.MessageContent @@ -52,6 +53,9 @@ enum class VerificationState { DONE } +fun VerificationState.isCanceled() : Boolean { + return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER +} /** * Called by EventRelationAggregationUpdater, when new events that can affect relations are inserted in base. */ @@ -438,26 +442,27 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( ?: ReferencesAggregatedContent(VerificationState.REQUEST.name) // TODO ignore invalid messages? e.g a START after a CANCEL? // i.e. never change state if already canceled/done + val currentState = VerificationState.values().firstOrNull { data.verificationSummary == it.name } val newState = when (event.getClearType()) { EventType.KEY_VERIFICATION_START -> { - VerificationState.WAITING + updateVerificationState(currentState, VerificationState.WAITING) } EventType.KEY_VERIFICATION_ACCEPT -> { - VerificationState.WAITING + updateVerificationState(currentState, VerificationState.WAITING) } EventType.KEY_VERIFICATION_KEY -> { - VerificationState.WAITING + updateVerificationState(currentState, VerificationState.WAITING) } EventType.KEY_VERIFICATION_MAC -> { - VerificationState.WAITING + updateVerificationState(currentState, VerificationState.WAITING) } EventType.KEY_VERIFICATION_CANCEL -> { - if (event.senderId == userId) { + updateVerificationState(currentState, if (event.senderId == userId) { VerificationState.CANCELED_BY_ME - } else VerificationState.CANCELED_BY_OTHER + } else VerificationState.CANCELED_BY_OTHER) } EventType.KEY_VERIFICATION_DONE -> { - VerificationState.DONE + updateVerificationState(currentState, VerificationState.DONE) } else -> VerificationState.REQUEST } @@ -475,4 +480,18 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( verifSummary.sourceEvents.add(event.eventId) } } + + private fun updateVerificationState(oldState: VerificationState?, newState: VerificationState) : VerificationState{ + // Cancel is always prioritary ? + // Eg id i found that mac or keys mismatch and send a cancel and the other send a done, i have to + // consider as canceled + if (newState == VerificationState.CANCELED_BY_OTHER || newState == VerificationState.CANCELED_BY_ME) { + return newState + } + //never move out of cancel + if (oldState == VerificationState.CANCELED_BY_OTHER || oldState == VerificationState.CANCELED_BY_ME) { + return oldState + } + return newState + } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index 3b0c2c2bb7..6d1ce2cf2a 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -67,13 +67,13 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me } EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_START, - EventType.KEY_VERIFICATION_CANCEL, EventType.KEY_VERIFICATION_KEY, EventType.KEY_VERIFICATION_MAC -> { // These events are filtered from timeline in normal case // Only visible in developer mode noticeItemFactory.create(event, highlight, callback) } + EventType.KEY_VERIFICATION_CANCEL, EventType.KEY_VERIFICATION_DONE -> { verificationConclusionItemFactory.create(event, highlight, callback) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/VerificationItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/VerificationItemFactory.kt index 56284b6777..beeb33b989 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/VerificationItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/VerificationItemFactory.kt @@ -16,13 +16,17 @@ package im.vector.riotx.features.home.room.detail.timeline.factory 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.safeValueOf import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.RelationType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.message.MessageRelationContent +import im.vector.matrix.android.api.session.room.model.message.MessageVerificationCancelContent import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.session.room.VerificationState +import im.vector.matrix.android.internal.session.room.isCanceled import im.vector.riotx.core.epoxy.VectorEpoxyModel import im.vector.riotx.core.resources.ColorProvider import im.vector.riotx.core.resources.UserPreferencesProvider @@ -70,15 +74,52 @@ class VerificationItemFactory @Inject constructor( // If it's not a request ignore this event if (refEvent.root.getClearContent().toModel() == null) return ignoredConclusion(event, highlight, callback) - // Is the request referenced is actually really completed? val referenceInformationData = messageInformationDataFactory.create(refEvent, null) - if (referenceInformationData.referencesInfoData?.verificationStatus != VerificationState.DONE) return ignoredConclusion(event, highlight, callback) val informationData = messageInformationDataFactory.create(event, null) val attributes = messageItemAttributesFactory.create(null, informationData, callback) when (event.root.getClearType()) { + EventType.KEY_VERIFICATION_CANCEL -> { + // Is the request referenced is actually really cancelled? + // if (referenceInformationData.referencesInfoData?.verificationStatus?.isCanceled() == false) return ignoredConclusion(event, highlight, callback) + + val cancelContent = event.root.getClearContent().toModel() + ?: return ignoredConclusion(event, highlight, callback) + + when (safeValueOf(cancelContent.code)) { + CancelCode.MismatchedCommitment, + CancelCode.MismatchedKeys, + CancelCode.MismatchedSas -> { + //We should display these bad conclusions + return VerificationRequestConclusionItem_() + .attributes( + VerificationRequestConclusionItem.Attributes( + toUserId = informationData.senderId, + toUserName = informationData.memberName.toString(), + isPositive = false, + informationData = informationData, + avatarRenderer = attributes.avatarRenderer, + colorProvider = colorProvider, + emojiTypeFace = attributes.emojiTypeFace, + itemClickListener = attributes.itemClickListener, + itemLongClickListener = attributes.itemLongClickListener, + reactionPillCallback = attributes.reactionPillCallback, + readReceiptsCallback = attributes.readReceiptsCallback + ) + ) + .highlighted(highlight) + .leftGuideline(avatarSizeProvider.leftGuideline) + } + else -> ignoredConclusion(event, highlight, callback) + } + + } EventType.KEY_VERIFICATION_DONE -> { + + // Is the request referenced is actually really completed? + if (referenceInformationData.referencesInfoData?.verificationStatus != VerificationState.DONE) return ignoredConclusion(event, highlight, callback) + // We only tale the one sent by me if (informationData.sentByMe) { // We only display the done sent by the other user, the done send by me is ignored @@ -89,6 +130,7 @@ class VerificationItemFactory @Inject constructor( VerificationRequestConclusionItem.Attributes( toUserId = informationData.senderId, toUserName = informationData.memberName.toString(), + isPositive = true, informationData = informationData, avatarRenderer = attributes.avatarRenderer, colorProvider = colorProvider, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/VerificationRequestConclusionItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/VerificationRequestConclusionItem.kt index bddef2c130..a5344e1055 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/VerificationRequestConclusionItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/VerificationRequestConclusionItem.kt @@ -20,6 +20,7 @@ import android.graphics.Typeface import android.view.View import android.widget.RelativeLayout import androidx.appcompat.widget.AppCompatTextView +import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass @@ -45,8 +46,15 @@ abstract class VerificationRequestConclusionItem : AbsBaseMessageItem { this.marginEnd = leftGuideline } - holder.titleView.text = holder.view.context.getString(R.string.sas_verified) + val title = if (attributes.isPositive) R.string.sas_verified else R.string.verification_conclusion_warning + holder.titleView.text = holder.view.context.getString(title) holder.descriptionView.text = "${attributes.informationData.memberName} (${attributes.informationData.senderId})" + + val startDrawable = if (attributes.isPositive) R.drawable.ic_shield_trusted else R.drawable.ic_shield_warning + holder.titleView.setCompoundDrawablesWithIntrinsicBounds( + ContextCompat.getDrawable(holder.view.context, startDrawable), + null, null, null + ) } class Holder : AbsBaseMessageItem.Holder(STUB_ID) { @@ -65,6 +73,7 @@ abstract class VerificationRequestConclusionItem : AbsBaseMessageItem + + + + diff --git a/vector/src/main/res/layout/item_timeline_event_verification_done_stub.xml b/vector/src/main/res/layout/item_timeline_event_verification_done_stub.xml index f991e110c0..c0fdea8c9d 100644 --- a/vector/src/main/res/layout/item_timeline_event_verification_done_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_verification_done_stub.xml @@ -11,7 +11,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:drawableStart="@drawable/ic_shield_trusted" + tools:drawableStart="@drawable/ic_shield_trusted" android:drawablePadding="6dp" android:gravity="center" android:textColor="?riotx_text_primary" diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index a78505aef9..d2911d1b54 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -150,6 +150,7 @@ You cancelled %s cancelled Waiting… + Untrusted sign in