Show untrusted conclusions

This commit is contained in:
Valere 2019-12-11 18:19:32 +01:00
parent 0776a301ea
commit a673bf092d
8 changed files with 104 additions and 13 deletions

View file

@ -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?

View file

@ -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
}
}

View file

@ -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)
}

View file

@ -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<MessageVerificationRequestContent>() == 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<MessageVerificationCancelContent>()
?: 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,

View file

@ -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<Verificati
holder.endGuideline.updateLayoutParams<RelativeLayout.LayoutParams> {
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<Verificati
data class Attributes(
val toUserId: String,
val toUserName: String,
val isPositive: Boolean,
override val informationData: MessageInformationData,
override val avatarRenderer: AvatarRenderer,
override val colorProvider: ColorProvider,

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:strokeWidth="1"
android:pathData="m12,21s9,-3.8 9,-9.5v-6.65l-9,-2.85 -9,2.85v6.65c0,5.7 9,9.5 9,9.5z"
android:strokeLineJoin="round"
android:fillColor="#ff4b55"
android:strokeColor="#fff"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M12.05,5.5L12.05,5.5A1.25,1.25 0,0 1,13.3 6.75L13.3,12.25A1.25,1.25 0,0 1,12.05 13.5L12.05,13.5A1.25,1.25 0,0 1,10.8 12.25L10.8,6.75A1.25,1.25 0,0 1,12.05 5.5z"
android:fillColor="#fff"/>
<path
android:pathData="M12.05,15L12.05,15A1.25,1.25 0,0 1,13.3 16.25L13.3,16.25A1.25,1.25 0,0 1,12.05 17.5L12.05,17.5A1.25,1.25 0,0 1,10.8 16.25L10.8,16.25A1.25,1.25 0,0 1,12.05 15z"
android:fillColor="#fff"/>
</vector>

View file

@ -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"

View file

@ -150,6 +150,7 @@
<string name="verification_request_you_cancelled">You cancelled</string>
<string name="verification_request_other_cancelled">%s cancelled</string>
<string name="verification_request_waiting">Waiting…</string>
<string name="verification_conclusion_warning">Untrusted sign in</string>
</resources>