Merge pull request #206 from ouchadam/bug/missing-decryption
Bug/missing image decryption
This commit is contained in:
commit
8270681a9d
|
@ -105,6 +105,19 @@ sealed class RoomEvent {
|
|||
abstract val author: RoomMember
|
||||
abstract val meta: MessageMeta
|
||||
|
||||
data class Encrypted(
|
||||
override val eventId: EventId,
|
||||
override val utcTimestamp: Long,
|
||||
override val author: RoomMember,
|
||||
override val meta: MessageMeta,
|
||||
) : RoomEvent() {
|
||||
|
||||
val time: String by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
val instant = Instant.ofEpochMilli(utcTimestamp)
|
||||
ZonedDateTime.ofInstant(instant, DEFAULT_ZONE).toLocalTime().format(MESSAGE_TIME_FORMAT)
|
||||
}
|
||||
}
|
||||
|
||||
data class Message(
|
||||
override val eventId: EventId,
|
||||
override val utcTimestamp: Long,
|
||||
|
|
|
@ -198,6 +198,7 @@ private fun ColumnScope.RoomContent(self: UserId, state: RoomState, replyActions
|
|||
is RoomEvent.Image -> MessageImage(it as BubbleContent<RoomEvent.Image>)
|
||||
is RoomEvent.Message -> TextBubbleContent(it as BubbleContent<RoomEvent.Message>)
|
||||
is RoomEvent.Reply -> ReplyBubbleContent(it as BubbleContent<RoomEvent.Reply>)
|
||||
is RoomEvent.Encrypted -> EncryptedBubbleContent(it as BubbleContent<RoomEvent.Encrypted>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -445,6 +446,54 @@ private fun TextBubbleContent(content: BubbleContent<RoomEvent.Message>) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EncryptedBubbleContent(content: BubbleContent<RoomEvent.Encrypted>) {
|
||||
Box(modifier = Modifier.padding(start = 6.dp)) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.clip(content.shape)
|
||||
.background(content.background)
|
||||
.height(IntrinsicSize.Max),
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
.width(IntrinsicSize.Max)
|
||||
.defaultMinSize(minWidth = 50.dp)
|
||||
) {
|
||||
if (content.isNotSelf) {
|
||||
Text(
|
||||
fontSize = 11.sp,
|
||||
text = content.message.author.displayName ?: content.message.author.id.value,
|
||||
maxLines = 1,
|
||||
color = content.textColor()
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "Encrypted message",
|
||||
color = content.textColor(),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Row(horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
fontSize = 9.sp,
|
||||
text = "${content.message.time}",
|
||||
textAlign = TextAlign.End,
|
||||
color = content.textColor(),
|
||||
modifier = Modifier.wrapContentSize()
|
||||
)
|
||||
SendStatus(content.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReplyBubbleContent(content: BubbleContent<RoomEvent.Reply>) {
|
||||
Box(modifier = Modifier.padding(start = 6.dp)) {
|
||||
|
@ -511,6 +560,16 @@ private fun ReplyBubbleContent(content: BubbleContent<RoomEvent.Reply>) {
|
|||
is RoomEvent.Reply -> {
|
||||
// TODO - a reply to a reply
|
||||
}
|
||||
|
||||
is RoomEvent.Encrypted -> {
|
||||
Text(
|
||||
text = "Encrypted message",
|
||||
color = content.textColor().copy(alpha = 0.8f),
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,6 +613,16 @@ private fun ReplyBubbleContent(content: BubbleContent<RoomEvent.Reply>) {
|
|||
is RoomEvent.Reply -> {
|
||||
// TODO - a reply to a reply
|
||||
}
|
||||
|
||||
is RoomEvent.Encrypted -> {
|
||||
Text(
|
||||
text = "Encrypted message",
|
||||
color = content.textColor(),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
|
|
@ -97,6 +97,7 @@ internal class MessengerViewModel(
|
|||
is RoomEvent.Image -> TODO()
|
||||
is RoomEvent.Reply -> TODO()
|
||||
is RoomEvent.Message -> it.content
|
||||
is RoomEvent.Encrypted -> error("Should never happen")
|
||||
},
|
||||
eventId = it.eventId,
|
||||
timestampUtc = it.utcTimestamp,
|
||||
|
|
|
@ -6,19 +6,14 @@ import app.dapk.st.matrix.common.RoomMember
|
|||
class RoomEventsToNotifiableMapper {
|
||||
|
||||
fun map(events: List<RoomEvent>): List<Notifiable> {
|
||||
return events.map {
|
||||
when (it) {
|
||||
is RoomEvent.Image -> Notifiable(content = it.toNotifiableContent(), it.utcTimestamp, it.author)
|
||||
is RoomEvent.Message -> Notifiable(content = it.toNotifiableContent(), it.utcTimestamp, it.author)
|
||||
is RoomEvent.Reply -> Notifiable(content = it.toNotifiableContent(), it.utcTimestamp, it.author)
|
||||
}
|
||||
}
|
||||
return events.map { Notifiable(content = it.toNotifiableContent(), it.utcTimestamp, it.author) }
|
||||
}
|
||||
|
||||
private fun RoomEvent.toNotifiableContent(): String = when (this) {
|
||||
is RoomEvent.Image -> "\uD83D\uDCF7"
|
||||
is RoomEvent.Message -> this.content
|
||||
is RoomEvent.Reply -> this.message.toNotifiableContent()
|
||||
is RoomEvent.Encrypted -> "Encrypted message"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ internal class LocalEchoMapper(private val metaMapper: MetaMapper) {
|
|||
is RoomEvent.Message -> this.copy(meta = metaMapper.toMeta(echo))
|
||||
is RoomEvent.Reply -> this.copy(message = this.message.mergeWith(echo))
|
||||
is RoomEvent.Image -> this.copy(meta = metaMapper.toMeta(echo))
|
||||
is RoomEvent.Encrypted -> this.copy(meta = metaMapper.toMeta(echo))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ fun MatrixRoomEvent.engine(): RoomEvent = when (this) {
|
|||
is MatrixRoomEvent.Image -> RoomEvent.Image(this.eventId, this.utcTimestamp, this.imageMeta.engine(), this.author, this.meta.engine(), this.edited)
|
||||
is MatrixRoomEvent.Message -> RoomEvent.Message(this.eventId, this.utcTimestamp, this.content, this.author, this.meta.engine(), this.edited, this.redacted)
|
||||
is MatrixRoomEvent.Reply -> RoomEvent.Reply(this.message.engine(), this.replyingTo.engine())
|
||||
is MatrixRoomEvent.Encrypted -> RoomEvent.Encrypted(this.eventId, this.utcTimestamp, this.author, this.meta.engine())
|
||||
}
|
||||
|
||||
fun MatrixRoomEvent.Image.ImageMeta.engine() = RoomEvent.Image.ImageMeta(
|
||||
|
|
|
@ -77,13 +77,12 @@ interface MessageService : MatrixService {
|
|||
|
||||
@Serializable
|
||||
data class Meta(
|
||||
val height: Int,
|
||||
val width: Int,
|
||||
val size: Long,
|
||||
val fileName: String,
|
||||
val mimeType: String,
|
||||
@SerialName("height") val height: Int,
|
||||
@SerialName("width") val width: Int,
|
||||
@SerialName("size") val size: Long,
|
||||
@SerialName("file_name") val fileName: String,
|
||||
@SerialName("mime_type") val mimeType: String,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
package app.dapk.st.matrix.sync
|
||||
|
||||
import app.dapk.st.core.extensions.unsafeLazy
|
||||
import app.dapk.st.matrix.common.*
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
data class RoomState(
|
||||
val roomOverview: RoomOverview,
|
||||
val events: List<RoomEvent>,
|
||||
)
|
||||
|
||||
internal val DEFAULT_ZONE = ZoneId.systemDefault()
|
||||
internal val MESSAGE_TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm")
|
||||
|
||||
@Serializable
|
||||
sealed class RoomEvent {
|
||||
|
||||
|
@ -24,18 +16,18 @@ sealed class RoomEvent {
|
|||
abstract val utcTimestamp: Long
|
||||
abstract val author: RoomMember
|
||||
abstract val meta: MessageMeta
|
||||
abstract val redacted: Boolean
|
||||
|
||||
@Serializable
|
||||
@SerialName("message")
|
||||
data class Message(
|
||||
@SerialName("encrypted")
|
||||
data class Encrypted(
|
||||
@SerialName("event_id") override val eventId: EventId,
|
||||
@SerialName("timestamp") override val utcTimestamp: Long,
|
||||
@SerialName("content") val content: String,
|
||||
@SerialName("author") override val author: RoomMember,
|
||||
@SerialName("meta") override val meta: MessageMeta,
|
||||
@SerialName("encrypted_content") val encryptedContent: MegOlmV1? = null,
|
||||
@SerialName("edited") val edited: Boolean = false,
|
||||
@SerialName("redacted") val redacted: Boolean = false,
|
||||
@SerialName("redacted") override val redacted: Boolean = false,
|
||||
@SerialName("encrypted_content") val encryptedContent: MegOlmV1,
|
||||
) : RoomEvent() {
|
||||
|
||||
@Serializable
|
||||
|
@ -46,12 +38,20 @@ sealed class RoomEvent {
|
|||
@SerialName("session_id") val sessionId: SessionId,
|
||||
)
|
||||
|
||||
val time: String by unsafeLazy {
|
||||
val instant = Instant.ofEpochMilli(utcTimestamp)
|
||||
ZonedDateTime.ofInstant(instant, DEFAULT_ZONE).toLocalTime().format(MESSAGE_TIME_FORMAT)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("message")
|
||||
data class Message(
|
||||
@SerialName("event_id") override val eventId: EventId,
|
||||
@SerialName("timestamp") override val utcTimestamp: Long,
|
||||
@SerialName("content") val content: String,
|
||||
@SerialName("author") override val author: RoomMember,
|
||||
@SerialName("meta") override val meta: MessageMeta,
|
||||
@SerialName("edited") val edited: Boolean = false,
|
||||
@SerialName("redacted") override val redacted: Boolean = false,
|
||||
) : RoomEvent()
|
||||
|
||||
@Serializable
|
||||
@SerialName("reply")
|
||||
data class Reply(
|
||||
|
@ -63,13 +63,8 @@ sealed class RoomEvent {
|
|||
override val utcTimestamp: Long = message.utcTimestamp
|
||||
override val author: RoomMember = message.author
|
||||
override val meta: MessageMeta = message.meta
|
||||
override val redacted: Boolean = message.redacted
|
||||
|
||||
val replyingToSelf = replyingTo.author == message.author
|
||||
|
||||
val time: String by unsafeLazy {
|
||||
val instant = Instant.ofEpochMilli(utcTimestamp)
|
||||
ZonedDateTime.ofInstant(instant, DEFAULT_ZONE).toLocalTime().format(MESSAGE_TIME_FORMAT)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
@ -80,15 +75,10 @@ sealed class RoomEvent {
|
|||
@SerialName("image_meta") val imageMeta: ImageMeta,
|
||||
@SerialName("author") override val author: RoomMember,
|
||||
@SerialName("meta") override val meta: MessageMeta,
|
||||
@SerialName("encrypted_content") val encryptedContent: Message.MegOlmV1? = null,
|
||||
@SerialName("edited") val edited: Boolean = false,
|
||||
@SerialName("redacted") override val redacted: Boolean = false,
|
||||
) : RoomEvent() {
|
||||
|
||||
val time: String by unsafeLazy {
|
||||
val instant = Instant.ofEpochMilli(utcTimestamp)
|
||||
ZonedDateTime.ofInstant(instant, DEFAULT_ZONE).toLocalTime().format(MESSAGE_TIME_FORMAT)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ImageMeta(
|
||||
@SerialName("width") val width: Int?,
|
||||
|
|
|
@ -3,6 +3,8 @@ package app.dapk.st.matrix.sync.internal.room
|
|||
import app.dapk.st.matrix.common.*
|
||||
import app.dapk.st.matrix.sync.RoomEvent
|
||||
import app.dapk.st.matrix.sync.internal.request.ApiTimelineEvent
|
||||
import app.dapk.st.matrix.sync.internal.request.ApiTimelineEvent.TimelineMessage.Content.Image
|
||||
import app.dapk.st.matrix.sync.internal.request.ApiTimelineEvent.TimelineMessage.Content.Text
|
||||
import app.dapk.st.matrix.sync.internal.request.DecryptedContent
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
@ -17,56 +19,60 @@ internal class RoomEventsDecrypter(
|
|||
}
|
||||
|
||||
private suspend fun decryptEvent(event: RoomEvent, userCredentials: UserCredentials): RoomEvent = when (event) {
|
||||
is RoomEvent.Message -> event.decrypt()
|
||||
is RoomEvent.Encrypted -> event.decrypt(userCredentials)
|
||||
is RoomEvent.Message -> event
|
||||
is RoomEvent.Reply -> RoomEvent.Reply(
|
||||
message = decryptEvent(event.message, userCredentials),
|
||||
replyingTo = decryptEvent(event.replyingTo, userCredentials),
|
||||
)
|
||||
is RoomEvent.Image -> event.decrypt(userCredentials)
|
||||
|
||||
is RoomEvent.Image -> event
|
||||
}
|
||||
|
||||
private suspend fun RoomEvent.Image.decrypt(userCredentials: UserCredentials) = when (this.encryptedContent) {
|
||||
null -> this
|
||||
else -> when (val result = messageDecrypter.decrypt(this.encryptedContent.toModel())) {
|
||||
private suspend fun RoomEvent.Encrypted.decrypt(userCredentials: UserCredentials) = when (val result = this.decryptContent()) {
|
||||
is DecryptionResult.Failed -> this.also { logger.crypto("Failed to decrypt ${it.eventId}") }
|
||||
is DecryptionResult.Success -> when (val model = result.payload.toModel()) {
|
||||
DecryptedContent.Ignored -> this
|
||||
is DecryptedContent.TimelineText -> {
|
||||
val content = model.content as ApiTimelineEvent.TimelineMessage.Content.Image
|
||||
this.copy(
|
||||
is DecryptedContent.TimelineText -> when (val content = model.content) {
|
||||
ApiTimelineEvent.TimelineMessage.Content.Ignored -> this
|
||||
is Image -> createImageEvent(content, userCredentials)
|
||||
is Text -> createMessageEvent(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun RoomEvent.Encrypted.decryptContent() = messageDecrypter.decrypt(this.encryptedContent.toModel())
|
||||
|
||||
private fun RoomEvent.Encrypted.createMessageEvent(content: Text) = RoomEvent.Message(
|
||||
eventId = this.eventId,
|
||||
utcTimestamp = this.utcTimestamp,
|
||||
author = this.author,
|
||||
meta = this.meta,
|
||||
edited = this.edited,
|
||||
redacted = this.redacted,
|
||||
content = content.body ?: ""
|
||||
)
|
||||
|
||||
private fun RoomEvent.Encrypted.createImageEvent(content: Image, userCredentials: UserCredentials) = RoomEvent.Image(
|
||||
eventId = this.eventId,
|
||||
utcTimestamp = this.utcTimestamp,
|
||||
author = this.author,
|
||||
meta = this.meta,
|
||||
edited = this.edited,
|
||||
redacted = this.redacted,
|
||||
imageMeta = RoomEvent.Image.ImageMeta(
|
||||
width = content.info?.width,
|
||||
height = content.info?.height,
|
||||
url = content.file?.url?.convertMxUrToUrl(userCredentials.homeServer) ?: content.url!!.convertMxUrToUrl(userCredentials.homeServer),
|
||||
keys = content.file?.let { RoomEvent.Image.ImageMeta.Keys(it.key.k, it.iv, it.v, it.hashes) }
|
||||
),
|
||||
encryptedContent = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun RoomEvent.Message.decrypt() = when (this.encryptedContent) {
|
||||
null -> this
|
||||
else -> when (val result = messageDecrypter.decrypt(this.encryptedContent.toModel())) {
|
||||
is DecryptionResult.Failed -> this.also { logger.crypto("Failed to decrypt ${it.eventId}") }
|
||||
is DecryptionResult.Success -> when (val model = result.payload.toModel()) {
|
||||
DecryptedContent.Ignored -> this
|
||||
is DecryptedContent.TimelineText -> this.copyWithDecryptedContent(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JsonString.toModel() = json.decodeFromString(DecryptedContent.serializer(), this.value)
|
||||
|
||||
private fun RoomEvent.Message.copyWithDecryptedContent(decryptedContent: DecryptedContent.TimelineText) = this.copy(
|
||||
content = (decryptedContent.content as ApiTimelineEvent.TimelineMessage.Content.Text).body ?: "",
|
||||
encryptedContent = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun RoomEvent.Message.MegOlmV1.toModel() = EncryptedMessageContent.MegOlmV1(
|
||||
private fun RoomEvent.Encrypted.MegOlmV1.toModel() = EncryptedMessageContent.MegOlmV1(
|
||||
this.cipherText,
|
||||
this.deviceId,
|
||||
this.senderKey,
|
||||
|
|
|
@ -51,11 +51,7 @@ class RoomDataSource(
|
|||
}
|
||||
}
|
||||
|
||||
private fun RoomEvent.redact() = when (this) {
|
||||
is RoomEvent.Image -> RoomEvent.Message(this.eventId, this.utcTimestamp, "Redacted", this.author, this.meta, redacted = true)
|
||||
is RoomEvent.Message -> RoomEvent.Message(this.eventId, this.utcTimestamp, "Redacted", this.author, this.meta, redacted = true)
|
||||
is RoomEvent.Reply -> RoomEvent.Message(this.eventId, this.utcTimestamp, "Redacted", this.author, this.meta, redacted = true)
|
||||
}
|
||||
private fun RoomEvent.redact() = RoomEvent.Message(this.eventId, this.utcTimestamp, "Redacted", this.author, this.meta, redacted = true)
|
||||
|
||||
private fun RoomState.replaceEvent(old: RoomEvent, new: RoomEvent): RoomState {
|
||||
val updatedEvents = this.events.toMutableList().apply {
|
||||
|
|
|
@ -24,13 +24,12 @@ internal class RoomEventCreator(
|
|||
suspend fun ApiTimelineEvent.Encrypted.toRoomEvent(roomId: RoomId): RoomEvent? {
|
||||
return when (this.encryptedContent) {
|
||||
is ApiEncryptedContent.MegOlmV1 -> {
|
||||
RoomEvent.Message(
|
||||
RoomEvent.Encrypted(
|
||||
eventId = this.eventId,
|
||||
author = roomMembersService.find(roomId, this.senderId)!!,
|
||||
utcTimestamp = this.utcTimestamp,
|
||||
meta = MessageMeta.FromServer,
|
||||
content = "Encrypted message",
|
||||
encryptedContent = RoomEvent.Message.MegOlmV1(
|
||||
encryptedContent = RoomEvent.Encrypted.MegOlmV1(
|
||||
this.encryptedContent.cipherText,
|
||||
this.encryptedContent.deviceId,
|
||||
this.encryptedContent.senderKey,
|
||||
|
@ -38,6 +37,7 @@ internal class RoomEventCreator(
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
is ApiEncryptedContent.OlmV1 -> errorTracker.nullAndTrack(IllegalStateException("unexpected encryption, got OlmV1 for a room event"))
|
||||
ApiEncryptedContent.Unknown -> errorTracker.nullAndTrack(IllegalStateException("unknown room event encryption"))
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ internal class TimelineEventMapper(
|
|||
is RoomEvent.Message -> relationEvent
|
||||
is RoomEvent.Reply -> relationEvent.message
|
||||
is RoomEvent.Image -> relationEvent
|
||||
is RoomEvent.Encrypted -> relationEvent
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -110,12 +111,19 @@ internal class TimelineEventMapper(
|
|||
is RoomEvent.Image -> original.message
|
||||
is RoomEvent.Message -> original.message.edited(incomingEdit)
|
||||
is RoomEvent.Reply -> original.message
|
||||
is RoomEvent.Encrypted -> original.message
|
||||
}
|
||||
)
|
||||
|
||||
is RoomEvent.Image -> {
|
||||
// can't edit images
|
||||
null
|
||||
}
|
||||
|
||||
is RoomEvent.Encrypted -> {
|
||||
// can't edit encrypted messages
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,11 +135,13 @@ internal class TimelineEventMapper(
|
|||
utcTimestamp = incomingEdit.utcTimestamp,
|
||||
edited = true,
|
||||
)
|
||||
|
||||
is ApiTimelineEvent.TimelineMessage.Content.Text -> original.toTextMessage(
|
||||
utcTimestamp = incomingEdit.utcTimestamp,
|
||||
content = incomingEdit.asTextContent().body?.removePrefix(" * ")?.trim() ?: "redacted",
|
||||
edited = true,
|
||||
)
|
||||
|
||||
ApiTimelineEvent.TimelineMessage.Content.Ignored -> null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,4 +81,5 @@ private fun RoomEvent.toTextContent(): String = when (this) {
|
|||
is RoomEvent.Image -> "\uD83D\uDCF7"
|
||||
is RoomEvent.Message -> this.content
|
||||
is RoomEvent.Reply -> this.message.toTextContent()
|
||||
is RoomEvent.Encrypted -> "Encrypted message"
|
||||
}
|
|
@ -43,6 +43,7 @@ internal class UnreadEventsProcessor(
|
|||
is RoomEvent.Message -> it.author.id == selfId
|
||||
is RoomEvent.Reply -> it.message.author.id == selfId
|
||||
is RoomEvent.Image -> it.author.id == selfId
|
||||
is RoomEvent.Encrypted -> it.author.id == selfId
|
||||
}
|
||||
}.map { it.eventId }
|
||||
roomStore.insertUnread(overview.roomId, eventsFromOthers)
|
||||
|
|
|
@ -15,12 +15,12 @@ import org.junit.Test
|
|||
|
||||
private const val A_DECRYPTED_MESSAGE_CONTENT = "decrypted - content"
|
||||
private val AN_ENCRYPTED_ROOM_CONTENT = aMegolmV1()
|
||||
private val AN_ENCRYPTED_ROOM_MESSAGE = aMatrixRoomMessageEvent(encryptedContent = AN_ENCRYPTED_ROOM_CONTENT)
|
||||
private val AN_ENCRYPTED_ROOM_MESSAGE = anEncryptedRoomMessageEvent(encryptedContent = AN_ENCRYPTED_ROOM_CONTENT)
|
||||
private val AN_ENCRYPTED_ROOM_REPLY = aRoomReplyMessageEvent(
|
||||
message = AN_ENCRYPTED_ROOM_MESSAGE,
|
||||
replyingTo = AN_ENCRYPTED_ROOM_MESSAGE.copy(eventId = anEventId("other-event"))
|
||||
)
|
||||
private val A_DECRYPTED_CONTENT = DecryptedContent.TimelineText(aTimelineTextEventContent(body = A_DECRYPTED_MESSAGE_CONTENT))
|
||||
private val A_DECRYPTED_TEXT_CONTENT = DecryptedContent.TimelineText(aTimelineTextEventContent(body = A_DECRYPTED_MESSAGE_CONTENT))
|
||||
private val A_USER_CREDENTIALS = aUserCredentials()
|
||||
|
||||
private val json = Json { encodeDefaults = true }
|
||||
|
@ -37,7 +37,7 @@ class RoomEventsDecrypterTest {
|
|||
|
||||
@Test
|
||||
fun `given clear message event, when decrypting, then does nothing`() = runTest {
|
||||
val aClearMessageEvent = aMatrixRoomMessageEvent(encryptedContent = null)
|
||||
val aClearMessageEvent = aMatrixRoomMessageEvent()
|
||||
val result = roomEventsDecrypter.decryptRoomEvents(A_USER_CREDENTIALS, listOf(aClearMessageEvent))
|
||||
|
||||
result shouldBeEqualTo listOf(aClearMessageEvent)
|
||||
|
@ -45,42 +45,52 @@ class RoomEventsDecrypterTest {
|
|||
|
||||
@Test
|
||||
fun `given encrypted message event, when decrypting, then applies decrypted body and removes encrypted content`() = runTest {
|
||||
givenEncryptedMessage(AN_ENCRYPTED_ROOM_MESSAGE, decryptsTo = A_DECRYPTED_CONTENT)
|
||||
givenEncryptedMessage(AN_ENCRYPTED_ROOM_MESSAGE, decryptsTo = A_DECRYPTED_TEXT_CONTENT)
|
||||
|
||||
val result = roomEventsDecrypter.decryptRoomEvents(A_USER_CREDENTIALS, listOf(AN_ENCRYPTED_ROOM_MESSAGE))
|
||||
|
||||
result shouldBeEqualTo listOf(AN_ENCRYPTED_ROOM_MESSAGE.copy(content = A_DECRYPTED_MESSAGE_CONTENT, encryptedContent = null))
|
||||
result shouldBeEqualTo listOf(AN_ENCRYPTED_ROOM_MESSAGE.toText(A_DECRYPTED_MESSAGE_CONTENT))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given encrypted reply event, when decrypting, then decrypts message and replyTo`() = runTest {
|
||||
givenEncryptedReply(AN_ENCRYPTED_ROOM_REPLY, decryptsTo = A_DECRYPTED_CONTENT)
|
||||
givenEncryptedReply(AN_ENCRYPTED_ROOM_REPLY, decryptsTo = A_DECRYPTED_TEXT_CONTENT)
|
||||
|
||||
val result = roomEventsDecrypter.decryptRoomEvents(A_USER_CREDENTIALS, listOf(AN_ENCRYPTED_ROOM_REPLY))
|
||||
|
||||
result shouldBeEqualTo listOf(
|
||||
AN_ENCRYPTED_ROOM_REPLY.copy(
|
||||
message = (AN_ENCRYPTED_ROOM_REPLY.message as RoomEvent.Message).copy(content = A_DECRYPTED_MESSAGE_CONTENT, encryptedContent = null),
|
||||
replyingTo = (AN_ENCRYPTED_ROOM_REPLY.replyingTo as RoomEvent.Message).copy(content = A_DECRYPTED_MESSAGE_CONTENT, encryptedContent = null),
|
||||
message = (AN_ENCRYPTED_ROOM_REPLY.message as RoomEvent.Encrypted).toText(A_DECRYPTED_MESSAGE_CONTENT),
|
||||
replyingTo = (AN_ENCRYPTED_ROOM_REPLY.replyingTo as RoomEvent.Encrypted).toText(A_DECRYPTED_MESSAGE_CONTENT),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun givenEncryptedMessage(roomMessage: RoomEvent.Message, decryptsTo: DecryptedContent) {
|
||||
val model = roomMessage.encryptedContent!!.toModel()
|
||||
private fun givenEncryptedMessage(roomMessage: RoomEvent.Encrypted, decryptsTo: DecryptedContent) {
|
||||
val model = roomMessage.encryptedContent.toModel()
|
||||
fakeMessageDecrypter.givenDecrypt(model)
|
||||
.returns(aDecryptionSuccessResult(payload = JsonString(json.encodeToString(DecryptedContent.serializer(), decryptsTo))))
|
||||
}
|
||||
|
||||
private fun givenEncryptedReply(roomReply: RoomEvent.Reply, decryptsTo: DecryptedContent) {
|
||||
givenEncryptedMessage(roomReply.message as RoomEvent.Message, decryptsTo)
|
||||
givenEncryptedMessage(roomReply.replyingTo as RoomEvent.Message, decryptsTo)
|
||||
givenEncryptedMessage(roomReply.message as RoomEvent.Encrypted, decryptsTo)
|
||||
givenEncryptedMessage(roomReply.replyingTo as RoomEvent.Encrypted, decryptsTo)
|
||||
}
|
||||
}
|
||||
|
||||
private fun RoomEvent.Message.MegOlmV1.toModel() = EncryptedMessageContent.MegOlmV1(
|
||||
private fun RoomEvent.Encrypted.MegOlmV1.toModel() = EncryptedMessageContent.MegOlmV1(
|
||||
this.cipherText,
|
||||
this.deviceId,
|
||||
this.senderKey,
|
||||
this.sessionId,
|
||||
)
|
||||
|
||||
private fun RoomEvent.Encrypted.toText(text: String) = RoomEvent.Message(
|
||||
this.eventId,
|
||||
this.utcTimestamp,
|
||||
content = text,
|
||||
this.author,
|
||||
this.meta,
|
||||
this.edited,
|
||||
this.redacted,
|
||||
)
|
|
@ -40,10 +40,9 @@ internal class RoomEventCreatorTest {
|
|||
|
||||
val result = with(roomEventCreator) { megolmEvent.toRoomEvent(A_ROOM_ID) }
|
||||
|
||||
result shouldBeEqualTo aMatrixRoomMessageEvent(
|
||||
result shouldBeEqualTo anEncryptedRoomMessageEvent(
|
||||
eventId = megolmEvent.eventId,
|
||||
utcTimestamp = megolmEvent.utcTimestamp,
|
||||
content = "Encrypted message",
|
||||
author = A_SENDER,
|
||||
encryptedContent = megolmEvent.encryptedContent.toMegolm(),
|
||||
)
|
||||
|
@ -320,7 +319,7 @@ private fun RoomEvent.Message.toReplyEvent(messageContent: String) = anApiTimeli
|
|||
)
|
||||
)
|
||||
|
||||
private fun ApiEncryptedContent.toMegolm(): RoomEvent.Message.MegOlmV1 {
|
||||
private fun ApiEncryptedContent.toMegolm(): RoomEvent.Encrypted.MegOlmV1 {
|
||||
require(this is ApiEncryptedContent.MegOlmV1)
|
||||
return aMegolmV1(this.cipherText, this.deviceId, this.senderKey, this.sessionId)
|
||||
}
|
||||
|
|
|
@ -10,9 +10,8 @@ fun aMatrixRoomMessageEvent(
|
|||
content: String = "message-content",
|
||||
author: RoomMember = aRoomMember(),
|
||||
meta: MessageMeta = MessageMeta.FromServer,
|
||||
encryptedContent: RoomEvent.Message.MegOlmV1? = null,
|
||||
edited: Boolean = false,
|
||||
) = RoomEvent.Message(eventId, utcTimestamp, content, author, meta, encryptedContent, edited)
|
||||
) = RoomEvent.Message(eventId, utcTimestamp, content, author, meta, edited)
|
||||
|
||||
fun aRoomImageMessageEvent(
|
||||
eventId: EventId = anEventId(),
|
||||
|
@ -20,9 +19,8 @@ fun aRoomImageMessageEvent(
|
|||
content: RoomEvent.Image.ImageMeta = anImageMeta(),
|
||||
author: RoomMember = aRoomMember(),
|
||||
meta: MessageMeta = MessageMeta.FromServer,
|
||||
encryptedContent: RoomEvent.Message.MegOlmV1? = null,
|
||||
edited: Boolean = false,
|
||||
) = RoomEvent.Image(eventId, utcTimestamp, content, author, meta, encryptedContent, edited)
|
||||
) = RoomEvent.Image(eventId, utcTimestamp, content, author, meta, edited)
|
||||
|
||||
fun aRoomReplyMessageEvent(
|
||||
message: RoomEvent = aMatrixRoomMessageEvent(),
|
||||
|
@ -32,19 +30,19 @@ fun aRoomReplyMessageEvent(
|
|||
fun anEncryptedRoomMessageEvent(
|
||||
eventId: EventId = anEventId(),
|
||||
utcTimestamp: Long = 0L,
|
||||
content: String = "encrypted-content",
|
||||
author: RoomMember = aRoomMember(),
|
||||
meta: MessageMeta = MessageMeta.FromServer,
|
||||
encryptedContent: RoomEvent.Message.MegOlmV1? = aMegolmV1(),
|
||||
encryptedContent: RoomEvent.Encrypted.MegOlmV1 = aMegolmV1(),
|
||||
edited: Boolean = false,
|
||||
) = RoomEvent.Message(eventId, utcTimestamp, content, author, meta, encryptedContent, edited)
|
||||
redacted: Boolean = false,
|
||||
) = RoomEvent.Encrypted(eventId, utcTimestamp, author, meta, edited, redacted, encryptedContent)
|
||||
|
||||
fun aMegolmV1(
|
||||
cipherText: CipherText = CipherText("a-cipher"),
|
||||
deviceId: DeviceId = aDeviceId(),
|
||||
senderKey: String = "a-sender-key",
|
||||
sessionId: SessionId = aSessionId(),
|
||||
) = RoomEvent.Message.MegOlmV1(cipherText, deviceId, senderKey, sessionId)
|
||||
) = RoomEvent.Encrypted.MegOlmV1(cipherText, deviceId, senderKey, sessionId)
|
||||
|
||||
fun anImageMeta(
|
||||
width: Int? = 100,
|
||||
|
|
Loading…
Reference in New Issue