From 888eda4ba9aa1611bac962628472300fe019f1b1 Mon Sep 17 00:00:00 2001 From: Brice Date: Fri, 27 Nov 2020 15:56:16 +1100 Subject: [PATCH 01/11] change package name + start of implementation --- libsession/build.gradle | 3 + .../messaging/messages/Destination.kt | 8 +- .../libsession/messaging/messages/Message.kt | 32 +++- .../messages/control/ClosedGroupUpdate.kt | 154 +++++++++++++++++- .../messages/control/ControlMessage.kt | 6 +- .../messages/control/ExpirationTimerUpdate.kt | 11 +- .../messaging/messages/control/ReadReceipt.kt | 11 +- .../messages/control/TypingIndicator.kt | 11 +- .../messages/control/unused/NullMessage.kt | 12 +- .../messages/control/unused/SessionRequest.kt | 12 +- .../messaging/messages/visible/Contact.kt | 13 +- .../messaging/messages/visible/LinkPreview.kt | 13 +- .../messaging/messages/visible/Profile.kt | 13 +- .../messaging/messages/visible/Quote.kt | 13 +- .../messages/visible/VisibleMessage.kt | 6 +- .../visible/attachments/Attachment.kt | 14 +- 16 files changed, 303 insertions(+), 29 deletions(-) diff --git a/libsession/build.gradle b/libsession/build.gradle index aea50a3003..47fc374def 100644 --- a/libsession/build.gradle +++ b/libsession/build.gradle @@ -38,7 +38,10 @@ dependencies { implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' + implementation "com.google.protobuf:protobuf-java:$protobufVersion" testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + implementation project(":libsignal") } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt index bd39ccbbce..8c255bdce5 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt @@ -1,5 +1,9 @@ -package org.session.messaging.messages +package org.session.libsession.messaging.messages -enum class Destination { +sealed class Destination { + + class Contact(val publicKey: String) + class ClosedGroup(val groupPublicKey: String) + class OpenGroup(val channel: Long, val server: String) } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt index b1ca1ce0ca..6176cee7c8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt @@ -1,5 +1,33 @@ -package org.session.messaging.messages +package org.session.libsession.messaging.messages -open class Message { +import org.session.libsignal.service.internal.push.SignalServiceProtos + +abstract class Message { + + var id: String? = null + var threadID: String? = null + var sentTimestamp: Long? = null + var receivedTimestamp: Long? = null + var recipient: String? = null + var sender: String? = null + var groupPublicKey: String? = null + var openGroupServerMessageID: Long? = null + + companion object { + @JvmStatic + val ttl = 2 * 24 * 60 * 60 * 1000 + + //fun fromProto(proto: SignalServiceProtos.Content): Message? {} + } + + open fun isValid(): Boolean { + sentTimestamp = if (sentTimestamp!! > 0) sentTimestamp else return false + receivedTimestamp = if (receivedTimestamp!! > 0) receivedTimestamp else return false + return sender != null && recipient != null + } + + + + abstract fun toProto(): SignalServiceProtos.Content? } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt index e6c673c7ee..18f424ba8e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt @@ -1,4 +1,154 @@ -package org.session.messaging.messages.control +package org.session.libsession.messaging.messages.control -class ClosedGroupUpdate : ControlMessage() { +import com.google.protobuf.ByteString +import org.session.libsignal.libsignal.logging.Log +import org.session.libsignal.service.internal.push.SignalServiceProtos +import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey + +class ClosedGroupUpdate() : ControlMessage() { + + companion object { + const val TAG = "ClosedGroupUpdate" + + fun fromProto(proto: SignalServiceProtos.Content): ClosedGroupUpdate? { + val closedGroupUpdateProto = proto.dataMessage?.closedGroupUpdate ?: return null + val groupPublicKey = closedGroupUpdateProto.groupPublicKey + var kind: Kind? = null + when(closedGroupUpdateProto.type) { + SignalServiceProtos.ClosedGroupUpdate.Type.NEW -> { + val name = closedGroupUpdateProto.name ?: return null + val groupPrivateKey = closedGroupUpdateProto.groupPrivateKey ?: return null + val senderKeys = closedGroupUpdateProto.senderKeysList.map { ClosedGroupSenderKey.fromProto(it) } + kind = Kind.New( + groupPublicKey = groupPublicKey.toByteArray(), + name = name, + groupPrivateKey = groupPrivateKey.toByteArray(), + senderKeys = senderKeys, + members = closedGroupUpdateProto.membersList.map { it.toByteArray() }, + admins = closedGroupUpdateProto.adminsList.map { it.toByteArray() } + ) + } + SignalServiceProtos.ClosedGroupUpdate.Type.INFO -> { + val name = closedGroupUpdateProto.name ?: return null + val senderKeys = closedGroupUpdateProto.senderKeysList.map { ClosedGroupSenderKey.fromProto(it) } + kind = Kind.Info( + groupPublicKey = groupPublicKey.toByteArray(), + name = name, + senderKeys = senderKeys, + members = closedGroupUpdateProto.membersList.map { it.toByteArray() }, + admins = closedGroupUpdateProto.adminsList.map { it.toByteArray() } + ) + } + SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY_REQUEST -> { + kind = Kind.SenderKeyRequest(groupPublicKey = groupPublicKey.toByteArray()) + } + SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY -> { + val senderKeyProto = closedGroupUpdateProto.senderKeysList?.first() ?: return null + kind = Kind.SenderKey( + groupPublicKey = groupPublicKey.toByteArray(), + senderKey = ClosedGroupSenderKey.fromProto(senderKeyProto) + ) + } + } + return ClosedGroupUpdate(kind) + } + } + //private val TAG: String = ClosedGroupUpdate::class.java.simpleName + + // Kind enum + sealed class Kind { + class New(val groupPublicKey: ByteArray, val name: String, val groupPrivateKey: ByteArray, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() + class Info(val groupPublicKey: ByteArray, val name: String, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() + class SenderKeyRequest(val groupPublicKey: ByteArray) : Kind() + class SenderKey(val groupPublicKey: ByteArray, val senderKey: org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey) : Kind() + } + + var kind: Kind? = null + + // constructors + internal constructor(kind: Kind?) : this() { + this.kind = kind + } + + override fun isValid(): Boolean { + if (!super.isValid() || kind == null) return false + val kind = kind ?: return false + when(kind) { + is Kind.New -> { + return !kind.groupPublicKey.isEmpty() && !kind.name.isEmpty() && !kind.groupPrivateKey.isEmpty() && !kind.members.isEmpty() && !kind.admins.isEmpty() + } + is Kind.Info -> { + return !kind.groupPublicKey.isEmpty() && !kind.name.isEmpty() && !kind.members.isEmpty() && !kind.admins.isEmpty() + } + is Kind.SenderKeyRequest -> { + return !kind.groupPublicKey.isEmpty() + } + is Kind.SenderKey -> { + return !kind.groupPublicKey.isEmpty() + } + } + } + + override fun toProto(): SignalServiceProtos.Content? { + val kind = kind + if (kind == null) { + Log.w(TAG, "Couldn't construct closed group update proto from: $this") + return null + } + try { + val closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdate.Builder = SignalServiceProtos.ClosedGroupUpdate.newBuilder() + when (kind) { + is Kind.New -> { + closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey) + closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.NEW + closedGroupUpdate.name = kind.name + closedGroupUpdate.groupPrivateKey = ByteString.copyFrom(kind.groupPrivateKey) + closedGroupUpdate.addAllSenderKeys(kind.senderKeys.map { it.toProto() }) + closedGroupUpdate.addAllMembers(kind.members.map { ByteString.copyFrom(it) }) + closedGroupUpdate.addAllAdmins(kind.admins.map { ByteString.copyFrom(it) }) + } + is Kind.Info -> { + closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey) + closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.INFO + closedGroupUpdate.name = kind.name + closedGroupUpdate.addAllSenderKeys(kind.senderKeys.map { it.toProto() }) + closedGroupUpdate.addAllMembers(kind.members.map { ByteString.copyFrom(it) }) + closedGroupUpdate.addAllAdmins(kind.admins.map { ByteString.copyFrom(it) }) + } + is Kind.SenderKeyRequest -> { + closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey) + closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY_REQUEST + } + is Kind.SenderKey -> { + closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey) + closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY + closedGroupUpdate.addAllSenderKeys(listOf( kind.senderKey.toProto() )) + } + } + val contentProto = SignalServiceProtos.Content.newBuilder() + val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder() + dataMessageProto.closedGroupUpdate = closedGroupUpdate.build() + contentProto.dataMessage = dataMessageProto.build() + return contentProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct closed group update proto from: $this") + return null + } + return null + } + +} + +// extension functions to class ClosedGroupSenderKey + +private fun ClosedGroupSenderKey.Companion.fromProto(proto: SignalServiceProtos.ClosedGroupUpdate.SenderKey): org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey { + return ClosedGroupSenderKey(chainKey = proto.chainKey.toByteArray(), keyIndex = proto.keyIndex, publicKey = proto.publicKey.toByteArray()) +} + +private fun ClosedGroupSenderKey.toProto(): SignalServiceProtos.ClosedGroupUpdate.SenderKey { + val proto = SignalServiceProtos.ClosedGroupUpdate.SenderKey.newBuilder() + proto.chainKey = ByteString.copyFrom(chainKey) + proto.keyIndex = keyIndex + proto.publicKey = ByteString.copyFrom(publicKey) + return proto.build() } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ControlMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ControlMessage.kt index 670553854c..44cd7ee4d8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ControlMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ControlMessage.kt @@ -1,6 +1,6 @@ -package org.session.messaging.messages.control +package org.session.libsession.messaging.messages.control -import org.session.messaging.messages.Message +import org.session.libsession.messaging.messages.Message -open class ControlMessage : Message() { +abstract class ControlMessage : Message() { } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt index 24d9140792..8ba8b802bd 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.control +package org.session.libsession.messaging.messages.control + +import org.session.libsignal.service.internal.push.SignalServiceProtos class ExpirationTimerUpdate : ControlMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt index 74f96aec81..2aa507065b 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.control +package org.session.libsession.messaging.messages.control + +import org.session.libsignal.service.internal.push.SignalServiceProtos class ReadReceipt : ControlMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): ReadReceipt? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt index 9610e0b88d..a08d8f3ff0 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.control +package org.session.libsession.messaging.messages.control + +import org.session.libsignal.service.internal.push.SignalServiceProtos class TypingIndicator : ControlMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator?{ + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt index a791c32ca3..392d56caf5 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt @@ -1,6 +1,14 @@ -package org.session.messaging.messages.control.unused +package org.session.libsession.messaging.messages.control.unused -import org.session.messaging.messages.control.ControlMessage +import org.session.libsession.messaging.messages.control.ControlMessage +import org.session.libsignal.service.internal.push.SignalServiceProtos class NullMessage : ControlMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): NullMessage? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt index 51f99a7c16..8090d68f68 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt @@ -1,6 +1,14 @@ -package org.session.messaging.messages.control.unused +package org.session.libsession.messaging.messages.control.unused -import org.session.messaging.messages.control.ControlMessage +import org.session.libsession.messaging.messages.control.ControlMessage +import org.session.libsignal.service.internal.push.SignalServiceProtos class SessionRequest : ControlMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): SessionRequest? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt index 7efb865119..cd67a4764e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.visible +package org.session.libsession.messaging.messages.visible -internal class Contact { +import org.session.libsignal.service.internal.push.SignalServiceProtos + +internal class Contact : VisibleMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): Contact? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt index a385545b51..355d8bd0c0 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.visible +package org.session.libsession.messaging.messages.visible -internal class LinkPreview { +import org.session.libsignal.service.internal.push.SignalServiceProtos + +internal class LinkPreview : VisibleMessage(){ + override fun fromProto(proto: SignalServiceProtos.Content): LinkPreview? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index 22740911ea..0b125bb1f9 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.visible +package org.session.libsession.messaging.messages.visible -internal class Profile { +import org.session.libsignal.service.internal.push.SignalServiceProtos + +internal class Profile : VisibleMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): Profile? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt index 90e2c287c5..7c0179e293 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt @@ -1,4 +1,13 @@ -package org.session.messaging.messages.visible +package org.session.libsession.messaging.messages.visible -internal class Quote { +import org.session.libsignal.service.internal.push.SignalServiceProtos + +internal class Quote : VisibleMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): Quote? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index 0b332aaaca..5ea2cea79e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -1,6 +1,6 @@ -package org.session.messaging.messages.visible +package org.session.libsession.messaging.messages.visible -import org.session.messaging.messages.Message +import org.session.libsession.messaging.messages.Message -class VisibleMessage : Message() { +abstract class VisibleMessage : Message() { } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt index fa94a1808e..e0093d9831 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt @@ -1,4 +1,14 @@ -package org.session.messaging.messages.visible.attachments +package org.session.libsession.messaging.messages.visible.attachments -internal class Attachment { +import org.session.libsession.messaging.messages.visible.VisibleMessage +import org.session.libsignal.service.internal.push.SignalServiceProtos + +internal class Attachment : VisibleMessage() { + override fun fromProto(proto: SignalServiceProtos.Content): Attachment? { + TODO("Not yet implemented") + } + + override fun toProto(): SignalServiceProtos.Content? { + TODO("Not yet implemented") + } } \ No newline at end of file From 8f409faefcfb9af2de2dc2c162ee6fed4ad1920f Mon Sep 17 00:00:00 2001 From: Brice Date: Fri, 27 Nov 2020 16:41:21 +1100 Subject: [PATCH 02/11] ExpirationTimerUpdate implementation + classes structure changes --- .../messages/control/ClosedGroupUpdate.kt | 4 +- .../messages/control/ExpirationTimerUpdate.kt | 46 +++++++++++++++++-- .../messaging/messages/control/ReadReceipt.kt | 10 ++-- .../messages/control/TypingIndicator.kt | 7 ++- .../messages/control/unused/NullMessage.kt | 11 +++-- .../messages/control/unused/SessionRequest.kt | 10 ++-- .../messaging/messages/visible/Contact.kt | 8 +++- .../messaging/messages/visible/LinkPreview.kt | 8 +++- .../messaging/messages/visible/Profile.kt | 8 +++- .../messaging/messages/visible/Quote.kt | 8 +++- .../visible/attachments/Attachment.kt | 8 +++- 11 files changed, 101 insertions(+), 27 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt index 18f424ba8e..9ff406e9e7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt @@ -53,7 +53,6 @@ class ClosedGroupUpdate() : ControlMessage() { return ClosedGroupUpdate(kind) } } - //private val TAG: String = ClosedGroupUpdate::class.java.simpleName // Kind enum sealed class Kind { @@ -65,11 +64,12 @@ class ClosedGroupUpdate() : ControlMessage() { var kind: Kind? = null - // constructors + // constructor internal constructor(kind: Kind?) : this() { this.kind = kind } + // validation override fun isValid(): Boolean { if (!super.isValid() || kind == null) return false val kind = kind ?: return false diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt index 8ba8b802bd..c392db9884 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt @@ -1,13 +1,51 @@ package org.session.libsession.messaging.messages.control +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos -class ExpirationTimerUpdate : ControlMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { - TODO("Not yet implemented") +class ExpirationTimerUpdate() : ControlMessage() { + + var duration: Int? = 0 + + companion object { + const val TAG = "ExpirationTimerUpdate" + + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + val dataMessageProto = proto.dataMessage ?: return null + val isExpirationTimerUpdate = (dataMessageProto.flags and SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE) != 0 + if (!isExpirationTimerUpdate) return null + val duration = dataMessageProto.expireTimer + return ExpirationTimerUpdate(duration) + } + } + + //constructor + internal constructor(duration: Int) : this() { + this.duration = duration + } + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + return duration != null } override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + val duration = duration + if (duration == null) { + Log.w(TAG, "Couldn't construct expiration timer update proto from: $this") + return null + } + val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder() + dataMessageProto.flags = SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE + dataMessageProto.expireTimer = duration + val contentProto = SignalServiceProtos.Content.newBuilder() + try { + contentProto.dataMessage = dataMessageProto.build() + return contentProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct expiration timer update proto from: $this") + return null + } } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt index 2aa507065b..152eac8729 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt @@ -2,9 +2,13 @@ package org.session.libsession.messaging.messages.control import org.session.libsignal.service.internal.push.SignalServiceProtos -class ReadReceipt : ControlMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): ReadReceipt? { - TODO("Not yet implemented") +class ReadReceipt() : ControlMessage() { + + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt index a08d8f3ff0..da022a84c1 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt @@ -3,8 +3,11 @@ package org.session.libsession.messaging.messages.control import org.session.libsignal.service.internal.push.SignalServiceProtos class TypingIndicator : ControlMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator?{ - TODO("Not yet implemented") + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt index 392d56caf5..df0887ee8d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt @@ -1,11 +1,16 @@ package org.session.libsession.messaging.messages.control.unused import org.session.libsession.messaging.messages.control.ControlMessage +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos -class NullMessage : ControlMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): NullMessage? { - TODO("Not yet implemented") +class NullMessage() : ControlMessage() { + + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt index 8090d68f68..7285d5c4cb 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt @@ -1,11 +1,15 @@ package org.session.libsession.messaging.messages.control.unused import org.session.libsession.messaging.messages.control.ControlMessage +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos -class SessionRequest : ControlMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): SessionRequest? { - TODO("Not yet implemented") +class SessionRequest() : ControlMessage() { + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt index cd67a4764e..f5f818e86e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt @@ -1,10 +1,14 @@ package org.session.libsession.messaging.messages.visible +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Contact : VisibleMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): Contact? { - TODO("Not yet implemented") + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt index 355d8bd0c0..d758a46cca 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt @@ -1,10 +1,14 @@ package org.session.libsession.messaging.messages.visible +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos internal class LinkPreview : VisibleMessage(){ - override fun fromProto(proto: SignalServiceProtos.Content): LinkPreview? { - TODO("Not yet implemented") + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index 0b125bb1f9..5b172bf5e1 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -1,10 +1,14 @@ package org.session.libsession.messaging.messages.visible +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Profile : VisibleMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): Profile? { - TODO("Not yet implemented") + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt index 7c0179e293..aecf3dc3da 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt @@ -1,10 +1,14 @@ package org.session.libsession.messaging.messages.visible +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Quote : VisibleMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): Quote? { - TODO("Not yet implemented") + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt index e0093d9831..94b7ace5d4 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt @@ -1,11 +1,15 @@ package org.session.libsession.messaging.messages.visible.attachments +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Attachment : VisibleMessage() { - override fun fromProto(proto: SignalServiceProtos.Content): Attachment? { - TODO("Not yet implemented") + + companion object { + fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + TODO("Not yet implemented") + } } override fun toProto(): SignalServiceProtos.Content? { From 746df2240a7bc5705e653b93ef48eff6865395cc Mon Sep 17 00:00:00 2001 From: Brice Date: Fri, 27 Nov 2020 17:27:09 +1100 Subject: [PATCH 03/11] ReadReceipt implementation + small corrections --- .../messaging/messages/control/ReadReceipt.kt | 42 +++++++++++++++++-- .../messages/control/TypingIndicator.kt | 2 +- .../messages/control/unused/NullMessage.kt | 2 +- .../messages/control/unused/SessionRequest.kt | 2 +- .../messaging/messages/visible/Contact.kt | 2 +- .../messaging/messages/visible/LinkPreview.kt | 2 +- .../messaging/messages/visible/Profile.kt | 2 +- .../messaging/messages/visible/Quote.kt | 2 +- .../visible/attachments/Attachment.kt | 2 +- 9 files changed, 47 insertions(+), 11 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt index 152eac8729..c735820b13 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt @@ -1,17 +1,53 @@ package org.session.libsession.messaging.messages.control +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos class ReadReceipt() : ControlMessage() { + var timestamps: LongArray? = null companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { - TODO("Not yet implemented") + const val TAG = "ReadReceipt" + + fun fromProto(proto: SignalServiceProtos.Content): ReadReceipt? { + val receiptProto = proto.receiptMessage ?: return null + if (receiptProto.type != SignalServiceProtos.ReceiptMessage.Type.READ) return null + val timestamps = receiptProto.timestampList + if (timestamps.isEmpty()) return null + return ReadReceipt(timestamps = timestamps.toLongArray()) } } + //constructor + internal constructor(timestamps: LongArray?) : this() { + this.timestamps = timestamps + } + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + val timestamps = timestamps ?: return false + if (timestamps.isNotEmpty()) { return true } + return false + } + override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + val timestamps = timestamps ?: return null + if (timestamps == null) { + Log.w(ExpirationTimerUpdate.TAG, "Couldn't construct read receipt proto from: $this") + return null + } + val receiptProto = SignalServiceProtos.ReceiptMessage.newBuilder() + receiptProto.type = SignalServiceProtos.ReceiptMessage.Type.READ + receiptProto.addAllTimestamp(timestamps.asIterable()) + val contentProto = SignalServiceProtos.Content.newBuilder() + try { + contentProto.receiptMessage = receiptProto.build() + return contentProto.build() + } catch (e: Exception) { + Log.w(ExpirationTimerUpdate.TAG, "Couldn't construct read receipt proto from: $this") + return null + } } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt index da022a84c1..41e9498a60 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt @@ -5,7 +5,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos class TypingIndicator : ControlMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt index df0887ee8d..a2bb642008 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt @@ -8,7 +8,7 @@ class NullMessage() : ControlMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): NullMessage? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt index 7285d5c4cb..173fb141fc 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt @@ -7,7 +7,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos class SessionRequest() : ControlMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): SessionRequest? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt index f5f818e86e..e0c9d2ab34 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt @@ -6,7 +6,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Contact : VisibleMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): Contact? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt index d758a46cca..3bcafd71a7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt @@ -6,7 +6,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos internal class LinkPreview : VisibleMessage(){ companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): LinkPreview? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index 5b172bf5e1..a5b09b4f79 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -6,7 +6,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Profile : VisibleMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): Profile? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt index aecf3dc3da..55b6481c94 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt @@ -6,7 +6,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Quote : VisibleMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): Quote? { TODO("Not yet implemented") } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt index 94b7ace5d4..b7ab2ec8e2 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt @@ -7,7 +7,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos internal class Attachment : VisibleMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { + fun fromProto(proto: SignalServiceProtos.Content): Attachment? { TODO("Not yet implemented") } } From 3a0ba29a7202557c851c4ced4369583b193654e2 Mon Sep 17 00:00:00 2001 From: Brice Date: Mon, 30 Nov 2020 10:08:56 +1100 Subject: [PATCH 04/11] TypingIndicator implementation --- .../messages/control/ClosedGroupUpdate.kt | 20 +++--- .../messaging/messages/control/ReadReceipt.kt | 2 +- .../messages/control/TypingIndicator.kt | 63 ++++++++++++++++++- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt index 9ff406e9e7..9b0ba71cf6 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt @@ -7,6 +7,16 @@ import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSende class ClosedGroupUpdate() : ControlMessage() { + // Kind enum + sealed class Kind { + class New(val groupPublicKey: ByteArray, val name: String, val groupPrivateKey: ByteArray, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() + class Info(val groupPublicKey: ByteArray, val name: String, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() + class SenderKeyRequest(val groupPublicKey: ByteArray) : Kind() + class SenderKey(val groupPublicKey: ByteArray, val senderKey: org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey) : Kind() + } + + var kind: Kind? = null + companion object { const val TAG = "ClosedGroupUpdate" @@ -54,16 +64,6 @@ class ClosedGroupUpdate() : ControlMessage() { } } - // Kind enum - sealed class Kind { - class New(val groupPublicKey: ByteArray, val name: String, val groupPrivateKey: ByteArray, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() - class Info(val groupPublicKey: ByteArray, val name: String, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() - class SenderKeyRequest(val groupPublicKey: ByteArray) : Kind() - class SenderKey(val groupPublicKey: ByteArray, val senderKey: org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey) : Kind() - } - - var kind: Kind? = null - // constructor internal constructor(kind: Kind?) : this() { this.kind = kind diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt index c735820b13..960b5aeaf9 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ReadReceipt.kt @@ -33,7 +33,7 @@ class ReadReceipt() : ControlMessage() { } override fun toProto(): SignalServiceProtos.Content? { - val timestamps = timestamps ?: return null + val timestamps = timestamps if (timestamps == null) { Log.w(ExpirationTimerUpdate.TAG, "Couldn't construct read receipt proto from: $this") return null diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt index 41e9498a60..005b11d155 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt @@ -1,16 +1,73 @@ package org.session.libsession.messaging.messages.control +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos -class TypingIndicator : ControlMessage() { +class TypingIndicator() : ControlMessage() { companion object { + const val TAG = "TypingIndicator" + fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator? { - TODO("Not yet implemented") + val typingIndicatorProto = proto.typingMessage ?: return null + val kind = Kind.fromProto(typingIndicatorProto.action) + return TypingIndicator(kind = kind) } } + // Kind enum + enum class Kind { + STARTED, + STOPPED, + ; + + companion object { + @JvmStatic + fun fromProto(proto: SignalServiceProtos.TypingMessage.Action): Kind = + when (proto) { + SignalServiceProtos.TypingMessage.Action.STARTED -> STARTED + SignalServiceProtos.TypingMessage.Action.STOPPED -> STOPPED + } + } + + fun toProto(): SignalServiceProtos.TypingMessage.Action { + when (this) { + STARTED -> return SignalServiceProtos.TypingMessage.Action.STARTED + STOPPED -> return SignalServiceProtos.TypingMessage.Action.STOPPED + } + } + } + + var kind: Kind? = null + + //constructor + internal constructor(kind: Kind) : this() { + this.kind = kind + } + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + return kind != null + } + override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + val timestamp = sentTimestamp + val kind = kind + if (timestamp == null || kind == null) { + Log.w(TAG, "Couldn't construct typing indicator proto from: $this") + return null + } + val typingIndicatorProto = SignalServiceProtos.TypingMessage.newBuilder() + typingIndicatorProto.timestamp = timestamp + typingIndicatorProto.action = kind.toProto() + val contentProto = SignalServiceProtos.Content.newBuilder() + try { + contentProto.typingMessage = typingIndicatorProto.build() + return contentProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct typing indicator proto from: $this") + return null + } } } \ No newline at end of file From 2c167b0cc0046812a2244f9ee726a6e808f937f4 Mon Sep 17 00:00:00 2001 From: Brice Date: Mon, 30 Nov 2020 10:29:06 +1100 Subject: [PATCH 05/11] NullMessage implementation --- .../messages/control/unused/NullMessage.kt | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt index a2bb642008..b46bbc0231 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/NullMessage.kt @@ -1,19 +1,37 @@ package org.session.libsession.messaging.messages.control.unused +import com.google.protobuf.ByteString import org.session.libsession.messaging.messages.control.ControlMessage -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate +import org.session.libsession.messaging.messages.control.TypingIndicator +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos +import java.security.SecureRandom class NullMessage() : ControlMessage() { companion object { + const val TAG = "NullMessage" + fun fromProto(proto: SignalServiceProtos.Content): NullMessage? { - TODO("Not yet implemented") + if (proto.nullMessage == null) return null + return NullMessage() } } override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + val nullMessageProto = SignalServiceProtos.NullMessage.newBuilder() + val sr = SecureRandom() + val paddingSize = sr.nextInt(512) + val padding = ByteArray(paddingSize) + nullMessageProto.padding = ByteString.copyFrom(padding) + val contentProto = SignalServiceProtos.Content.newBuilder() + try { + contentProto.nullMessage = nullMessageProto.build() + return contentProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct null message proto from: $this") + return null + } } } \ No newline at end of file From 3f0e456002753000c7011ee82122014554bd9b1e Mon Sep 17 00:00:00 2001 From: Brice Date: Mon, 30 Nov 2020 11:23:27 +1100 Subject: [PATCH 06/11] SessionRequest unfinished implementation --- .../libsession/messaging/messages/Message.kt | 6 +- .../messages/control/TypingIndicator.kt | 2 + .../messages/control/unused/SessionRequest.kt | 67 ++++++++++++++++++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt index 6176cee7c8..3f2c5b0fee 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt @@ -15,9 +15,9 @@ abstract class Message { companion object { @JvmStatic - val ttl = 2 * 24 * 60 * 60 * 1000 + val ttl = 2 * 24 * 60 * 60 * 1000 //TODO not sure about that declaration - //fun fromProto(proto: SignalServiceProtos.Content): Message? {} + //TODO how to declare fromProto? } open fun isValid(): Boolean { @@ -26,8 +26,6 @@ abstract class Message { return sender != null && recipient != null } - - abstract fun toProto(): SignalServiceProtos.Content? } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt index 005b11d155..ec9ae23358 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/TypingIndicator.kt @@ -8,6 +8,8 @@ class TypingIndicator() : ControlMessage() { companion object { const val TAG = "TypingIndicator" + //val ttl: 30 * 1000 //TODO + fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator? { val typingIndicatorProto = proto.typingMessage ?: return null val kind = Kind.fromProto(typingIndicatorProto.action) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt index 173fb141fc..8a25b5dccc 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt @@ -1,18 +1,81 @@ package org.session.libsession.messaging.messages.control.unused +import com.google.protobuf.ByteString import org.session.libsession.messaging.messages.control.ControlMessage import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate +import org.session.libsession.messaging.messages.control.TypingIndicator +import org.session.libsignal.libsignal.logging.Log +import org.session.libsignal.libsignal.state.PreKeyBundle import org.session.libsignal.service.internal.push.SignalServiceProtos +import java.security.SecureRandom class SessionRequest() : ControlMessage() { + var preKeyBundle: PreKeyBundle? = null + companion object { + const val TAG = "SessionRequest" + fun fromProto(proto: SignalServiceProtos.Content): SessionRequest? { - TODO("Not yet implemented") + if (proto.nullMessage == null) return null + val preKeyBundleProto = proto.preKeyBundleMessage ?: return null + val registrationID: Int = 0 + //TODO looks like database stuff here + /*iOS code: Configuration.shared.storage.with { transaction in + registrationID = Configuration.shared.storage.getOrGenerateRegistrationID(using: transaction) + }*/ + val preKeyBundle = PreKeyBundle( + registrationID, + 1, + preKeyBundleProto.preKeyId, + null, //TODO preKeyBundleProto.preKey, + 0, //TODO preKeyBundleProto.signedKey, + null, //TODO preKeyBundleProto.signedKeyId, + preKeyBundleProto.signature.toByteArray(), + null, //TODO preKeyBundleProto.identityKey + ) ?: return null + return SessionRequest(preKeyBundle) } } + //constructor + internal constructor(preKeyBundle: PreKeyBundle) : this() { + this.preKeyBundle = preKeyBundle + } + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + return preKeyBundle != null + } + override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + val preKeyBundle = preKeyBundle + if (preKeyBundle == null) { + Log.w(TAG, "Couldn't construct session request proto from: $this") + return null + } + val nullMessageProto = SignalServiceProtos.NullMessage.newBuilder() + val sr = SecureRandom() + val paddingSize = sr.nextInt(512) + val padding = ByteArray(paddingSize) + nullMessageProto.padding = ByteString.copyFrom(padding) + val preKeyBundleProto = SignalServiceProtos.PreKeyBundleMessage.newBuilder() + //TODO preKeyBundleProto.identityKey = preKeyBundle.identityKey + preKeyBundleProto.deviceId = preKeyBundle.deviceId + preKeyBundleProto.preKeyId = preKeyBundle.preKeyId + //TODO preKeyBundleProto.preKey = preKeyBundle.preKeyPublic + preKeyBundleProto.signedKeyId = preKeyBundle.signedPreKeyId + //TODO preKeyBundleProto.signedKey = preKeyBundle.signedPreKeyPublic + preKeyBundleProto.signature = ByteString.copyFrom(preKeyBundle.signedPreKeySignature) + val contentProto = SignalServiceProtos.Content.newBuilder() + try { + contentProto.nullMessage = nullMessageProto.build() + contentProto.preKeyBundleMessage = preKeyBundleProto.build() + return contentProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct session request proto from: $this") + return null + } } } \ No newline at end of file From f5a583e7c86869da97212113b46f1d36108d2298 Mon Sep 17 00:00:00 2001 From: Brice Date: Tue, 1 Dec 2020 16:24:50 +1100 Subject: [PATCH 07/11] classes structure redesign + LinkPreview & BaseVisibleMessage implementations --- .../messages/visible/BaseVisibleMessage.kt | 98 +++++++++++++++++++ .../messaging/messages/visible/Contact.kt | 5 +- .../messaging/messages/visible/LinkPreview.kt | 53 ++++++++-- .../messaging/messages/visible/Profile.kt | 9 +- .../messaging/messages/visible/Quote.kt | 14 ++- .../messages/visible/VisibleMessage.kt | 11 ++- .../visible/attachments/Attachment.kt | 5 +- 7 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt new file mode 100644 index 0000000000..1ea7768381 --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt @@ -0,0 +1,98 @@ +package org.session.libsession.messaging.messages.visible + +import org.session.libsignal.libsignal.logging.Log +import org.session.libsignal.service.internal.push.SignalServiceProtos + +class BaseVisibleMessage() : VisibleMessage() { + + var text: String? = null + var attachmentIDs = ArrayList() + var quote: Quote? = null + var linkPreview: LinkPreview? = null + var contact: Contact? = null + var profile: Profile? = null + + companion object { + const val TAG = "BaseVisibleMessage" + + fun fromProto(proto: SignalServiceProtos.Content): BaseVisibleMessage? { + val dataMessage = proto.dataMessage ?: return null + val result = BaseVisibleMessage() + result.text = dataMessage.body + // Attachments are handled in MessageReceiver + val quoteProto = dataMessage.quote + val quote = Quote.fromProto(quoteProto) + quote?.let { result.quote = quote } + val linkPreviewProto = dataMessage.previewList.first() + val linkPreview = LinkPreview.fromProto(linkPreviewProto) + linkPreview?.let { result.linkPreview = linkPreview } + // TODO Contact + val profile = Profile.fromProto(dataMessage) + if (profile != null) { result.profile = profile } + return result + } + } + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + if (attachmentIDs.isNotEmpty()) return true + val text = text?.trim() ?: return false + if (text.isEmpty()) return true + return false + } + + override fun toProto(transaction: String): SignalServiceProtos.Content? { + val proto = SignalServiceProtos.Content.newBuilder() + var attachmentIDs = this.attachmentIDs + val dataMessage: SignalServiceProtos.DataMessage.Builder + // Profile + val profile = profile + val profileProto = profile?.toProto("") //TODO + if (profileProto != null) { + dataMessage = profileProto.toBuilder() + } else { + dataMessage = SignalServiceProtos.DataMessage.newBuilder() + } + // Text + text?.let { dataMessage.body = text } + // Quote + val quotedAttachmentID = quote?.attachmentID + quotedAttachmentID?.let { + val index = attachmentIDs.indexOf(quotedAttachmentID) + if (index >= 0) { attachmentIDs.removeAt(index) } + } + val quote = quote + quote?.let { + val quoteProto = quote.toProto(transaction) + if (quoteProto != null) dataMessage.quote = quoteProto + } + //Link preview + val linkPreviewAttachmentID = linkPreview?.attachmentID + linkPreviewAttachmentID?.let { + val index = attachmentIDs.indexOf(quotedAttachmentID) + if (index >= 0) { attachmentIDs.removeAt(index) } + } + val linkPreview = linkPreview + linkPreview?.let { + val linkPreviewProto = linkPreview.toProto(transaction) + linkPreviewProto?.let { + dataMessage.addAllPreview(listOf(linkPreviewProto)) + } + } + //Attachments + // TODO I'm blocking on that one... + //swift: let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } + + + // Build + try { + proto.dataMessage = dataMessage.build() + return proto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct visible message proto from: $this") + return null + } + } + +} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt index e0c9d2ab34..cbca11cd2d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Contact.kt @@ -1,9 +1,8 @@ package org.session.libsession.messaging.messages.visible -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos -internal class Contact : VisibleMessage() { +class Contact : VisibleMessage() { companion object { fun fromProto(proto: SignalServiceProtos.Content): Contact? { @@ -11,7 +10,7 @@ internal class Contact : VisibleMessage() { } } - override fun toProto(): SignalServiceProtos.Content? { + override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Contact? { TODO("Not yet implemented") } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt index 3bcafd71a7..90521b6e30 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt @@ -1,17 +1,58 @@ package org.session.libsession.messaging.messages.visible -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate +import org.session.libsession.messaging.messages.control.TypingIndicator +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos -internal class LinkPreview : VisibleMessage(){ +class LinkPreview() : VisibleMessage(){ + + var title: String? = null + var url: String? = null + var attachmentID: String? = null companion object { - fun fromProto(proto: SignalServiceProtos.Content): LinkPreview? { - TODO("Not yet implemented") + const val TAG = "LinkPreview" + + fun fromProto(proto: SignalServiceProtos.DataMessage.Preview): LinkPreview? { + val title = proto.title + val url = proto.url + return LinkPreview(title, url, null) } } - override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + //constructor + internal constructor(title: String?, url: String, attachmentID: String?) : this() { + this.title = title + this.url = url + this.attachmentID = attachmentID + } + + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + return (title != null && url != null && attachmentID != null) + } + + override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Preview? { + val url = url + if (url == null) { + Log.w(TAG, "Couldn't construct link preview proto from: $this") + return null + } + val linkPreviewProto = SignalServiceProtos.DataMessage.Preview.newBuilder() + linkPreviewProto.url = url + title?. let { linkPreviewProto.title = title } + val attachmentID = attachmentID + attachmentID?.let { + //TODO database stuff + } + // Build + try { + return linkPreviewProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct link preview proto from: $this") + return null + } } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index a5b09b4f79..193966e003 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -1,17 +1,16 @@ package org.session.libsession.messaging.messages.visible -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos -internal class Profile : VisibleMessage() { +class Profile() : VisibleMessage() { companion object { - fun fromProto(proto: SignalServiceProtos.Content): Profile? { + fun fromProto(proto: SignalServiceProtos.DataMessage): Profile? { TODO("Not yet implemented") } } - override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + override fun toProto(transaction: String): SignalServiceProtos.DataMessage? { + return null } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt index 55b6481c94..0f60db1865 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt @@ -1,17 +1,21 @@ package org.session.libsession.messaging.messages.visible -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsignal.service.internal.push.SignalServiceProtos -internal class Quote : VisibleMessage() { +class Quote() : VisibleMessage() { + + var timestamp: Long? = 0 + var publicKey: String? = null + var text: String? = null + var attachmentID: String? = null companion object { - fun fromProto(proto: SignalServiceProtos.Content): Quote? { + fun fromProto(proto: SignalServiceProtos.DataMessage.Quote): Quote? { TODO("Not yet implemented") } } - override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") + override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Quote? { + return null } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index 5ea2cea79e..bb60a51817 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -1,6 +1,15 @@ package org.session.libsession.messaging.messages.visible import org.session.libsession.messaging.messages.Message +import org.session.libsignal.service.internal.push.SignalServiceProtos -abstract class VisibleMessage : Message() { +abstract class VisibleMessage : Message() { + + abstract fun toProto(transaction: String): T + + final override fun toProto(): SignalServiceProtos.Content? { + //we don't need to implement this method in subclasses + //TODO it just needs an equivalent to swift: preconditionFailure("Use toProto(using:) instead.") + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt index b7ab2ec8e2..f50ffb6baa 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt @@ -1,10 +1,9 @@ package org.session.libsession.messaging.messages.visible.attachments -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate -import org.session.libsession.messaging.messages.visible.VisibleMessage +import org.session.libsession.messaging.messages.visible.BaseVisibleMessage import org.session.libsignal.service.internal.push.SignalServiceProtos -internal class Attachment : VisibleMessage() { +internal class Attachment : BaseVisibleMessage() { companion object { fun fromProto(proto: SignalServiceProtos.Content): Attachment? { From feec22bf722aeb83bdf6603c34230939e2406554 Mon Sep 17 00:00:00 2001 From: Brice Date: Tue, 1 Dec 2020 17:35:47 +1100 Subject: [PATCH 08/11] Profile implementation --- .../messaging/messages/visible/Profile.kt | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index 193966e003..417599962c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -1,16 +1,65 @@ package org.session.libsession.messaging.messages.visible +import com.google.protobuf.ByteString +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos class Profile() : VisibleMessage() { + var displayName: String? = null + var profileKey: ByteArray? = null + var profilePictureURL: String? = null + companion object { + const val TAG = "Profile" + fun fromProto(proto: SignalServiceProtos.DataMessage): Profile? { - TODO("Not yet implemented") + val profileProto = proto.profile ?: return null + val displayName = profileProto.displayName ?: return null + val profileKey = proto.profileKey + val profilePictureURL = profileProto.profilePictureURL + profileKey?.let { + val profilePictureURL = profilePictureURL + profilePictureURL?.let { + return Profile(displayName = displayName, profileKey = profileKey.toByteArray(), profilePictureURL = profilePictureURL) + } + return Profile(displayName) + } + } } + //constructor + internal constructor(displayName: String, profileKey: ByteArray? = nil, profilePictureURL: String? = nil) : this() { + this.displayName = displayName + this.profileKey = profileKey + this.profilePictureURL = profilePictureURL + } + + fun toProto(): SignalServiceProtos.DataMessage? { + return this.toProto("") + } + override fun toProto(transaction: String): SignalServiceProtos.DataMessage? { - return null + val displayName = displayName + if (displayName == null) { + Log.w(TAG, "Couldn't construct link preview proto from: $this") + return null + } + val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder() + val profileProto = SignalServiceProtos.LokiUserProfile.newBuilder() + profileProto.displayName = displayName + val profileKey = profileKey + profileKey?.let { dataMessageProto.profileKey = ByteString.copyFrom(profileKey) } + val profilePictureURL = profilePictureURL + profilePictureURL?.let { profileProto.profilePictureURL = profilePictureURL } + // Build + try { + dataMessageProto.profile = profileProto.build() + return dataMessageProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct profile proto from: $this") + return null + } } } \ No newline at end of file From 344af77f0f6408238a2f70f3b9b9ee02390355d8 Mon Sep 17 00:00:00 2001 From: Brice Date: Wed, 2 Dec 2020 11:44:55 +1100 Subject: [PATCH 09/11] incomplete Quote implementation --- .../messaging/messages/visible/Profile.kt | 7 +-- .../messaging/messages/visible/Quote.kt | 55 ++++++++++++++++++- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index 417599962c..5a2590b56d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -23,20 +23,19 @@ class Profile() : VisibleMessage() { profilePictureURL?.let { return Profile(displayName = displayName, profileKey = profileKey.toByteArray(), profilePictureURL = profilePictureURL) } - return Profile(displayName) } - + return Profile(displayName) } } //constructor - internal constructor(displayName: String, profileKey: ByteArray? = nil, profilePictureURL: String? = nil) : this() { + internal constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() { this.displayName = displayName this.profileKey = profileKey this.profilePictureURL = profilePictureURL } - fun toProto(): SignalServiceProtos.DataMessage? { + fun toSSProto(): SignalServiceProtos.DataMessage? { return this.toProto("") } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt index 0f60db1865..47a9e99626 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt @@ -1,5 +1,6 @@ package org.session.libsession.messaging.messages.visible +import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.service.internal.push.SignalServiceProtos class Quote() : VisibleMessage() { @@ -10,12 +11,62 @@ class Quote() : VisibleMessage() { var attachmentID: String? = null companion object { + const val TAG = "Quote" + fun fromProto(proto: SignalServiceProtos.DataMessage.Quote): Quote? { - TODO("Not yet implemented") + val timestamp = proto.id + val publicKey = proto.author + val text = proto.text + return Quote(timestamp, publicKey, text, null) } } + //constructor + internal constructor(timestamp: Long, publicKey: String, text: String?, attachmentID: String?) : this() { + this.timestamp = timestamp + this.publicKey = publicKey + this.text = text + this.attachmentID = attachmentID + } + + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + return (timestamp != null && publicKey != null) + } + override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Quote? { - return null + val timestamp = timestamp + val publicKey = publicKey + if (timestamp == null || publicKey == null) { + Log.w(TAG, "Couldn't construct quote proto from: $this") + return null + } + val quoteProto = SignalServiceProtos.DataMessage.Quote.newBuilder() + quoteProto.id = timestamp + quoteProto.author = publicKey + text?.let { quoteProto.text = text } + //TODO addAttachmentsIfNeeded(quoteProto, transaction) + // Build + try { + return quoteProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct quote proto from: $this") + return null + } + } + + private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder, transaction: String) { + val attachmentID = attachmentID ?: return + //TODO databas stuff + val quotedAttachmentProto = SignalServiceProtos.DataMessage.Quote.QuotedAttachment.newBuilder() + //TODO more database related stuff + //quotedAttachmentProto.contentType = + try { + quoteProto.addAttachments(quotedAttachmentProto.build()) + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct quoted attachment proto from: $this") + } } } \ No newline at end of file From aefe721fa41b078c1a04873201b93b04ef288426 Mon Sep 17 00:00:00 2001 From: Brice Date: Wed, 2 Dec 2020 15:02:46 +1100 Subject: [PATCH 10/11] Attachment implementation --- .../messages/control/ClosedGroupUpdate.kt | 2 +- .../messaging/messages/visible/Attachment.kt | 71 +++++++++++++++++++ .../visible/attachments/Attachment.kt | 17 ----- 3 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt delete mode 100644 libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt index 9b0ba71cf6..f72c8a1dce 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt @@ -141,7 +141,7 @@ class ClosedGroupUpdate() : ControlMessage() { // extension functions to class ClosedGroupSenderKey -private fun ClosedGroupSenderKey.Companion.fromProto(proto: SignalServiceProtos.ClosedGroupUpdate.SenderKey): org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey { +private fun ClosedGroupSenderKey.Companion.fromProto(proto: SignalServiceProtos.ClosedGroupUpdate.SenderKey): ClosedGroupSenderKey { return ClosedGroupSenderKey(chainKey = proto.chainKey.toByteArray(), keyIndex = proto.keyIndex, publicKey = proto.publicKey.toByteArray()) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt new file mode 100644 index 0000000000..3e1530f34e --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt @@ -0,0 +1,71 @@ +package org.session.libsession.messaging.messages.visible + +import android.util.Size +import android.webkit.MimeTypeMap +import org.session.libsignal.service.internal.push.SignalServiceProtos +import java.io.File +import java.net.URL +import kotlin.math.absoluteValue + +class Attachment : VisibleMessage() { + + var fileName: String? = null + var contentType: String? = null + var key: ByteArray? = null + var digest: ByteArray? = null + var kind: Kind? = null + var caption: String? = null + var size: Size? = null + var sizeInBytes: Int? = 0 + var url: String? = null + + companion object { + fun fromProto(proto: SignalServiceProtos.AttachmentPointer): Attachment? { + val result = Attachment() + result.fileName = proto.fileName + fun inferContentType(): String { + val fileName = result.fileName ?: return "application/octet-stream" //TODO find equivalent to OWSMimeTypeApplicationOctetStream + val fileExtension = File(fileName).extension + val mimeTypeMap = MimeTypeMap.getSingleton() + return mimeTypeMap.getMimeTypeFromExtension(fileExtension) ?: "application/octet-stream" //TODO check that it's correct + } + result.contentType = proto.contentType ?: inferContentType() + result.key = proto.key.toByteArray() + result.digest = proto.digest.toByteArray() + val kind: Kind + if (proto.hasFlags() && (proto.flags and SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE_VALUE) > 0) { + kind = Kind.VOICEMESSAGE + } else { + kind = Kind.GENERIC + } + result.kind = kind + result.caption = if (proto.hasCaption()) proto.caption else null + val size: Size + if (proto.hasWidth() && proto.width > 0 && proto.hasHeight() && proto.height > 0) { + size = Size(proto.width, proto.height) + } else { + size = Size(0,0) //TODO check that it's equivalent to swift: CGSize.zero + } + result.size = size + result.sizeInBytes = if (proto.size > 0) proto.size else null + result. url = proto.url + return result + } + } + + enum class Kind { + VOICEMESSAGE, + GENERIC + } + + // validation + override fun isValid(): Boolean { + if (!super.isValid()) return false + // key and digest can be nil for open group attachments + return (contentType != null && kind != null && size != null && sizeInBytes != null && url != null) + } + + override fun toProto(transaction: String): SignalServiceProtos.AttachmentPointer? { + TODO("Not implemented") + } +} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt deleted file mode 100644 index f50ffb6baa..0000000000 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/attachments/Attachment.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.session.libsession.messaging.messages.visible.attachments - -import org.session.libsession.messaging.messages.visible.BaseVisibleMessage -import org.session.libsignal.service.internal.push.SignalServiceProtos - -internal class Attachment : BaseVisibleMessage() { - - companion object { - fun fromProto(proto: SignalServiceProtos.Content): Attachment? { - TODO("Not yet implemented") - } - } - - override fun toProto(): SignalServiceProtos.Content? { - TODO("Not yet implemented") - } -} \ No newline at end of file From a69916895692d440b50871443452e7e5aa8db59d Mon Sep 17 00:00:00 2001 From: Brice Date: Wed, 2 Dec 2020 16:21:38 +1100 Subject: [PATCH 11/11] code review, minor changes --- .../messaging/messages/Destination.kt | 3 +++ .../libsession/messaging/messages/Message.kt | 3 +-- .../messages/control/ClosedGroupUpdate.kt | 8 ++++---- .../messages/control/ExpirationTimerUpdate.kt | 2 +- .../messages/control/unused/SessionRequest.kt | 2 +- .../messaging/messages/visible/Attachment.kt | 2 +- .../messages/visible/BaseVisibleMessage.kt | 20 +++++++++++-------- .../messaging/messages/visible/LinkPreview.kt | 2 +- .../messaging/messages/visible/Quote.kt | 2 +- .../messages/visible/VisibleMessage.kt | 4 ++-- 10 files changed, 27 insertions(+), 21 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt index 8c255bdce5..a0573bd19c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt @@ -6,4 +6,7 @@ sealed class Destination { class ClosedGroup(val groupPublicKey: String) class OpenGroup(val channel: Long, val server: String) + companion object { + //TODO need to implement the equivalent to TSThread and then implement from(...) + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt index 3f2c5b0fee..3e92077689 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt @@ -16,10 +16,9 @@ abstract class Message { companion object { @JvmStatic val ttl = 2 * 24 * 60 * 60 * 1000 //TODO not sure about that declaration - - //TODO how to declare fromProto? } + // validation open fun isValid(): Boolean { sentTimestamp = if (sentTimestamp!! > 0) sentTimestamp else return false receivedTimestamp = if (receivedTimestamp!! > 0) receivedTimestamp else return false diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt index f72c8a1dce..75486b6557 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupUpdate.kt @@ -7,6 +7,8 @@ import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSende class ClosedGroupUpdate() : ControlMessage() { + var kind: Kind? = null + // Kind enum sealed class Kind { class New(val groupPublicKey: ByteArray, val name: String, val groupPrivateKey: ByteArray, val senderKeys: Collection, val members: Collection, val admins: Collection) : Kind() @@ -15,15 +17,13 @@ class ClosedGroupUpdate() : ControlMessage() { class SenderKey(val groupPublicKey: ByteArray, val senderKey: org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey) : Kind() } - var kind: Kind? = null - companion object { const val TAG = "ClosedGroupUpdate" fun fromProto(proto: SignalServiceProtos.Content): ClosedGroupUpdate? { val closedGroupUpdateProto = proto.dataMessage?.closedGroupUpdate ?: return null val groupPublicKey = closedGroupUpdateProto.groupPublicKey - var kind: Kind? = null + var kind: Kind when(closedGroupUpdateProto.type) { SignalServiceProtos.ClosedGroupUpdate.Type.NEW -> { val name = closedGroupUpdateProto.name ?: return null @@ -71,7 +71,7 @@ class ClosedGroupUpdate() : ControlMessage() { // validation override fun isValid(): Boolean { - if (!super.isValid() || kind == null) return false + if (!super.isValid()) return false val kind = kind ?: return false when(kind) { is Kind.New -> { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt index c392db9884..9f2a38c86c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt @@ -12,7 +12,7 @@ class ExpirationTimerUpdate() : ControlMessage() { fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { val dataMessageProto = proto.dataMessage ?: return null - val isExpirationTimerUpdate = (dataMessageProto.flags and SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE) != 0 + val isExpirationTimerUpdate = (dataMessageProto.flags and SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE) != 0 //TODO validate that 'and' operator equivalent to Swift '&' if (!isExpirationTimerUpdate) return null val duration = dataMessageProto.expireTimer return ExpirationTimerUpdate(duration) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt index 8a25b5dccc..b078ce5545 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/unused/SessionRequest.kt @@ -33,7 +33,7 @@ class SessionRequest() : ControlMessage() { null, //TODO preKeyBundleProto.signedKeyId, preKeyBundleProto.signature.toByteArray(), null, //TODO preKeyBundleProto.identityKey - ) ?: return null + ) return SessionRequest(preKeyBundle) } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt index 3e1530f34e..7a37ef4849 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt @@ -33,7 +33,7 @@ class Attachment : VisibleMessage() { result.key = proto.key.toByteArray() result.digest = proto.digest.toByteArray() val kind: Kind - if (proto.hasFlags() && (proto.flags and SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE_VALUE) > 0) { + if (proto.hasFlags() && (proto.flags and SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE_VALUE) > 0) { //TODO validate that 'and' operator = swift '&' kind = Kind.VOICEMESSAGE } else { kind = Kind.GENERIC diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt index 1ea7768381..5e3fab2d1c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/BaseVisibleMessage.kt @@ -21,14 +21,18 @@ class BaseVisibleMessage() : VisibleMessage() { result.text = dataMessage.body // Attachments are handled in MessageReceiver val quoteProto = dataMessage.quote - val quote = Quote.fromProto(quoteProto) - quote?.let { result.quote = quote } + quoteProto?.let { + val quote = Quote.fromProto(quoteProto) + quote?.let { result.quote = quote } + } val linkPreviewProto = dataMessage.previewList.first() - val linkPreview = LinkPreview.fromProto(linkPreviewProto) - linkPreview?.let { result.linkPreview = linkPreview } + linkPreviewProto?.let { + val linkPreview = LinkPreview.fromProto(linkPreviewProto) + linkPreview?.let { result.linkPreview = linkPreview } + } // TODO Contact val profile = Profile.fromProto(dataMessage) - if (profile != null) { result.profile = profile } + profile?.let { result.profile = profile } return result } } @@ -38,7 +42,7 @@ class BaseVisibleMessage() : VisibleMessage() { if (!super.isValid()) return false if (attachmentIDs.isNotEmpty()) return true val text = text?.trim() ?: return false - if (text.isEmpty()) return true + if (text.isNotEmpty()) return true return false } @@ -48,7 +52,7 @@ class BaseVisibleMessage() : VisibleMessage() { val dataMessage: SignalServiceProtos.DataMessage.Builder // Profile val profile = profile - val profileProto = profile?.toProto("") //TODO + val profileProto = profile?.toSSProto() if (profileProto != null) { dataMessage = profileProto.toBuilder() } else { @@ -84,7 +88,7 @@ class BaseVisibleMessage() : VisibleMessage() { // TODO I'm blocking on that one... //swift: let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } - + // TODO Contact // Build try { proto.dataMessage = dataMessage.build() diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt index 90521b6e30..7806e9fbe0 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/LinkPreview.kt @@ -42,7 +42,7 @@ class LinkPreview() : VisibleMessage() } val linkPreviewProto = SignalServiceProtos.DataMessage.Preview.newBuilder() linkPreviewProto.url = url - title?. let { linkPreviewProto.title = title } + title?.let { linkPreviewProto.title = title } val attachmentID = attachmentID attachmentID?.let { //TODO database stuff diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt index 47a9e99626..0d07821e40 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Quote.kt @@ -47,7 +47,7 @@ class Quote() : VisibleMessage() { quoteProto.id = timestamp quoteProto.author = publicKey text?.let { quoteProto.text = text } - //TODO addAttachmentsIfNeeded(quoteProto, transaction) + addAttachmentsIfNeeded(quoteProto, transaction) // Build try { return quoteProto.build() diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index bb60a51817..dd1068cc45 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -9,7 +9,7 @@ abstract class VisibleMessage : Me final override fun toProto(): SignalServiceProtos.Content? { //we don't need to implement this method in subclasses - //TODO it just needs an equivalent to swift: preconditionFailure("Use toProto(using:) instead.") - TODO("Not yet implemented") + //TODO it just needs an equivalent to swift: preconditionFailure("Use toProto(using:) if that exists... + TODO("Not implemented") } } \ No newline at end of file