mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-25 02:55:23 +00:00
Fix Message#expiryMode de/serialisation
This commit is contained in:
parent
cb0327ecb2
commit
4c7485f53d
@ -14,6 +14,7 @@ import org.session.libsession.utilities.ExpirationUtil
|
|||||||
import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol
|
import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsession.utilities.getExpirationTypeDisplayValue
|
import org.session.libsession.utilities.getExpirationTypeDisplayValue
|
||||||
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
import org.thoughtcrime.securesms.showSessionDialog
|
import org.thoughtcrime.securesms.showSessionDialog
|
||||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||||
@ -25,11 +26,11 @@ class DisappearingMessages @Inject constructor(
|
|||||||
private val textSecurePreferences: TextSecurePreferences,
|
private val textSecurePreferences: TextSecurePreferences,
|
||||||
private val messageExpirationManager: MessageExpirationManagerProtocol,
|
private val messageExpirationManager: MessageExpirationManagerProtocol,
|
||||||
) {
|
) {
|
||||||
fun set(threadId: Long, address: Address, mode: ExpiryMode) {
|
fun set(threadId: Long, address: Address, mode: ExpiryMode, isGroup: Boolean) {
|
||||||
val expiryChangeTimestampMs = SnodeAPI.nowWithOffset
|
val expiryChangeTimestampMs = SnodeAPI.nowWithOffset
|
||||||
MessagingModuleConfiguration.shared.storage.setExpirationConfiguration(ExpirationConfiguration(threadId, mode, expiryChangeTimestampMs))
|
MessagingModuleConfiguration.shared.storage.setExpirationConfiguration(ExpirationConfiguration(threadId, mode, expiryChangeTimestampMs))
|
||||||
|
|
||||||
val message = ExpirationTimerUpdate().apply {
|
val message = ExpirationTimerUpdate(isGroup = isGroup).apply {
|
||||||
expiryMode = mode
|
expiryMode = mode
|
||||||
sender = textSecurePreferences.getLocalNumber()
|
sender = textSecurePreferences.getLocalNumber()
|
||||||
isSenderSelf = true
|
isSenderSelf = true
|
||||||
@ -62,7 +63,7 @@ class DisappearingMessages @Inject constructor(
|
|||||||
text = if (message.expiresIn == 0L) R.string.dialog_disappearing_messages_follow_setting_confirm else R.string.dialog_disappearing_messages_follow_setting_set,
|
text = if (message.expiresIn == 0L) R.string.dialog_disappearing_messages_follow_setting_confirm else R.string.dialog_disappearing_messages_follow_setting_set,
|
||||||
contentDescription = if (message.expiresIn == 0L) R.string.AccessibilityId_confirm else R.string.AccessibilityId_set_button
|
contentDescription = if (message.expiresIn == 0L) R.string.AccessibilityId_confirm else R.string.AccessibilityId_set_button
|
||||||
) {
|
) {
|
||||||
set(message.threadId, message.recipient.address, message.expiryMode)
|
set(message.threadId, message.recipient.address, message.expiryMode, message.recipient.isClosedGroupRecipient)
|
||||||
}
|
}
|
||||||
cancelButton()
|
cancelButton()
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ class DisappearingMessagesViewModel(
|
|||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
disappearingMessages.set(threadId, address, mode)
|
disappearingMessages.set(threadId, address, mode, state.isGroup)
|
||||||
|
|
||||||
_event.send(Event.SUCCESS)
|
_event.send(Event.SUCCESS)
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ import org.session.libsession.messaging.jobs.JobQueue
|
|||||||
import org.session.libsession.messaging.mentions.Mention
|
import org.session.libsession.messaging.mentions.Mention
|
||||||
import org.session.libsession.messaging.mentions.MentionsManager
|
import org.session.libsession.messaging.mentions.MentionsManager
|
||||||
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
||||||
|
import org.session.libsession.messaging.messages.applyExpiryMode
|
||||||
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
||||||
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
|
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
|
||||||
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
|
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
|
||||||
@ -1574,7 +1575,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
// Create the message
|
// Create the message
|
||||||
val message = VisibleMessage()
|
val message = VisibleMessage().applyExpiryMode(viewModel.threadId)
|
||||||
message.sentTimestamp = sentTimestamp
|
message.sentTimestamp = sentTimestamp
|
||||||
message.text = text
|
message.text = text
|
||||||
val expiresInMillis = viewModel.expirationConfiguration?.expiryMode?.expiryMillis ?: 0
|
val expiresInMillis = viewModel.expirationConfiguration?.expiryMode?.expiryMillis ?: 0
|
||||||
@ -1609,7 +1610,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
val sentTimestamp = SnodeAPI.nowWithOffset
|
val sentTimestamp = SnodeAPI.nowWithOffset
|
||||||
processMessageRequestApproval()
|
processMessageRequestApproval()
|
||||||
// Create the message
|
// Create the message
|
||||||
val message = VisibleMessage()
|
val message = VisibleMessage().applyExpiryMode()
|
||||||
message.sentTimestamp = sentTimestamp
|
message.sentTimestamp = sentTimestamp
|
||||||
message.text = body
|
message.text = body
|
||||||
val quote = quotedMessage?.let {
|
val quote = quotedMessage?.let {
|
||||||
|
@ -30,6 +30,10 @@ class ExpirationTimerView @JvmOverloads constructor(
|
|||||||
R.drawable.timer60
|
R.drawable.timer60
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun setTimerIcon() {
|
||||||
|
setExpirationTime(0L, 0L)
|
||||||
|
}
|
||||||
|
|
||||||
fun setExpirationTime(startedAt: Long, expiresIn: Long) {
|
fun setExpirationTime(startedAt: Long, expiresIn: Long) {
|
||||||
if (expiresIn == 0L) {
|
if (expiresIn == 0L) {
|
||||||
setImageResource(R.drawable.timer55)
|
setImageResource(R.drawable.timer55)
|
||||||
|
@ -53,12 +53,19 @@ class ControlMessageView : LinearLayout {
|
|||||||
|
|
||||||
Log.d(TAG, "bind() called, messageBody = $messageBody")
|
Log.d(TAG, "bind() called, messageBody = $messageBody")
|
||||||
|
|
||||||
expirationTimerView.setExpirationTime(message.expireStarted, message.expiresIn)
|
val threadRecipient = DatabaseComponent.get(context).threadDatabase().getRecipientForThreadId(message.threadId)
|
||||||
|
|
||||||
|
if (threadRecipient?.isClosedGroupRecipient == true) {
|
||||||
|
expirationTimerView.setTimerIcon()
|
||||||
|
} else {
|
||||||
|
expirationTimerView.setExpirationTime(message.expireStarted, message.expiresIn)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
followSetting.isVisible = ExpirationConfiguration.isNewConfigEnabled
|
followSetting.isVisible = ExpirationConfiguration.isNewConfigEnabled
|
||||||
&& !message.isOutgoing
|
&& !message.isOutgoing
|
||||||
&& message.expiryMode != (MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(message.threadId)?.expiryMode ?: ExpiryMode.NONE)
|
&& message.expiryMode != (MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(message.threadId)?.expiryMode ?: ExpiryMode.NONE)
|
||||||
&& DatabaseComponent.get(context).threadDatabase().getRecipientForThreadId(message.threadId)?.isGroupRecipient != true
|
&& threadRecipient?.isGroupRecipient != true
|
||||||
|
|
||||||
followSetting.setOnClickListener { disappearingMessages.showFollowSettingDialog(context, message) }
|
followSetting.setOnClickListener { disappearingMessages.showFollowSettingDialog(context, message) }
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ import org.thoughtcrime.securesms.conversation.disappearingmessages.ExpiryType
|
|||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId
|
||||||
|
|
||||||
data class MarkedMessageInfo(val syncMessageId: SyncMessageId, val expirationInfo: ExpirationInfo) {
|
data class MarkedMessageInfo(val syncMessageId: SyncMessageId, val expirationInfo: ExpirationInfo) {
|
||||||
fun guessExpiryType(): ExpiryType = expirationInfo.run {
|
val expiryType get() = when {
|
||||||
when {
|
syncMessageId.timetamp == expirationInfo.expireStarted -> ExpiryType.AFTER_SEND
|
||||||
syncMessageId.timetamp == expireStarted -> ExpiryType.AFTER_SEND
|
expirationInfo.expiresIn > 0 -> ExpiryType.AFTER_READ
|
||||||
expiresIn > 0 -> ExpiryType.AFTER_READ
|
else -> ExpiryType.NONE
|
||||||
else -> ExpiryType.NONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val expiryMode get() = expiryType.mode(expirationInfo.expiresIn)
|
||||||
}
|
}
|
||||||
|
@ -382,9 +382,6 @@ open class Storage(
|
|||||||
DatabaseComponent.get(context).lokiMessageDatabase().setMessageServerHash(id, message.isMediaMessage(), serverHash)
|
DatabaseComponent.get(context).lokiMessageDatabase().setMessageServerHash(id, message.isMediaMessage(), serverHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expiryMode is ExpiryMode.AfterSend) {
|
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message.sentTimestamp!!, message.sender!!, expireStartedAt)
|
|
||||||
}
|
|
||||||
return messageID
|
return messageID
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,26 +969,24 @@ open class Storage(
|
|||||||
val recipient = Recipient.from(context, fromSerialized(groupID), false)
|
val recipient = Recipient.from(context, fromSerialized(groupID), false)
|
||||||
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
||||||
val expirationConfig = getExpirationConfiguration(threadId)
|
val expirationConfig = getExpirationConfiguration(threadId)
|
||||||
val expiryMode = expirationConfig?.expiryMode
|
val expiryMode = expirationConfig?.expiryMode ?: ExpiryMode.NONE
|
||||||
val expiresInMillis = expiryMode?.expiryMillis ?: 0
|
val expiresInMillis = expiryMode.expiryMillis
|
||||||
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
||||||
val m = IncomingTextMessage(fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), expiresInMillis, expireStartedAt, true, false)
|
val m = IncomingTextMessage(fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), expiresInMillis, expireStartedAt, true, false)
|
||||||
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
|
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
|
||||||
val infoMessage = IncomingGroupMessage(m, groupID, updateData, true)
|
val infoMessage = IncomingGroupMessage(m, groupID, updateData, true)
|
||||||
val smsDB = DatabaseComponent.get(context).smsDatabase()
|
val smsDB = DatabaseComponent.get(context).smsDatabase()
|
||||||
smsDB.insertMessageInbox(infoMessage, true)
|
smsDB.insertMessageInbox(infoMessage, true)
|
||||||
if (expiryMode is ExpiryMode.AfterSend) {
|
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(sentTimestamp, senderPublicKey, expiryMode)
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(sentTimestamp, senderPublicKey, expireStartedAt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long) {
|
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long) {
|
||||||
val userPublicKey = getUserPublicKey()
|
val userPublicKey = getUserPublicKey()!!
|
||||||
val recipient = Recipient.from(context, fromSerialized(groupID), false)
|
val recipient = Recipient.from(context, fromSerialized(groupID), false)
|
||||||
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
||||||
val expirationConfig = getExpirationConfiguration(threadId)
|
val expirationConfig = getExpirationConfiguration(threadId)
|
||||||
val expiryMode = expirationConfig?.expiryMode
|
val expiryMode = expirationConfig?.expiryMode ?: ExpiryMode.NONE
|
||||||
val expiresInMillis = expiryMode?.expiryMillis ?: 0
|
val expiresInMillis = expiryMode.expiryMillis
|
||||||
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
||||||
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
|
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
|
||||||
val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, expiresInMillis, expireStartedAt, true, null, listOf(), listOf())
|
val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, expiresInMillis, expireStartedAt, true, null, listOf(), listOf())
|
||||||
@ -1000,9 +995,7 @@ open class Storage(
|
|||||||
if (mmsSmsDB.getMessageFor(sentTimestamp, userPublicKey) != null) return
|
if (mmsSmsDB.getMessageFor(sentTimestamp, userPublicKey) != null) return
|
||||||
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null, runThreadUpdate = true)
|
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null, runThreadUpdate = true)
|
||||||
mmsDB.markAsSent(infoMessageID, true)
|
mmsDB.markAsSent(infoMessageID, true)
|
||||||
if (expiryMode is ExpiryMode.AfterSend) {
|
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(sentTimestamp, userPublicKey, expiryMode)
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(sentTimestamp, userPublicKey!!, expireStartedAt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isClosedGroup(publicKey: String): Boolean {
|
override fun isClosedGroup(publicKey: String): Boolean {
|
||||||
@ -1403,8 +1396,8 @@ open class Storage(
|
|||||||
if (recipient.isBlocked) return
|
if (recipient.isBlocked) return
|
||||||
val threadId = getThreadId(recipient) ?: return
|
val threadId = getThreadId(recipient) ?: return
|
||||||
val expirationConfig = getExpirationConfiguration(threadId)
|
val expirationConfig = getExpirationConfiguration(threadId)
|
||||||
val expiryMode = expirationConfig?.expiryMode
|
val expiryMode = expirationConfig?.expiryMode ?: ExpiryMode.NONE
|
||||||
val expiresInMillis = expiryMode?.expiryMillis ?: 0
|
val expiresInMillis = expiryMode.expiryMillis
|
||||||
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
||||||
val mediaMessage = IncomingMediaMessage(
|
val mediaMessage = IncomingMediaMessage(
|
||||||
address,
|
address,
|
||||||
@ -1426,9 +1419,8 @@ open class Storage(
|
|||||||
)
|
)
|
||||||
|
|
||||||
database.insertSecureDecryptedMessageInbox(mediaMessage, threadId, runThreadUpdate = true)
|
database.insertSecureDecryptedMessageInbox(mediaMessage, threadId, runThreadUpdate = true)
|
||||||
if (expiryMode is ExpiryMode.AfterSend) {
|
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(sentTimestamp, senderPublicKey, expireStartedAt)
|
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(sentTimestamp, senderPublicKey, expiryMode)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun insertMessageRequestResponse(response: MessageRequestResponse) {
|
override fun insertMessageRequestResponse(response: MessageRequestResponse) {
|
||||||
@ -1557,14 +1549,12 @@ open class Storage(
|
|||||||
val recipient = Recipient.from(context, address, false)
|
val recipient = Recipient.from(context, address, false)
|
||||||
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
||||||
val expirationConfig = getExpirationConfiguration(threadId)
|
val expirationConfig = getExpirationConfiguration(threadId)
|
||||||
val expiryMode = expirationConfig?.expiryMode
|
val expiryMode = expirationConfig?.expiryMode?.coerceSendToRead() ?: ExpiryMode.NONE
|
||||||
val expiresInMillis = expiryMode?.expiryMillis ?: 0
|
val expiresInMillis = expiryMode.expiryMillis
|
||||||
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
val expireStartedAt = if (expiryMode is ExpiryMode.AfterSend) sentTimestamp else 0
|
||||||
val callMessage = IncomingTextMessage.fromCallInfo(callMessageType, address, Optional.absent(), sentTimestamp, expiresInMillis, expireStartedAt)
|
val callMessage = IncomingTextMessage.fromCallInfo(callMessageType, address, Optional.absent(), sentTimestamp, expiresInMillis, expireStartedAt)
|
||||||
database.insertCallMessage(callMessage)
|
database.insertCallMessage(callMessage)
|
||||||
if (expiryMode is ExpiryMode.AfterSend) {
|
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(sentTimestamp, senderPublicKey, expiryMode)
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(sentTimestamp, senderPublicKey, expireStartedAt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun conversationHasOutgoing(userPublicKey: String): Boolean {
|
override fun conversationHasOutgoing(userPublicKey: String): Boolean {
|
||||||
|
@ -11,6 +11,7 @@ import org.session.libsession.messaging.messages.control.ReadReceipt
|
|||||||
import org.session.libsession.messaging.sending_receiving.MessageSender.send
|
import org.session.libsession.messaging.sending_receiving.MessageSender.send
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsession.snode.SnodeAPI.nowWithOffset
|
import org.session.libsession.snode.SnodeAPI.nowWithOffset
|
||||||
|
import org.session.libsession.utilities.SSKEnvironment
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.isReadReceiptsEnabled
|
import org.session.libsession.utilities.TextSecurePreferences.Companion.isReadReceiptsEnabled
|
||||||
import org.session.libsession.utilities.associateByNotNull
|
import org.session.libsession.utilities.associateByNotNull
|
||||||
@ -62,6 +63,18 @@ class MarkReadReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
sendReadReceipts(context, markedReadMessages)
|
sendReadReceipts(context, markedReadMessages)
|
||||||
|
|
||||||
|
markedReadMessages
|
||||||
|
.filter { it.expiryType == ExpiryType.AFTER_READ }
|
||||||
|
.forEach { info ->
|
||||||
|
DatabaseComponent.get(context).mmsSmsDatabase().getMessageForTimestamp(info.syncMessageId.timetamp)
|
||||||
|
?.takeUnless { it.isExpirationTimerUpdate && it.recipient.isClosedGroupRecipient }
|
||||||
|
?.run {
|
||||||
|
SSKEnvironment.shared.messageExpirationManager.startDisappearAfterRead(
|
||||||
|
info.syncMessageId.timetamp,
|
||||||
|
info.syncMessageId.address.serialize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
markedReadMessages.forEach { scheduleDeletion(context, it.expirationInfo) }
|
markedReadMessages.forEach { scheduleDeletion(context, it.expirationInfo) }
|
||||||
|
|
||||||
hashToDisappearAfterReadMessage(context, markedReadMessages)?.let {
|
hashToDisappearAfterReadMessage(context, markedReadMessages)?.let {
|
||||||
@ -77,7 +90,7 @@ class MarkReadReceiver : BroadcastReceiver() {
|
|||||||
val loki = DatabaseComponent.get(context).lokiMessageDatabase()
|
val loki = DatabaseComponent.get(context).lokiMessageDatabase()
|
||||||
|
|
||||||
return markedReadMessages
|
return markedReadMessages
|
||||||
.filter { it.guessExpiryType() == ExpiryType.AFTER_READ }
|
.filter { it.expiryType == ExpiryType.AFTER_READ }
|
||||||
.associateByNotNull { it.expirationInfo.run { loki.getMessageServerHash(id, isMms) } }
|
.associateByNotNull { it.expirationInfo.run { loki.getMessageServerHash(id, isMms) } }
|
||||||
.takeIf { it.isNotEmpty() }
|
.takeIf { it.isNotEmpty() }
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@ class ExpiringMessageManager(context: Context) : MessageExpirationManagerProtoco
|
|||||||
|
|
||||||
fun scheduleDeletion(id: Long, mms: Boolean, startedAtTimestamp: Long, expiresInMillis: Long) {
|
fun scheduleDeletion(id: Long, mms: Boolean, startedAtTimestamp: Long, expiresInMillis: Long) {
|
||||||
Log.d(TAG, "scheduleDeletion() called with: id = $id, mms = $mms, startedAtTimestamp = $startedAtTimestamp, expiresInMillis = $expiresInMillis")
|
Log.d(TAG, "scheduleDeletion() called with: id = $id, mms = $mms, startedAtTimestamp = $startedAtTimestamp, expiresInMillis = $expiresInMillis")
|
||||||
|
|
||||||
|
if (startedAtTimestamp <= 0) return
|
||||||
|
|
||||||
val expiresAtMillis = startedAtTimestamp + expiresInMillis
|
val expiresAtMillis = startedAtTimestamp + expiresInMillis
|
||||||
synchronized(expiringMessageReferences) {
|
synchronized(expiringMessageReferences) {
|
||||||
expiringMessageReferences += ExpiringMessageReference(id, mms, expiresAtMillis)
|
expiringMessageReferences += ExpiringMessageReference(id, mms, expiresAtMillis)
|
||||||
@ -164,16 +167,16 @@ class ExpiringMessageManager(context: Context) : MessageExpirationManagerProtoco
|
|||||||
insertIncomingExpirationTimerMessage(message, expireStartedAt)
|
insertIncomingExpirationTimerMessage(message, expireStartedAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
startAnyExpiration(message)
|
maybeStartExpiration(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) {
|
override fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) {
|
||||||
Log.d(TAG, "startAnyExpiration() called with: timestamp = $timestamp, author = $author, expireStartedAt = $expireStartedAt")
|
Log.d(TAG, "startAnyExpiration() called with: timestamp = $timestamp, author = $author, expireStartedAt = $expireStartedAt")
|
||||||
val messageRecord = mmsSmsDatabase.getMessageFor(timestamp, author) ?: throw Exception("no message record!!!")
|
|
||||||
Log.d(TAG, "startAnyExpiration() $messageRecord")
|
mmsSmsDatabase.getMessageFor(timestamp, author)?.run {
|
||||||
val mms = messageRecord.isMms()
|
getDatabase(isMms()).markExpireStarted(getId(), expireStartedAt)
|
||||||
getDatabase(mms).markExpireStarted(messageRecord.getId(), expireStartedAt)
|
scheduleDeletion(getId(), isMms(), expireStartedAt, expiresIn)
|
||||||
scheduleDeletion(messageRecord.getId(), mms, expireStartedAt, messageRecord.expiresIn)
|
} ?: Log.e(TAG, "no message record!!!")
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class LoadTask : Runnable {
|
private inner class LoadTask : Runnable {
|
||||||
|
@ -16,6 +16,7 @@ import nl.komponents.kovenant.Promise
|
|||||||
import nl.komponents.kovenant.functional.bind
|
import nl.komponents.kovenant.functional.bind
|
||||||
import org.session.libsession.database.StorageProtocol
|
import org.session.libsession.database.StorageProtocol
|
||||||
import org.session.libsession.messaging.calls.CallMessageType
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
|
import org.session.libsession.messaging.messages.applyExpiryMode
|
||||||
import org.session.libsession.messaging.messages.control.CallMessage
|
import org.session.libsession.messaging.messages.control.CallMessage
|
||||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
@ -57,8 +58,12 @@ import java.util.ArrayDeque
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import org.thoughtcrime.securesms.webrtc.data.State as CallState
|
import org.thoughtcrime.securesms.webrtc.data.State as CallState
|
||||||
|
|
||||||
class CallManager(context: Context, audioManager: AudioManagerCompat, private val storage: StorageProtocol): PeerConnection.Observer,
|
class CallManager(
|
||||||
SignalAudioManager.EventListener, CameraEventListener, DataChannel.Observer {
|
private val context: Context,
|
||||||
|
audioManager: AudioManagerCompat,
|
||||||
|
private val storage: StorageProtocol
|
||||||
|
): PeerConnection.Observer,
|
||||||
|
SignalAudioManager.EventListener, CameraEventListener, DataChannel.Observer {
|
||||||
|
|
||||||
sealed class StateEvent {
|
sealed class StateEvent {
|
||||||
data class AudioEnabled(val isEnabled: Boolean): StateEvent()
|
data class AudioEnabled(val isEnabled: Boolean): StateEvent()
|
||||||
@ -293,17 +298,16 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
|
|||||||
while (pendingOutgoingIceUpdates.isNotEmpty()) {
|
while (pendingOutgoingIceUpdates.isNotEmpty()) {
|
||||||
currentPendings.add(pendingOutgoingIceUpdates.pop())
|
currentPendings.add(pendingOutgoingIceUpdates.pop())
|
||||||
}
|
}
|
||||||
val sdps = currentPendings.map { it.sdp }
|
|
||||||
val sdpMLineIndexes = currentPendings.map { it.sdpMLineIndex }
|
|
||||||
val sdpMids = currentPendings.map { it.sdpMid }
|
|
||||||
|
|
||||||
MessageSender.sendNonDurably(CallMessage(
|
CallMessage(
|
||||||
ICE_CANDIDATES,
|
ICE_CANDIDATES,
|
||||||
sdps = sdps,
|
sdps = currentPendings.map(IceCandidate::sdp),
|
||||||
sdpMLineIndexes = sdpMLineIndexes,
|
sdpMLineIndexes = currentPendings.map(IceCandidate::sdpMLineIndex),
|
||||||
sdpMids = sdpMids,
|
sdpMids = currentPendings.map(IceCandidate::sdpMid),
|
||||||
currentCallId
|
currentCallId
|
||||||
), currentRecipient.address, isSyncMessage = currentRecipient.isLocalNumber)
|
)
|
||||||
|
.applyExpiryMode()
|
||||||
|
.also { MessageSender.sendNonDurably(it, currentRecipient.address, isSyncMessage = currentRecipient.isLocalNumber) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,13 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
|
|
||||||
sealed class ExpiryMode(val expirySeconds: Long) {
|
sealed class ExpiryMode(val expirySeconds: Long) {
|
||||||
object NONE: ExpiryMode(0)
|
object NONE: ExpiryMode(0)
|
||||||
data class Legacy(private val seconds: Long): ExpiryMode(seconds) // after read
|
data class Legacy(private val seconds: Long): ExpiryMode(seconds)
|
||||||
data class AfterSend(private val seconds: Long): ExpiryMode(seconds)
|
data class AfterSend(private val seconds: Long): ExpiryMode(seconds)
|
||||||
data class AfterRead(private val seconds: Long): ExpiryMode(seconds)
|
data class AfterRead(private val seconds: Long): ExpiryMode(seconds)
|
||||||
|
|
||||||
val duration get() = expirySeconds.seconds
|
val duration get() = expirySeconds.seconds
|
||||||
|
|
||||||
val expiryMillis get() = expirySeconds * 1000L
|
val expiryMillis get() = expirySeconds * 1000L
|
||||||
|
|
||||||
|
fun coerceSendToRead(coerce: Boolean = true) = if (coerce && this is AfterSend) AfterRead(expirySeconds) else this
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import org.session.libsession.database.StorageProtocol
|
|||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||||
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsignal.protos.SignalServiceProtos
|
import org.session.libsignal.protos.SignalServiceProtos
|
||||||
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
|
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
|
||||||
@ -25,6 +26,8 @@ abstract class Message {
|
|||||||
|
|
||||||
var expiryMode: ExpiryMode = ExpiryMode.NONE
|
var expiryMode: ExpiryMode = ExpiryMode.NONE
|
||||||
|
|
||||||
|
open val coerceDisappearAfterSendToRead = false
|
||||||
|
|
||||||
open val defaultTtl: Long = 14 * 24 * 60 * 60 * 1000
|
open val defaultTtl: Long = 14 * 24 * 60 * 60 * 1000
|
||||||
open val ttl: Long get() = specifiedTtl ?: defaultTtl
|
open val ttl: Long get() = specifiedTtl ?: defaultTtl
|
||||||
open val isSelfSendValid: Boolean = false
|
open val isSelfSendValid: Boolean = false
|
||||||
@ -51,26 +54,16 @@ abstract class Message {
|
|||||||
abstract fun toProto(): SignalServiceProtos.Content?
|
abstract fun toProto(): SignalServiceProtos.Content?
|
||||||
|
|
||||||
fun setGroupContext(dataMessage: SignalServiceProtos.DataMessage.Builder) {
|
fun setGroupContext(dataMessage: SignalServiceProtos.DataMessage.Builder) {
|
||||||
val groupProto = SignalServiceProtos.GroupContext.newBuilder()
|
dataMessage.group = SignalServiceProtos.GroupContext.newBuilder().apply {
|
||||||
val groupID = GroupUtil.doubleEncodeGroupID(recipient!!)
|
id = GroupUtil.doubleEncodeGroupID(recipient!!).let(GroupUtil::getDecodedGroupIDAsData).let(ByteString::copyFrom)
|
||||||
groupProto.id = ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID))
|
type = SignalServiceProtos.GroupContext.Type.DELIVER
|
||||||
groupProto.type = SignalServiceProtos.GroupContext.Type.DELIVER
|
}.build()
|
||||||
dataMessage.group = groupProto.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SignalServiceProtos.Content.Builder.setExpirationConfigurationIfNeeded(
|
fun SignalServiceProtos.Content.Builder.applyExpiryMode(): SignalServiceProtos.Content.Builder {
|
||||||
threadId: Long?,
|
expirationTimer = expiryMode.expirySeconds.toInt()
|
||||||
coerceDisappearAfterSendToRead: Boolean = false
|
expirationType = when (expiryMode) {
|
||||||
): SignalServiceProtos.Content.Builder {
|
is ExpiryMode.AfterSend -> ExpirationType.DELETE_AFTER_SEND
|
||||||
val config = threadId?.let(MessagingModuleConfiguration.shared.storage::getExpirationConfiguration)
|
|
||||||
?: run {
|
|
||||||
expirationTimer = 0
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
expirationTimer = config.expiryMode.expirySeconds.toInt()
|
|
||||||
lastDisappearingMessageChangeTimestamp = config.updatedTimestampMs
|
|
||||||
expirationType = when (config.expiryMode) {
|
|
||||||
is ExpiryMode.AfterSend -> if (coerceDisappearAfterSendToRead) ExpirationType.DELETE_AFTER_READ else ExpirationType.DELETE_AFTER_SEND
|
|
||||||
is ExpiryMode.AfterRead -> ExpirationType.DELETE_AFTER_READ
|
is ExpiryMode.AfterRead -> ExpirationType.DELETE_AFTER_READ
|
||||||
else -> ExpirationType.UNKNOWN
|
else -> ExpirationType.UNKNOWN
|
||||||
}
|
}
|
||||||
@ -79,13 +72,36 @@ abstract class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified M: Message> M.copyExpiration(proto: SignalServiceProtos.Content): M {
|
inline fun <reified M: Message> M.copyExpiration(proto: SignalServiceProtos.Content): M {
|
||||||
val duration: Int = (if (proto.hasExpirationTimer()) proto.expirationTimer else if (proto.hasDataMessage()) proto.dataMessage?.expireTimer else null) ?: return this
|
(proto.takeIf { it.hasExpirationTimer() }?.expirationTimer ?: proto.dataMessage?.expireTimer)?.let { duration ->
|
||||||
|
expiryMode = when (proto.expirationType.takeIf { duration > 0 }) {
|
||||||
expiryMode = when (proto.expirationType.takeIf { duration > 0 }) {
|
ExpirationType.DELETE_AFTER_SEND -> ExpiryMode.AfterSend(duration.toLong())
|
||||||
ExpirationType.DELETE_AFTER_SEND -> ExpiryMode.AfterSend(duration.toLong())
|
ExpirationType.DELETE_AFTER_READ -> ExpiryMode.AfterRead(duration.toLong())
|
||||||
ExpirationType.DELETE_AFTER_READ -> ExpiryMode.AfterRead(duration.toLong())
|
else -> ExpiryMode.NONE
|
||||||
else -> ExpiryMode.NONE
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun SignalServiceProtos.Content.expiryMode(): ExpiryMode =
|
||||||
|
(takeIf { it.hasExpirationTimer() }?.expirationTimer ?: dataMessage?.expireTimer)?.let { duration ->
|
||||||
|
when (expirationType.takeIf { duration > 0 }) {
|
||||||
|
ExpirationType.DELETE_AFTER_SEND -> ExpiryMode.AfterSend(duration.toLong())
|
||||||
|
ExpirationType.DELETE_AFTER_READ -> ExpiryMode.AfterRead(duration.toLong())
|
||||||
|
else -> ExpiryMode.NONE
|
||||||
|
}
|
||||||
|
} ?: ExpiryMode.NONE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply ExpiryMode from the current setting.
|
||||||
|
*/
|
||||||
|
inline fun <reified M: Message> M.applyExpiryMode(): M {
|
||||||
|
val address = Address.fromSerialized(sender ?: return this)
|
||||||
|
MessagingModuleConfiguration.shared.storage.getThreadId(address)?.let(::applyExpiryMode)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified M: Message> M.applyExpiryMode(thread: Long): M {
|
||||||
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
expiryMode = storage.getExpirationConfiguration(thread)?.expiryMode?.coerceSendToRead(coerceDisappearAfterSendToRead) ?: ExpiryMode.NONE
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.session.libsession.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
|
import org.session.libsession.messaging.messages.applyExpiryMode
|
||||||
import org.session.libsession.messaging.messages.copyExpiration
|
import org.session.libsession.messaging.messages.copyExpiration
|
||||||
import org.session.libsignal.protos.SignalServiceProtos
|
import org.session.libsignal.protos.SignalServiceProtos
|
||||||
import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.*
|
import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.*
|
||||||
@ -13,6 +14,7 @@ class CallMessage(): ControlMessage() {
|
|||||||
var sdpMids: List<String> = listOf()
|
var sdpMids: List<String> = listOf()
|
||||||
var callId: UUID? = null
|
var callId: UUID? = null
|
||||||
|
|
||||||
|
override val coerceDisappearAfterSendToRead = true
|
||||||
override val isSelfSendValid: Boolean get() = type in arrayOf(ANSWER, END_CALL)
|
override val isSelfSendValid: Boolean get() = type in arrayOf(ANSWER, END_CALL)
|
||||||
|
|
||||||
override val defaultTtl: Long = 300000L // 5m
|
override val defaultTtl: Long = 300000L // 5m
|
||||||
@ -40,21 +42,21 @@ class CallMessage(): ControlMessage() {
|
|||||||
listOf(),
|
listOf(),
|
||||||
listOf(),
|
listOf(),
|
||||||
callId
|
callId
|
||||||
)
|
).applyExpiryMode()
|
||||||
|
|
||||||
fun preOffer(callId: UUID) = CallMessage(PRE_OFFER,
|
fun preOffer(callId: UUID) = CallMessage(PRE_OFFER,
|
||||||
listOf(),
|
listOf(),
|
||||||
listOf(),
|
listOf(),
|
||||||
listOf(),
|
listOf(),
|
||||||
callId
|
callId
|
||||||
)
|
).applyExpiryMode()
|
||||||
|
|
||||||
fun offer(sdp: String, callId: UUID) = CallMessage(OFFER,
|
fun offer(sdp: String, callId: UUID) = CallMessage(OFFER,
|
||||||
listOf(sdp),
|
listOf(sdp),
|
||||||
listOf(),
|
listOf(),
|
||||||
listOf(),
|
listOf(),
|
||||||
callId
|
callId
|
||||||
)
|
).applyExpiryMode()
|
||||||
|
|
||||||
fun endCall(callId: UUID) = CallMessage(END_CALL, emptyList(), emptyList(), emptyList(), callId)
|
fun endCall(callId: UUID) = CallMessage(END_CALL, emptyList(), emptyList(), emptyList(), callId)
|
||||||
|
|
||||||
@ -83,9 +85,8 @@ class CallMessage(): ControlMessage() {
|
|||||||
.addAllSdpMids(sdpMids)
|
.addAllSdpMids(sdpMids)
|
||||||
.setUuid(callId!!.toString())
|
.setUuid(callId!!.toString())
|
||||||
|
|
||||||
val content = SignalServiceProtos.Content.newBuilder()
|
return SignalServiceProtos.Content.newBuilder()
|
||||||
content.setExpirationConfigurationIfNeeded(threadID, true)
|
.applyExpiryMode()
|
||||||
return content
|
|
||||||
.setCallMessage(callMessage)
|
.setCallMessage(callMessage)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
contentProto.dataMessage = dataMessageProto.build()
|
contentProto.dataMessage = dataMessageProto.build()
|
||||||
// Expiration timer
|
// Expiration timer
|
||||||
val threadId = groupID?.let { MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(Address.fromSerialized(it)) }
|
val threadId = groupID?.let { MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(Address.fromSerialized(it)) }
|
||||||
contentProto.setExpirationConfigurationIfNeeded(threadId)
|
contentProto.applyExpiryMode()
|
||||||
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.")
|
||||||
|
@ -20,10 +20,10 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
|
|
||||||
override val isSelfSendValid: Boolean = true
|
override val isSelfSendValid: Boolean = true
|
||||||
|
|
||||||
class ClosedGroup(var publicKey: String, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<String>, var admins: List<String>, var expirationTimer: Int) {
|
class ClosedGroup(var publicKey: String, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<String>, var admins: List<String>) {
|
||||||
val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty()
|
val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty()
|
||||||
|
|
||||||
internal constructor() : this("", "", null, listOf(), listOf(), 0)
|
internal constructor() : this("", "", null, listOf(), listOf())
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return name
|
return name
|
||||||
@ -40,8 +40,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
|
DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
|
||||||
val members = proto.membersList.map { it.toByteArray().toHexString() }
|
val members = proto.membersList.map { it.toByteArray().toHexString() }
|
||||||
val admins = proto.adminsList.map { it.toByteArray().toHexString() }
|
val admins = proto.adminsList.map { it.toByteArray().toHexString() }
|
||||||
val expirationTimer = proto.expirationTimer
|
return ClosedGroup(publicKey, name, encryptionKeyPair, members, admins)
|
||||||
return ClosedGroup(publicKey, name, encryptionKeyPair, members, admins, expirationTimer)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +54,6 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
result.encryptionKeyPair = encryptionKeyPairAsProto.build()
|
result.encryptionKeyPair = encryptionKeyPairAsProto.build()
|
||||||
result.addAllMembers(members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
|
result.addAllMembers(members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
|
||||||
result.addAllAdmins(admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
|
result.addAllAdmins(admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
|
||||||
result.expirationTimer = expirationTimer
|
|
||||||
return result.build()
|
return result.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,15 +126,12 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
if (!group.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue
|
if (!group.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue
|
||||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
||||||
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue
|
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue
|
||||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(group.encodedId))
|
|
||||||
val expiryConfig = storage.getExpirationConfiguration(threadID)
|
|
||||||
val closedGroup = ClosedGroup(
|
val closedGroup = ClosedGroup(
|
||||||
groupPublicKey,
|
groupPublicKey,
|
||||||
group.title,
|
group.title,
|
||||||
encryptionKeyPair,
|
encryptionKeyPair,
|
||||||
group.members.map { it.serialize() },
|
group.members.map { it.serialize() },
|
||||||
group.admins.map { it.serialize() },
|
group.admins.map { it.serialize() }
|
||||||
expiryConfig?.expiryMode?.expirySeconds?.toInt() ?: 0
|
|
||||||
)
|
)
|
||||||
closedGroups.add(closedGroup)
|
closedGroups.add(closedGroup)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import org.session.libsignal.utilities.Log
|
|||||||
class DataExtractionNotification() : ControlMessage() {
|
class DataExtractionNotification() : ControlMessage() {
|
||||||
var kind: Kind? = null
|
var kind: Kind? = null
|
||||||
|
|
||||||
|
override val coerceDisappearAfterSendToRead = true
|
||||||
|
|
||||||
sealed class Kind {
|
sealed class Kind {
|
||||||
class Screenshot() : Kind()
|
class Screenshot() : Kind()
|
||||||
class MediaSaved(val timestamp: Long) : Kind()
|
class MediaSaved(val timestamp: Long) : Kind()
|
||||||
@ -64,10 +66,10 @@ class DataExtractionNotification() : ControlMessage() {
|
|||||||
dataExtractionNotification.timestamp = kind.timestamp
|
dataExtractionNotification.timestamp = kind.timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val contentProto = SignalServiceProtos.Content.newBuilder()
|
return SignalServiceProtos.Content.newBuilder()
|
||||||
contentProto.dataExtractionNotification = dataExtractionNotification.build()
|
.setDataExtractionNotification(dataExtractionNotification.build())
|
||||||
contentProto.setExpirationConfigurationIfNeeded(threadID, true)
|
.applyExpiryMode()
|
||||||
return contentProto.build()
|
.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")
|
||||||
return null
|
return null
|
||||||
|
@ -1,58 +1,52 @@
|
|||||||
package org.session.libsession.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
import network.loki.messenger.libsession_util.util.ExpiryMode
|
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
import org.session.libsession.messaging.messages.copyExpiration
|
import org.session.libsession.messaging.messages.copyExpiration
|
||||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||||
import org.session.libsignal.protos.SignalServiceProtos
|
import org.session.libsignal.protos.SignalServiceProtos
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
|
|
||||||
/** In the case of a sync message, the public key of the person the message was targeted at.
|
/** In the case of a sync message, the public key of the person the message was targeted at.
|
||||||
*
|
*
|
||||||
* **Note:** `nil` if this isn't a sync message.
|
* **Note:** `nil` if this isn't a sync message.
|
||||||
*/
|
*/
|
||||||
data class ExpirationTimerUpdate(var syncTarget: String? = null) : ControlMessage() {
|
data class ExpirationTimerUpdate(var syncTarget: String? = null, val isGroup: Boolean = false) : ControlMessage() {
|
||||||
override val isSelfSendValid: Boolean = true
|
override val isSelfSendValid: Boolean = true
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "ExpirationTimerUpdate"
|
const val TAG = "ExpirationTimerUpdate"
|
||||||
|
private val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
|
||||||
fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? {
|
fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? =
|
||||||
val dataMessageProto = if (proto.hasDataMessage()) proto.dataMessage else return null
|
proto.dataMessage?.takeIf { it.flags and EXPIRATION_TIMER_UPDATE_VALUE != 0 }?.run {
|
||||||
val isExpirationTimerUpdate = dataMessageProto.flags.and(
|
ExpirationTimerUpdate(syncTarget, hasGroup()).copyExpiration(proto)
|
||||||
SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE
|
}
|
||||||
) != 0
|
|
||||||
if (!isExpirationTimerUpdate) return null
|
|
||||||
|
|
||||||
return ExpirationTimerUpdate(dataMessageProto.syncTarget)
|
|
||||||
.copyExpiration(proto)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder()
|
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder().apply {
|
||||||
dataMessageProto.flags = SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE
|
flags = EXPIRATION_TIMER_UPDATE_VALUE
|
||||||
dataMessageProto.expireTimer = expiryMode.expirySeconds.toInt()
|
expireTimer = expiryMode.expirySeconds.toInt()
|
||||||
// Sync target
|
|
||||||
if (syncTarget != null) {
|
|
||||||
dataMessageProto.syncTarget = syncTarget
|
|
||||||
}
|
}
|
||||||
|
// Sync target
|
||||||
|
syncTarget?.let { dataMessageProto.syncTarget = it }
|
||||||
// Group context
|
// Group context
|
||||||
if (MessagingModuleConfiguration.shared.storage.isClosedGroup(recipient!!)) {
|
if (storage.isClosedGroup(recipient!!)) {
|
||||||
try {
|
try {
|
||||||
setGroupContext(dataMessageProto)
|
setGroupContext(dataMessageProto)
|
||||||
} catch(e: Exception) {
|
} catch(e: Exception) {
|
||||||
Log.w(VisibleMessage.TAG, "Couldn't construct visible message proto from: $this")
|
Log.w(TAG, "Couldn't construct visible message proto from: $this", e)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return try {
|
return try {
|
||||||
SignalServiceProtos.Content.newBuilder().apply {
|
SignalServiceProtos.Content.newBuilder()
|
||||||
dataMessage = dataMessageProto.build()
|
.setDataMessage(dataMessageProto)
|
||||||
setExpirationConfigurationIfNeeded(threadID)
|
.applyExpiryMode()
|
||||||
}.build()
|
.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", e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class MessageRequestResponse(val isApproved: Boolean, var profile: Profile? = nu
|
|||||||
profile?.profileKey?.let { messageRequestResponseProto.profileKey = ByteString.copyFrom(it) }
|
profile?.profileKey?.let { messageRequestResponseProto.profileKey = ByteString.copyFrom(it) }
|
||||||
return try {
|
return try {
|
||||||
SignalServiceProtos.Content.newBuilder()
|
SignalServiceProtos.Content.newBuilder()
|
||||||
.setExpirationConfigurationIfNeeded(threadID)
|
.applyExpiryMode()
|
||||||
.setMessageRequestResponse(messageRequestResponseProto.build())
|
.setMessageRequestResponse(messageRequestResponseProto.build())
|
||||||
.build()
|
.build()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -37,14 +37,15 @@ class ReadReceipt() : ControlMessage() {
|
|||||||
Log.w(TAG, "Couldn't construct read receipt proto from: $this")
|
Log.w(TAG, "Couldn't construct read receipt proto from: $this")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val receiptProto = SignalServiceProtos.ReceiptMessage.newBuilder()
|
|
||||||
receiptProto.type = SignalServiceProtos.ReceiptMessage.Type.READ
|
|
||||||
receiptProto.addAllTimestamp(timestamps.asIterable())
|
|
||||||
val contentProto = SignalServiceProtos.Content.newBuilder()
|
|
||||||
return try {
|
return try {
|
||||||
contentProto.receiptMessage = receiptProto.build()
|
SignalServiceProtos.Content.newBuilder()
|
||||||
contentProto.setExpirationConfigurationIfNeeded(threadID)
|
.setReceiptMessage(
|
||||||
contentProto.build()
|
SignalServiceProtos.ReceiptMessage.newBuilder()
|
||||||
|
.setType(SignalServiceProtos.ReceiptMessage.Type.READ)
|
||||||
|
.addAllTimestamp(timestamps.asIterable()).build()
|
||||||
|
).applyExpiryMode()
|
||||||
|
.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")
|
||||||
null
|
null
|
||||||
|
@ -56,14 +56,11 @@ class TypingIndicator() : ControlMessage() {
|
|||||||
Log.w(TAG, "Couldn't construct typing indicator proto from: $this")
|
Log.w(TAG, "Couldn't construct typing indicator proto from: $this")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val typingIndicatorProto = SignalServiceProtos.TypingMessage.newBuilder()
|
|
||||||
typingIndicatorProto.timestamp = timestamp
|
|
||||||
typingIndicatorProto.action = kind.toProto()
|
|
||||||
val contentProto = SignalServiceProtos.Content.newBuilder()
|
|
||||||
return try {
|
return try {
|
||||||
contentProto.typingMessage = typingIndicatorProto.build()
|
SignalServiceProtos.Content.newBuilder()
|
||||||
contentProto.setExpirationConfigurationIfNeeded(threadID)
|
.setTypingMessage(SignalServiceProtos.TypingMessage.newBuilder().setTimestamp(timestamp).setAction(kind.toProto()).build())
|
||||||
contentProto.build()
|
.applyExpiryMode()
|
||||||
|
.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")
|
||||||
null
|
null
|
||||||
|
@ -41,14 +41,11 @@ class UnsendRequest(): ControlMessage() {
|
|||||||
Log.w(TAG, "Couldn't construct unsend request proto from: $this")
|
Log.w(TAG, "Couldn't construct unsend request proto from: $this")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val unsendRequestProto = SignalServiceProtos.UnsendRequest.newBuilder()
|
|
||||||
unsendRequestProto.timestamp = timestamp
|
|
||||||
unsendRequestProto.author = author
|
|
||||||
val contentProto = SignalServiceProtos.Content.newBuilder()
|
|
||||||
return try {
|
return try {
|
||||||
contentProto.unsendRequest = unsendRequestProto.build()
|
SignalServiceProtos.Content.newBuilder()
|
||||||
contentProto.setExpirationConfigurationIfNeeded(threadID)
|
.setUnsendRequest(SignalServiceProtos.UnsendRequest.newBuilder().setTimestamp(timestamp).setAuthor(author).build())
|
||||||
contentProto.build()
|
.applyExpiryMode()
|
||||||
|
.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")
|
||||||
null
|
null
|
||||||
|
@ -44,52 +44,26 @@ data class VisibleMessage(
|
|||||||
companion object {
|
companion object {
|
||||||
const val TAG = "VisibleMessage"
|
const val TAG = "VisibleMessage"
|
||||||
|
|
||||||
fun fromProto(proto: SignalServiceProtos.Content): VisibleMessage? {
|
fun fromProto(proto: SignalServiceProtos.Content): VisibleMessage? =
|
||||||
val dataMessage = proto.dataMessage ?: return null
|
proto.dataMessage?.let { VisibleMessage().apply {
|
||||||
val result = VisibleMessage()
|
if (it.hasSyncTarget()) syncTarget = it.syncTarget
|
||||||
if (dataMessage.hasSyncTarget()) { result.syncTarget = dataMessage.syncTarget }
|
text = it.body
|
||||||
result.text = dataMessage.body
|
// Attachments are handled in MessageReceiver
|
||||||
// Attachments are handled in MessageReceiver
|
if (it.hasQuote()) quote = Quote.fromProto(it.quote)
|
||||||
val quoteProto = if (dataMessage.hasQuote()) dataMessage.quote else null
|
linkPreview = it.previewList.firstOrNull()?.let(LinkPreview::fromProto)
|
||||||
if (quoteProto != null) {
|
if (it.hasOpenGroupInvitation()) openGroupInvitation = it.openGroupInvitation?.let(OpenGroupInvitation::fromProto)
|
||||||
val quote = Quote.fromProto(quoteProto)
|
// TODO Contact
|
||||||
result.quote = quote
|
profile = Profile.fromProto(it)
|
||||||
}
|
if (it.hasReaction()) reaction = it.reaction?.let(Reaction::fromProto)
|
||||||
val linkPreviewProto = dataMessage.previewList.firstOrNull()
|
blocksMessageRequests = it.hasBlocksCommunityMessageRequests() && it.blocksCommunityMessageRequests
|
||||||
if (linkPreviewProto != null) {
|
}.copyExpiration(proto)
|
||||||
val linkPreview = LinkPreview.fromProto(linkPreviewProto)
|
|
||||||
result.linkPreview = linkPreview
|
|
||||||
}
|
|
||||||
val openGroupInvitationProto = if (dataMessage.hasOpenGroupInvitation()) dataMessage.openGroupInvitation else null
|
|
||||||
if (openGroupInvitationProto != null) {
|
|
||||||
val openGroupInvitation = OpenGroupInvitation.fromProto(openGroupInvitationProto)
|
|
||||||
result.openGroupInvitation = openGroupInvitation
|
|
||||||
}
|
|
||||||
// TODO Contact
|
|
||||||
val profile = Profile.fromProto(dataMessage)
|
|
||||||
if (profile != null) { result.profile = profile }
|
|
||||||
val reactionProto = if (dataMessage.hasReaction()) dataMessage.reaction else null
|
|
||||||
if (reactionProto != null) {
|
|
||||||
val reaction = Reaction.fromProto(reactionProto)
|
|
||||||
result.reaction = reaction
|
|
||||||
}
|
|
||||||
|
|
||||||
result.blocksMessageRequests = with (dataMessage) { hasBlocksCommunityMessageRequests() && blocksCommunityMessageRequests }
|
|
||||||
|
|
||||||
return result.copyExpiration(proto)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val proto = SignalServiceProtos.Content.newBuilder()
|
val proto = SignalServiceProtos.Content.newBuilder()
|
||||||
val dataMessage: SignalServiceProtos.DataMessage.Builder
|
|
||||||
// Profile
|
// Profile
|
||||||
val profileProto = profile?.toProto()
|
val dataMessage = profile?.toProto()?.toBuilder() ?: SignalServiceProtos.DataMessage.newBuilder()
|
||||||
dataMessage = if (profileProto != null) {
|
|
||||||
profileProto.toBuilder()
|
|
||||||
} else {
|
|
||||||
SignalServiceProtos.DataMessage.newBuilder()
|
|
||||||
}
|
|
||||||
// Text
|
// Text
|
||||||
if (text != null) { dataMessage.body = text }
|
if (text != null) { dataMessage.body = text }
|
||||||
// Quote
|
// Quote
|
||||||
@ -124,7 +98,7 @@ data class VisibleMessage(
|
|||||||
dataMessage.addAllAttachments(pointers)
|
dataMessage.addAllAttachments(pointers)
|
||||||
// TODO: Contact
|
// TODO: Contact
|
||||||
// Expiration timer
|
// Expiration timer
|
||||||
proto.setExpirationConfigurationIfNeeded(threadID)
|
proto.applyExpiryMode()
|
||||||
// Group context
|
// Group context
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
if (storage.isClosedGroup(recipient!!)) {
|
if (storage.isClosedGroup(recipient!!)) {
|
||||||
|
@ -145,9 +145,7 @@ object MessageReceiver {
|
|||||||
MessageRequestResponse.fromProto(proto) ?:
|
MessageRequestResponse.fromProto(proto) ?:
|
||||||
CallMessage.fromProto(proto) ?:
|
CallMessage.fromProto(proto) ?:
|
||||||
SharedConfigurationMessage.fromProto(proto) ?:
|
SharedConfigurationMessage.fromProto(proto) ?:
|
||||||
VisibleMessage.fromProto(proto) ?: run {
|
VisibleMessage.fromProto(proto) ?: throw Error.UnknownMessage
|
||||||
throw Error.UnknownMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
val isUserBlindedSender = sender == openGroupPublicKey?.let { SodiumUtilities.blindedKeyPair(it, MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!) }?.let { SessionId(IdPrefix.BLINDED, it.publicKey.asBytes).hexString }
|
val isUserBlindedSender = sender == openGroupPublicKey?.let { SodiumUtilities.blindedKeyPair(it, MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!) }?.let { SessionId(IdPrefix.BLINDED, it.publicKey.asBytes).hexString }
|
||||||
val isUserSender = sender == userPublicKey
|
val isUserSender = sender == userPublicKey
|
||||||
|
@ -9,6 +9,7 @@ import org.session.libsession.messaging.jobs.MessageSendJob
|
|||||||
import org.session.libsession.messaging.jobs.NotifyPNServerJob
|
import org.session.libsession.messaging.jobs.NotifyPNServerJob
|
||||||
import org.session.libsession.messaging.messages.Destination
|
import org.session.libsession.messaging.messages.Destination
|
||||||
import org.session.libsession.messaging.messages.Message
|
import org.session.libsession.messaging.messages.Message
|
||||||
|
import org.session.libsession.messaging.messages.applyExpiryMode
|
||||||
import org.session.libsession.messaging.messages.control.CallMessage
|
import org.session.libsession.messaging.messages.control.CallMessage
|
||||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
||||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||||
@ -421,12 +422,7 @@ object MessageSender {
|
|||||||
storage.markUnidentified(timestamp, userPublicKey)
|
storage.markUnidentified(timestamp, userPublicKey)
|
||||||
// Start the disappearing messages timer if needed
|
// Start the disappearing messages timer if needed
|
||||||
Log.d("MessageSender", "Start the disappearing messages timer if needed message.recipient = ${message.recipient}, userPublicKey = $userPublicKey, isSyncMessage = $isSyncMessage")
|
Log.d("MessageSender", "Start the disappearing messages timer if needed message.recipient = ${message.recipient}, userPublicKey = $userPublicKey, isSyncMessage = $isSyncMessage")
|
||||||
message.threadID?.let(storage::getExpirationConfiguration)?.expiryMode?.takeIf { it.expirySeconds > 0 }?.let { mode ->
|
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(message, startDisappearAfterRead = true)
|
||||||
if (message.recipient == userPublicKey || !isSyncMessage) {
|
|
||||||
val expireStartedAt = if (mode is ExpiryMode.AfterRead) timestamp + 1 else timestamp
|
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(timestamp, userPublicKey, expireStartedAt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: run {
|
} ?: run {
|
||||||
storage.updateReactionIfNeeded(message, message.sender?:userPublicKey, openGroupSentTimestamp)
|
storage.updateReactionIfNeeded(message, message.sender?:userPublicKey, openGroupSentTimestamp)
|
||||||
}
|
}
|
||||||
@ -475,6 +471,7 @@ object MessageSender {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun send(message: Message, address: Address) {
|
fun send(message: Message, address: Address) {
|
||||||
|
message.applyExpiryMode()
|
||||||
val threadID = MessagingModuleConfiguration.shared.storage.getThreadId(address)
|
val threadID = MessagingModuleConfiguration.shared.storage.getThreadId(address)
|
||||||
message.threadID = threadID
|
message.threadID = threadID
|
||||||
val destination = Destination.from(address)
|
val destination = Destination.from(address)
|
||||||
|
@ -124,7 +124,6 @@ private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) {
|
|||||||
private fun MessageReceiver.handleCallMessage(message: CallMessage) {
|
private fun MessageReceiver.handleCallMessage(message: CallMessage) {
|
||||||
// TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing
|
// TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing
|
||||||
WebRtcUtils.SIGNAL_QUEUE.trySend(message)
|
WebRtcUtils.SIGNAL_QUEUE.trySend(message)
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message, coerceToDisappearAfterRead = true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) {
|
private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) {
|
||||||
@ -192,7 +191,6 @@ private fun MessageReceiver.handleDataExtractionNotification(message: DataExtrac
|
|||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
storage.insertDataExtractionNotificationMessage(senderPublicKey, notification, message.sentTimestamp!!)
|
storage.insertDataExtractionNotificationMessage(senderPublicKey, notification, message.sentTimestamp!!)
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message, coerceToDisappearAfterRead = true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleConfigurationMessage(message: ConfigurationMessage) {
|
private fun handleConfigurationMessage(message: ConfigurationMessage) {
|
||||||
@ -221,7 +219,7 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) {
|
|||||||
} else {
|
} else {
|
||||||
// only handle new closed group if it's first time sync
|
// only handle new closed group if it's first time sync
|
||||||
handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, closedGroup.publicKey, closedGroup.name,
|
handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, closedGroup.publicKey, closedGroup.name,
|
||||||
closedGroup.encryptionKeyPair!!, closedGroup.members, closedGroup.admins, message.sentTimestamp!!, closedGroup.expirationTimer)
|
closedGroup.encryptionKeyPair!!, closedGroup.members, closedGroup.admins, message.sentTimestamp!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val allV2OpenGroups = storage.getAllOpenGroups().map { it.value.joinURL }
|
val allV2OpenGroups = storage.getAllOpenGroups().map { it.value.joinURL }
|
||||||
@ -431,7 +429,7 @@ fun MessageReceiver.handleVisibleMessage(
|
|||||||
val isSms = !message.isMediaMessage() && attachments.isEmpty()
|
val isSms = !message.isMediaMessage() && attachments.isEmpty()
|
||||||
storage.setOpenGroupServerMessageID(messageID, it, threadID, isSms)
|
storage.setOpenGroupServerMessageID(messageID, it, threadID, isSms)
|
||||||
}
|
}
|
||||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message)
|
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(message)
|
||||||
return messageID
|
return messageID
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -550,10 +548,10 @@ private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMess
|
|||||||
val members = kind.members.map { it.toByteArray().toHexString() }
|
val members = kind.members.map { it.toByteArray().toHexString() }
|
||||||
val admins = kind.admins.map { it.toByteArray().toHexString() }
|
val admins = kind.admins.map { it.toByteArray().toHexString() }
|
||||||
val expirationTimer = kind.expirationTimer
|
val expirationTimer = kind.expirationTimer
|
||||||
handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, groupPublicKey, kind.name, kind.encryptionKeyPair!!, members, admins, message.sentTimestamp!!, expirationTimer)
|
handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, groupPublicKey, kind.name, kind.encryptionKeyPair!!, members, admins, message.sentTimestamp!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPublicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: List<String>, admins: List<String>, formationTimestamp: Long, expireTimer: Int) {
|
private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPublicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: List<String>, admins: List<String>, formationTimestamp: Long) {
|
||||||
val context = MessagingModuleConfiguration.shared.context
|
val context = MessagingModuleConfiguration.shared.context
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val userPublicKey = storage.getUserPublicKey()!!
|
val userPublicKey = storage.getUserPublicKey()!!
|
||||||
|
@ -3,11 +3,12 @@ package org.session.libsession.utilities
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import network.loki.messenger.libsession_util.util.ExpiryMode
|
import network.loki.messenger.libsession_util.util.ExpiryMode
|
||||||
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
import org.session.libsession.messaging.messages.Message
|
import org.session.libsession.messaging.messages.Message
|
||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier
|
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI.nowWithOffset
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
|
||||||
class SSKEnvironment(
|
class SSKEnvironment(
|
||||||
@ -43,18 +44,41 @@ class SSKEnvironment(
|
|||||||
interface MessageExpirationManagerProtocol {
|
interface MessageExpirationManagerProtocol {
|
||||||
fun insertExpirationTimerMessage(message: ExpirationTimerUpdate)
|
fun insertExpirationTimerMessage(message: ExpirationTimerUpdate)
|
||||||
fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long)
|
fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long)
|
||||||
fun startAnyExpiration(message: Message, coerceToDisappearAfterRead: Boolean = false) {
|
|
||||||
Log.d("MessageExpirationManagerProtocol", "startAnyExpiration() called with: message = $message, coerceToDisappearAfterRead = $coerceToDisappearAfterRead")
|
|
||||||
|
|
||||||
val timestamp = message.sentTimestamp ?: return
|
fun maybeStartExpiration(message: Message, startDisappearAfterRead: Boolean = false) {
|
||||||
startAnyExpiration(
|
Log.d("MessageExpirationManagerProtocol", "maybeStartExpiration() called with: message = $message, startDisappearAfterRead = $startDisappearAfterRead")
|
||||||
timestamp = timestamp,
|
|
||||||
author = message.sender ?: return,
|
if (message is ExpirationTimerUpdate && message.isGroup) return
|
||||||
expireStartedAt = if (message.expiryMode is ExpiryMode.AfterRead || coerceToDisappearAfterRead && message.expiryMode.expiryMillis > 0) SnodeAPI.nowWithOffset.coerceAtLeast(timestamp + 1)
|
|
||||||
else if (message.expiryMode is ExpiryMode.AfterSend) timestamp
|
maybeStartExpiration(
|
||||||
else return
|
message.sentTimestamp ?: return,
|
||||||
|
message.sender ?: return,
|
||||||
|
message.expiryMode,
|
||||||
|
startDisappearAfterRead || message.isSenderSelf
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startDisappearAfterRead(timestamp: Long, sender: String) {
|
||||||
|
Log.d("MessageExpirationManagerProtocol", "startDisappearAfterRead() called with: timestamp = $timestamp, sender = $sender")
|
||||||
|
|
||||||
|
startAnyExpiration(
|
||||||
|
timestamp,
|
||||||
|
sender,
|
||||||
|
expireStartedAt = nowWithOffset.coerceAtLeast(timestamp + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun maybeStartExpiration(timestamp: Long, sender: String, mode: ExpiryMode, startDisappearAfterRead: Boolean = false) {
|
||||||
|
Log.d("MessageExpirationManagerProtocol", "maybeStartExpiration() called with: timestamp = $timestamp, sender = $sender, mode = $mode, startDisappearAfterRead = $startDisappearAfterRead")
|
||||||
|
|
||||||
|
val expireStartedAt = when (mode) {
|
||||||
|
is ExpiryMode.AfterSend -> timestamp
|
||||||
|
is ExpiryMode.AfterRead -> if (startDisappearAfterRead) nowWithOffset.coerceAtLeast(timestamp + 1) else return
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
|
||||||
|
startAnyExpiration(timestamp, sender, expireStartedAt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
Loading…
Reference in New Issue
Block a user