Merge pull request #206 from ouchadam/bug/missing-decryption

Bug/missing image decryption
This commit is contained in:
Adam Brown 2022-10-17 21:21:42 +01:00 committed by GitHub
commit 8270681a9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 199 additions and 109 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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())) {
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(
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.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 -> when (val content = model.content) {
ApiTimelineEvent.TimelineMessage.Content.Ignored -> this
is Image -> createImageEvent(content, userCredentials)
is Text -> createMessageEvent(content)
}
}
}
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 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) }
),
)
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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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