Apply conversation config on messages being converted to protobuf

This commit is contained in:
charles 2022-12-22 19:33:33 +11:00
parent cdbf76c0f1
commit b1f69539a9
11 changed files with 38 additions and 34 deletions

View File

@ -39,16 +39,16 @@ abstract class Message {
dataMessage.group = groupProto.build() dataMessage.group = groupProto.build()
} }
fun setExpirationConfigurationIfNeeded(builder: SignalServiceProtos.Content.Builder) { fun SignalServiceProtos.Content.Builder.setExpirationConfigurationIfNeeded(threadId: Long?) {
val config = threadID?.let { MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(it) } val config = threadId?.let { MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(it) }
?: run { ?: run {
builder.expirationTimer = 0 expirationTimer = 0
return return
} }
builder.expirationTimer = config.durationSeconds expirationTimer = config.durationSeconds
builder.lastDisappearingMessageChangeTimestamp = config.updatedTimestampMs lastDisappearingMessageChangeTimestamp = config.updatedTimestampMs
if (config.isEnabled) { if (config.isEnabled) {
builder.expirationType = config.expirationType expirationType = config.expirationType
} }
} }
} }

View File

@ -82,7 +82,7 @@ class CallMessage(): ControlMessage() {
.setUuid(callId!!.toString()) .setUuid(callId!!.toString())
val content = SignalServiceProtos.Content.newBuilder() val content = SignalServiceProtos.Content.newBuilder()
setExpirationConfigurationIfNeeded(content) content.setExpirationConfigurationIfNeeded(threadID)
return content return content
.setCallMessage(callMessage) .setCallMessage(callMessage)

View File

@ -1,18 +1,21 @@
package org.session.libsession.messaging.messages.control package org.session.libsession.messaging.messages.control
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.utilities.Address
import org.session.libsignal.crypto.ecc.DjbECPrivateKey import org.session.libsignal.crypto.ecc.DjbECPrivateKey
import org.session.libsignal.crypto.ecc.DjbECPublicKey import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.crypto.ecc.ECKeyPair import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.protos.SignalServiceProtos.DataMessage import org.session.libsignal.protos.SignalServiceProtos.DataMessage
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
import org.session.libsignal.utilities.toHexString
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
import org.session.libsignal.utilities.toHexString
class ClosedGroupControlMessage() : ControlMessage() { class ClosedGroupControlMessage() : ControlMessage() {
var kind: Kind? = null var kind: Kind? = null
var groupID: String? = null
override val defaultTtl: Long get() { override val defaultTtl: Long get() {
return when (kind) { return when (kind) {
@ -118,8 +121,9 @@ class ClosedGroupControlMessage() : ControlMessage() {
} }
} }
internal constructor(kind: Kind?) : this() { internal constructor(kind: Kind?, groupID: String? = null) : this() {
this.kind = kind this.kind = kind
this.groupID = groupID
} }
override fun toProto(): SignalServiceProtos.Content? { override fun toProto(): SignalServiceProtos.Content? {
@ -167,11 +171,12 @@ class ClosedGroupControlMessage() : ControlMessage() {
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
val dataMessageProto = DataMessage.newBuilder() val dataMessageProto = DataMessage.newBuilder()
dataMessageProto.closedGroupControlMessage = closedGroupControlMessage.build() dataMessageProto.closedGroupControlMessage = closedGroupControlMessage.build()
// Expiration timer
setExpirationConfigurationIfNeeded(contentProto)
// Group context // Group context
setGroupContext(dataMessageProto) setGroupContext(dataMessageProto)
contentProto.dataMessage = dataMessageProto.build() contentProto.dataMessage = dataMessageProto.build()
// Expiration timer
val threadId = groupID?.let { MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(Address.fromSerialized(it)) }
contentProto.setExpirationConfigurationIfNeeded(threadId)
return contentProto.build() return contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct closed group control message proto from: $this.") Log.w(TAG, "Couldn't construct closed group control message proto from: $this.")

View File

@ -64,7 +64,7 @@ class DataExtractionNotification() : ControlMessage() {
} }
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
contentProto.dataExtractionNotification = dataExtractionNotification.build() contentProto.dataExtractionNotification = dataExtractionNotification.build()
setExpirationConfigurationIfNeeded(contentProto) contentProto.setExpirationConfigurationIfNeeded(threadID)
return contentProto.build() return contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct data extraction notification proto from: $this") Log.w(TAG, "Couldn't construct data extraction notification proto from: $this")

View File

@ -64,7 +64,7 @@ class ExpirationTimerUpdate() : ControlMessage() {
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
return try { return try {
contentProto.dataMessage = dataMessageProto.build() contentProto.dataMessage = dataMessageProto.build()
setExpirationConfigurationIfNeeded(contentProto) contentProto.setExpirationConfigurationIfNeeded(threadID)
contentProto.build() contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct expiration timer update proto from: $this") Log.w(TAG, "Couldn't construct expiration timer update proto from: $this")

View File

@ -13,7 +13,7 @@ class MessageRequestResponse(val isApproved: Boolean) : ControlMessage() {
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
return try { return try {
contentProto.messageRequestResponse = messageRequestResponseProto.build() contentProto.messageRequestResponse = messageRequestResponseProto.build()
setExpirationConfigurationIfNeeded(contentProto) contentProto.setExpirationConfigurationIfNeeded(threadID)
contentProto.build() contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct message request response proto from: $this") Log.w(TAG, "Couldn't construct message request response proto from: $this")

View File

@ -41,7 +41,7 @@ class ReadReceipt() : ControlMessage() {
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
return try { return try {
contentProto.receiptMessage = receiptProto.build() contentProto.receiptMessage = receiptProto.build()
setExpirationConfigurationIfNeeded(contentProto) contentProto.setExpirationConfigurationIfNeeded(threadID)
contentProto.build() contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct read receipt proto from: $this") Log.w(TAG, "Couldn't construct read receipt proto from: $this")

View File

@ -60,7 +60,7 @@ class TypingIndicator() : ControlMessage() {
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
return try { return try {
contentProto.typingMessage = typingIndicatorProto.build() contentProto.typingMessage = typingIndicatorProto.build()
setExpirationConfigurationIfNeeded(contentProto) contentProto.setExpirationConfigurationIfNeeded(threadID)
contentProto.build() contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct typing indicator proto from: $this") Log.w(TAG, "Couldn't construct typing indicator proto from: $this")

View File

@ -45,7 +45,7 @@ class UnsendRequest(): ControlMessage() {
val contentProto = SignalServiceProtos.Content.newBuilder() val contentProto = SignalServiceProtos.Content.newBuilder()
return try { return try {
contentProto.unsendRequest = unsendRequestProto.build() contentProto.unsendRequest = unsendRequestProto.build()
setExpirationConfigurationIfNeeded(contentProto) contentProto.setExpirationConfigurationIfNeeded(threadID)
contentProto.build() contentProto.build()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Couldn't construct unsend request proto from: $this") Log.w(TAG, "Couldn't construct unsend request proto from: $this")

View File

@ -116,7 +116,7 @@ class VisibleMessage : Message() {
dataMessage.addAllAttachments(pointers) dataMessage.addAllAttachments(pointers)
// TODO: Contact // TODO: Contact
// Expiration timer // Expiration timer
setExpirationConfigurationIfNeeded(proto) proto.setExpirationConfigurationIfNeeded(threadID)
// Group context // Group context
val storage = MessagingModuleConfiguration.shared.storage val storage = MessagingModuleConfiguration.shared.storage
if (storage.isClosedGroup(recipient!!)) { if (storage.isClosedGroup(recipient!!)) {

View File

@ -15,18 +15,17 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.crypto.ecc.Curve import org.session.libsignal.crypto.ecc.Curve
import org.session.libsignal.crypto.ecc.ECKeyPair import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.utilities.guava.Optional
import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.ThreadUtils
import org.session.libsignal.utilities.guava.Optional
import org.session.libsignal.utilities.hexEncodedPublicKey import org.session.libsignal.utilities.hexEncodedPublicKey
import org.session.libsignal.utilities.removingIdPrefixIfNeeded import org.session.libsignal.utilities.removingIdPrefixIfNeeded
import org.session.libsignal.utilities.Hex import java.util.LinkedList
import org.session.libsignal.utilities.ThreadUtils
import org.session.libsignal.utilities.Log
import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
const val groupSizeLimit = 100 const val groupSizeLimit = 100
@ -49,14 +48,14 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey) val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val admins = setOf( userPublicKey ) val admins = setOf( userPublicKey )
val adminsAsData = admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) } val adminsAsData = admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }
storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }), storage.createGroup(groupID, name, LinkedList(members.map { fromSerialized(it) }),
null, null, LinkedList(admins.map { Address.fromSerialized(it) }), System.currentTimeMillis()) null, null, LinkedList(admins.map { Address.fromSerialized(it) }), System.currentTimeMillis())
storage.setProfileSharing(Address.fromSerialized(groupID), true) storage.setProfileSharing(Address.fromSerialized(groupID), true)
// Send a closed group update message to all members individually // Send a closed group update message to all members individually
val closedGroupUpdateKind = ClosedGroupControlMessage.Kind.New(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), name, encryptionKeyPair, membersAsData, adminsAsData, 0) val closedGroupUpdateKind = ClosedGroupControlMessage.Kind.New(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), name, encryptionKeyPair, membersAsData, adminsAsData, 0)
val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset
for (member in members) { for (member in members) {
val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupUpdateKind) val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupUpdateKind, groupID)
closedGroupControlMessage.sentTimestamp = sentTime closedGroupControlMessage.sentTimestamp = sentTime
try { try {
sendNonDurably(closedGroupControlMessage, Address.fromSerialized(member)).get() sendNonDurably(closedGroupControlMessage, Address.fromSerialized(member)).get()
@ -115,7 +114,7 @@ fun MessageSender.setName(groupPublicKey: String, newName: String) {
// Send the update to the group // Send the update to the group
val kind = ClosedGroupControlMessage.Kind.NameChange(newName) val kind = ClosedGroupControlMessage.Kind.NameChange(newName)
val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset
val closedGroupControlMessage = ClosedGroupControlMessage(kind) val closedGroupControlMessage = ClosedGroupControlMessage(kind, groupID)
closedGroupControlMessage.sentTimestamp = sentTime closedGroupControlMessage.sentTimestamp = sentTime
send(closedGroupControlMessage, Address.fromSerialized(groupID)) send(closedGroupControlMessage, Address.fromSerialized(groupID))
// Update the group // Update the group
@ -155,13 +154,13 @@ fun MessageSender.addMembers(groupPublicKey: String, membersToAdd: List<String>)
// Send the update to the group // Send the update to the group
val memberUpdateKind = ClosedGroupControlMessage.Kind.MembersAdded(newMembersAsData) val memberUpdateKind = ClosedGroupControlMessage.Kind.MembersAdded(newMembersAsData)
val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset
val closedGroupControlMessage = ClosedGroupControlMessage(memberUpdateKind) val closedGroupControlMessage = ClosedGroupControlMessage(memberUpdateKind, groupID)
closedGroupControlMessage.sentTimestamp = sentTime closedGroupControlMessage.sentTimestamp = sentTime
send(closedGroupControlMessage, Address.fromSerialized(groupID)) send(closedGroupControlMessage, Address.fromSerialized(groupID))
// Send closed group update messages to any new members individually // Send closed group update messages to any new members individually
for (member in membersToAdd) { for (member in membersToAdd) {
val closedGroupNewKind = ClosedGroupControlMessage.Kind.New(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), name, encryptionKeyPair, membersAsData, adminsAsData, expireTimer) val closedGroupNewKind = ClosedGroupControlMessage.Kind.New(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), name, encryptionKeyPair, membersAsData, adminsAsData, expireTimer)
val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupNewKind) val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupNewKind, groupID)
// It's important that the sent timestamp of this message is greater than the sent timestamp // It's important that the sent timestamp of this message is greater than the sent timestamp
// of the `MembersAdded` message above. The reason is that upon receiving this `New` message, // of the `MembersAdded` message above. The reason is that upon receiving this `New` message,
// the recipient will update the closed group formation timestamp and ignore any closed group // the recipient will update the closed group formation timestamp and ignore any closed group
@ -210,7 +209,7 @@ fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List<St
// Send the update to the group // Send the update to the group
val memberUpdateKind = ClosedGroupControlMessage.Kind.MembersRemoved(removeMembersAsData) val memberUpdateKind = ClosedGroupControlMessage.Kind.MembersRemoved(removeMembersAsData)
val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset
val closedGroupControlMessage = ClosedGroupControlMessage(memberUpdateKind) val closedGroupControlMessage = ClosedGroupControlMessage(memberUpdateKind, groupID)
closedGroupControlMessage.sentTimestamp = sentTime closedGroupControlMessage.sentTimestamp = sentTime
send(closedGroupControlMessage, Address.fromSerialized(groupID)) send(closedGroupControlMessage, Address.fromSerialized(groupID))
// Send the new encryption key pair to the remaining group members. // Send the new encryption key pair to the remaining group members.
@ -239,7 +238,7 @@ fun MessageSender.leave(groupPublicKey: String, notifyUser: Boolean = true): Pro
val admins = group.admins.map { it.serialize() } val admins = group.admins.map { it.serialize() }
val name = group.title val name = group.title
// Send the update to the group // Send the update to the group
val closedGroupControlMessage = ClosedGroupControlMessage(ClosedGroupControlMessage.Kind.MemberLeft()) val closedGroupControlMessage = ClosedGroupControlMessage(ClosedGroupControlMessage.Kind.MemberLeft(), groupID)
val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset
closedGroupControlMessage.sentTimestamp = sentTime closedGroupControlMessage.sentTimestamp = sentTime
storage.setActive(groupID, false) storage.setActive(groupID, false)
@ -300,7 +299,7 @@ fun MessageSender.sendEncryptionKeyPair(groupPublicKey: String, newKeyPair: ECKe
} }
val kind = ClosedGroupControlMessage.Kind.EncryptionKeyPair(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), wrappers) val kind = ClosedGroupControlMessage.Kind.EncryptionKeyPair(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), wrappers)
val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset val sentTime = System.currentTimeMillis() + SnodeAPI.clockOffset
val closedGroupControlMessage = ClosedGroupControlMessage(kind) val closedGroupControlMessage = ClosedGroupControlMessage(kind, null)
closedGroupControlMessage.sentTimestamp = sentTime closedGroupControlMessage.sentTimestamp = sentTime
return if (force) { return if (force) {
MessageSender.sendNonDurably(closedGroupControlMessage, Address.fromSerialized(destination)) MessageSender.sendNonDurably(closedGroupControlMessage, Address.fromSerialized(destination))
@ -334,6 +333,6 @@ fun MessageSender.sendLatestEncryptionKeyPair(publicKey: String, groupPublicKey:
Log.d("Loki", "Sending latest encryption key pair to: $publicKey.") Log.d("Loki", "Sending latest encryption key pair to: $publicKey.")
val wrapper = ClosedGroupControlMessage.KeyPairWrapper(publicKey, ByteString.copyFrom(ciphertext)) val wrapper = ClosedGroupControlMessage.KeyPairWrapper(publicKey, ByteString.copyFrom(ciphertext))
val kind = ClosedGroupControlMessage.Kind.EncryptionKeyPair(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), listOf(wrapper)) val kind = ClosedGroupControlMessage.Kind.EncryptionKeyPair(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), listOf(wrapper))
val closedGroupControlMessage = ClosedGroupControlMessage(kind) val closedGroupControlMessage = ClosedGroupControlMessage(kind, groupID)
MessageSender.send(closedGroupControlMessage, Address.fromSerialized(publicKey)) MessageSender.send(closedGroupControlMessage, Address.fromSerialized(publicKey))
} }