feat: add user config integrated into config sync

This commit is contained in:
0x330a 2023-08-03 17:37:21 +10:00
parent 06c0ab3080
commit 8db92cc55c
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
13 changed files with 120 additions and 37 deletions

View File

@ -95,7 +95,7 @@ class LibSessionTests {
fakePollNewConfig(contacts, newContactMerge) fakePollNewConfig(contacts, newContactMerge)
verify(storageSpy).addLibSessionContacts(argThat { verify(storageSpy).addLibSessionContacts(argThat {
first().let { it.id == newContactId && it.approved } && size == 1 first().let { it.id == newContactId && it.approved } && size == 1
}) }, 0)
verify(storageSpy).setRecipientApproved(argThat { address.serialize() == newContactId }, eq(true)) verify(storageSpy).setRecipientApproved(argThat { address.serialize() == newContactId }, eq(true))
} }

View File

@ -194,12 +194,12 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
} }
@Override @Override
public void notifyUpdates(@NonNull ConfigBase forConfigObject) { public void notifyUpdates(@NonNull ConfigBase forConfigObject, long messageTimestamp) {
// forward to the config factory / storage ig // forward to the config factory / storage ig
if (forConfigObject instanceof UserProfile && !textSecurePreferences.getConfigurationMessageSynced()) { if (forConfigObject instanceof UserProfile && !textSecurePreferences.getConfigurationMessageSynced()) {
textSecurePreferences.setConfigurationMessageSynced(true); textSecurePreferences.setConfigurationMessageSynced(true);
} }
storage.notifyConfigUpdates(forConfigObject); storage.notifyConfigUpdates(forConfigObject, messageTimestamp);
} }
@Override @Override

View File

@ -27,7 +27,7 @@ class ExpirationConfigurationDatabase(context: Context, helper: SQLCipherOpenHel
@JvmField @JvmField
val MIGRATE_GROUP_CONVERSATION_EXPIRY_TYPE_COMMAND = """ val MIGRATE_GROUP_CONVERSATION_EXPIRY_TYPE_COMMAND = """
INSERT INTO $TABLE_NAME ($THREAD_ID) SELECT ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ID}, ${RecipientDatabase.EXPIRE_MESSAGES}, 1 INSERT INTO $TABLE_NAME ($THREAD_ID) SELECT ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ID}
FROM ${ThreadDatabase.TABLE_NAME}, ${RecipientDatabase.TABLE_NAME} FROM ${ThreadDatabase.TABLE_NAME}, ${RecipientDatabase.TABLE_NAME}
WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} LIKE '$CLOSED_GROUP_PREFIX%' WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} LIKE '$CLOSED_GROUP_PREFIX%'
AND EXISTS (SELECT ${RecipientDatabase.EXPIRE_MESSAGES} FROM ${RecipientDatabase.TABLE_NAME} WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} = ${RecipientDatabase.TABLE_NAME}.${RecipientDatabase.ADDRESS} AND ${RecipientDatabase.EXPIRE_MESSAGES} > 0) AND EXISTS (SELECT ${RecipientDatabase.EXPIRE_MESSAGES} FROM ${RecipientDatabase.TABLE_NAME} WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} = ${RecipientDatabase.TABLE_NAME}.${RecipientDatabase.ADDRESS} AND ${RecipientDatabase.EXPIRE_MESSAGES} > 0)
@ -35,7 +35,7 @@ class ExpirationConfigurationDatabase(context: Context, helper: SQLCipherOpenHel
@JvmField @JvmField
val MIGRATE_ONE_TO_ONE_CONVERSATION_EXPIRY_TYPE_COMMAND = """ val MIGRATE_ONE_TO_ONE_CONVERSATION_EXPIRY_TYPE_COMMAND = """
INSERT INTO $TABLE_NAME ($THREAD_ID) SELECT ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ID}, ${RecipientDatabase.EXPIRE_MESSAGES}, 2 INSERT INTO $TABLE_NAME ($THREAD_ID) SELECT ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ID}
FROM ${ThreadDatabase.TABLE_NAME}, ${RecipientDatabase.TABLE_NAME} FROM ${ThreadDatabase.TABLE_NAME}, ${RecipientDatabase.TABLE_NAME}
WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$CLOSED_GROUP_PREFIX%' WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$CLOSED_GROUP_PREFIX%'
AND ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$OPEN_GROUP_PREFIX%' AND ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$OPEN_GROUP_PREFIX%'

View File

@ -434,8 +434,8 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
return DatabaseComponent.get(context).lokiAPIDatabase().getAuthToken(id) return DatabaseComponent.get(context).lokiAPIDatabase().getAuthToken(id)
} }
override fun notifyConfigUpdates(forConfigObject: ConfigBase) { override fun notifyConfigUpdates(forConfigObject: ConfigBase, messageTimestamp: Long) {
notifyUpdates(forConfigObject) notifyUpdates(forConfigObject, messageTimestamp)
} }
override fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean { override fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean {
@ -446,16 +446,16 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
return configFactory.canPerformChange(variant, publicKey, changeTimestampMs) return configFactory.canPerformChange(variant, publicKey, changeTimestampMs)
} }
fun notifyUpdates(forConfigObject: ConfigBase) { private fun notifyUpdates(forConfigObject: ConfigBase, messageTimestamp: Long) {
when (forConfigObject) { when (forConfigObject) {
is UserProfile -> updateUser(forConfigObject) is UserProfile -> updateUser(forConfigObject, messageTimestamp)
is Contacts -> updateContacts(forConfigObject) is Contacts -> updateContacts(forConfigObject, messageTimestamp)
is ConversationVolatileConfig -> updateConvoVolatile(forConfigObject) is ConversationVolatileConfig -> updateConvoVolatile(forConfigObject, messageTimestamp)
is UserGroupsConfig -> updateUserGroups(forConfigObject) is UserGroupsConfig -> updateUserGroups(forConfigObject, messageTimestamp)
} }
} }
private fun updateUser(userProfile: UserProfile) { private fun updateUser(userProfile: UserProfile, messageTimestamp: Long) {
val userPublicKey = getUserPublicKey() ?: return val userPublicKey = getUserPublicKey() ?: return
// would love to get rid of recipient and context from this // would love to get rid of recipient and context from this
val recipient = Recipient.from(context, fromSerialized(userPublicKey), false) val recipient = Recipient.from(context, fromSerialized(userPublicKey), false)
@ -486,11 +486,16 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
setPinned(ourThread, userProfile.getNtsPriority() > 0) setPinned(ourThread, userProfile.getNtsPriority() > 0)
} }
getThreadId(recipient)?.let { ourThread ->
val expiration = ExpirationConfiguration(ourThread, userProfile.getNtsExpiry(), messageTimestamp)
DatabaseComponent.get(context).expirationConfigurationDatabase().setExpirationConfiguration(expiration)
}
} }
private fun updateContacts(contacts: Contacts) { private fun updateContacts(contacts: Contacts, messageTimestamp: Long) {
val extracted = contacts.all().toList() val extracted = contacts.all().toList()
addLibSessionContacts(extracted) addLibSessionContacts(extracted, messageTimestamp)
} }
override fun clearUserPic() { override fun clearUserPic() {
@ -510,7 +515,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context) ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
} }
private fun updateConvoVolatile(convos: ConversationVolatileConfig) { private fun updateConvoVolatile(convos: ConversationVolatileConfig, messageTimestamp: Long) {
val extracted = convos.all() val extracted = convos.all()
for (conversation in extracted) { for (conversation in extracted) {
val threadId = when (conversation) { val threadId = when (conversation) {
@ -527,7 +532,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
} }
} }
private fun updateUserGroups(userGroups: UserGroupsConfig) { private fun updateUserGroups(userGroups: UserGroupsConfig, messageTimestamp: Long) {
val threadDb = DatabaseComponent.get(context).threadDatabase() val threadDb = DatabaseComponent.get(context).threadDatabase()
val localUserPublicKey = getUserPublicKey() ?: return Log.w( val localUserPublicKey = getUserPublicKey() ?: return Log.w(
"Loki", "Loki",
@ -579,6 +584,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
} }
for (group in lgc) { for (group in lgc) {
val groupId = GroupUtil.doubleEncodeGroupID(group.sessionId)
val existingGroup = existingClosedGroups.firstOrNull { GroupUtil.doubleDecodeGroupId(it.encodedId) == group.sessionId } val existingGroup = existingClosedGroups.firstOrNull { GroupUtil.doubleDecodeGroupId(it.encodedId) == group.sessionId }
val existingThread = existingGroup?.let { getThreadId(existingGroup.encodedId) } val existingThread = existingGroup?.let { getThreadId(existingGroup.encodedId) }
if (existingGroup != null) { if (existingGroup != null) {
@ -593,7 +599,6 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
} else { } else {
val members = group.members.keys.map { Address.fromSerialized(it) } val members = group.members.keys.map { Address.fromSerialized(it) }
val admins = group.members.filter { it.value /*admin = true*/ }.keys.map { Address.fromSerialized(it) } val admins = group.members.filter { it.value /*admin = true*/ }.keys.map { Address.fromSerialized(it) }
val groupId = GroupUtil.doubleEncodeGroupID(group.sessionId)
val title = group.name val title = group.name
val formationTimestamp = (group.joinedAt * 1000L) val formationTimestamp = (group.joinedAt * 1000L)
createGroup(groupId, title, admins + members, null, null, admins, formationTimestamp) createGroup(groupId, title, admins + members, null, null, admins, formationTimestamp)
@ -616,6 +621,17 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
// Start polling // Start polling
ClosedGroupPollerV2.shared.startPolling(group.sessionId) ClosedGroupPollerV2.shared.startPolling(group.sessionId)
} }
getThreadId(Address.fromSerialized(groupId))?.let { conversationThreadId ->
val mode =
if (group.disappearingTimer == 0L) ExpiryMode.NONE
else ExpiryMode.AfterRead(group.disappearingTimer)
val newConfig = ExpirationConfiguration(
conversationThreadId, mode, messageTimestamp
)
DatabaseComponent.get(context)
.expirationConfigurationDatabase()
.setExpirationConfiguration(newConfig)
}
} }
} }
@ -1163,7 +1179,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
return if (recipientSettings.isPresent) { recipientSettings.get() } else null return if (recipientSettings.isPresent) { recipientSettings.get() } else null
} }
override fun addLibSessionContacts(contacts: List<LibSessionContact>) { override fun addLibSessionContacts(contacts: List<LibSessionContact>, timestamp: Long) {
val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase() val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase()
val moreContacts = contacts.filter { contact -> val moreContacts = contacts.filter { contact ->
val id = SessionId(contact.id) val id = SessionId(contact.id)
@ -1204,6 +1220,15 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
setPinned(conversationThreadId, contact.priority == PRIORITY_PINNED) setPinned(conversationThreadId, contact.priority == PRIORITY_PINNED)
} }
} }
getThreadId(recipient)?.let { conversationThreadId ->
val expiration = ExpirationConfiguration(
conversationThreadId,
contact.expiryMode,
timestamp
)
DatabaseComponent.get(context).expirationConfigurationDatabase()
.setExpirationConfiguration(expiration)
}
setRecipientHash(recipient, contact.hashCode().toString()) setRecipientHash(recipient, contact.hashCode().toString())
} }
} }
@ -1676,7 +1701,15 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
override fun getExpirationConfiguration(threadId: Long): ExpirationConfiguration? { override fun getExpirationConfiguration(threadId: Long): ExpirationConfiguration? {
val recipient = getRecipientForThread(threadId) ?: return null val recipient = getRecipientForThread(threadId) ?: return null
val dbExpirationMetadata = DatabaseComponent.get(context).expirationConfigurationDatabase().getExpirationConfiguration(threadId) ?: return null val dbExpirationMetadata = DatabaseComponent.get(context).expirationConfigurationDatabase().getExpirationConfiguration(threadId) ?: return null
return if (recipient.isContactRecipient && recipient.address.serialize().startsWith(IdPrefix.STANDARD.value)) { return if (recipient.isLocalNumber) {
configFactory.user?.getNtsExpiry()?.let { mode ->
ExpirationConfiguration(
threadId,
mode,
dbExpirationMetadata.updatedTimestampMs
)
}
} else if (recipient.isContactRecipient && recipient.address.serialize().startsWith(IdPrefix.STANDARD.value)) {
// read it from contacts config if exists // read it from contacts config if exists
configFactory.contacts?.get(recipient.address.serialize())?.let { contact -> configFactory.contacts?.get(recipient.address.serialize())?.let { contact ->
val mode = contact.expiryMode val mode = contact.expiryMode
@ -1703,11 +1736,26 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
override fun setExpirationConfiguration(config: ExpirationConfiguration) { override fun setExpirationConfiguration(config: ExpirationConfiguration) {
val recipient = getRecipientForThread(config.threadId) ?: return val recipient = getRecipientForThread(config.threadId) ?: return
if (recipient.isClosedGroupRecipient) { if (recipient.isClosedGroupRecipient) {
configFactory.userGroups?.getLegacyGroupInfo() val userGroups = configFactory.userGroups ?: return
val groupPublicKey = GroupUtil.addressToGroupSessionId(recipient.address)
val expiryMode = config.expiryMode
val groupInfo = userGroups.getLegacyGroupInfo(groupPublicKey)?.let { info ->
info.copy(disappearingTimer = when (expiryMode) {
null, ExpiryMode.NONE -> 0
else -> expiryMode.expirySeconds
})
} ?: return
userGroups.set(groupInfo)
} else if (recipient.isLocalNumber) { } else if (recipient.isLocalNumber) {
val user = configFactory.user ?: return
user.setNtsExpiry(config.expiryMode ?: ExpiryMode.NONE)
} else if (recipient.isContactRecipient) { } else if (recipient.isContactRecipient) {
val contacts = configFactory.contacts ?: return
val expiry = config.expiryMode
val contact = contacts.get(recipient.address.serialize())?.copy(
expiryMode = expiry ?: ExpiryMode.NONE
) ?: return
contacts.set(contact)
} }
DatabaseComponent.get(context).expirationConfigurationDatabase().setExpirationConfiguration(config) DatabaseComponent.get(context).expirationConfigurationDatabase().setExpirationConfiguration(config)
} }

View File

@ -187,7 +187,7 @@ class ConfigFactory(
override fun persist(forConfigObject: ConfigBase, timestamp: Long) { override fun persist(forConfigObject: ConfigBase, timestamp: Long) {
try { try {
listeners.forEach { listener -> listeners.forEach { listener ->
listener.notifyUpdates(forConfigObject) listener.notifyUpdates(forConfigObject, timestamp)
} }
when (forConfigObject) { when (forConfigObject) {
is UserProfile -> persistUserConfigDump(timestamp) is UserProfile -> persistUserConfigDump(timestamp)

View File

@ -95,4 +95,28 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getNtsPriority(JNIEnv *
std::lock_guard lock{util::util_mutex_}; std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz); auto profile = ptrToProfile(env, thiz);
return profile->get_nts_priority(); return profile->get_nts_priority();
} }
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_UserProfile_setNtsExpiry(JNIEnv *env, jobject thiz,
jobject expiry_mode) {
std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz);
auto expiry = util::deserialize_expiry(env, expiry_mode);
profile->set_nts_expiry(std::chrono::seconds (expiry.second));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_network_loki_messenger_libsession_1util_UserProfile_getNtsExpiry(JNIEnv *env, jobject thiz) {
std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz);
auto nts_expiry = profile->get_nts_expiry();
if (nts_expiry == std::nullopt) {
auto expiry = util::serialize_expiry(env, session::config::expiration_mode::none, std::chrono::seconds(0));
return expiry;
}
auto expiry = util::serialize_expiry(env, session::config::expiration_mode::after_send, std::chrono::seconds(*nts_expiry));
return expiry;
}

View File

@ -4,6 +4,7 @@ import network.loki.messenger.libsession_util.util.BaseCommunityInfo
import network.loki.messenger.libsession_util.util.ConfigPush import network.loki.messenger.libsession_util.util.ConfigPush
import network.loki.messenger.libsession_util.util.Contact import network.loki.messenger.libsession_util.util.Contact
import network.loki.messenger.libsession_util.util.Conversation import network.loki.messenger.libsession_util.util.Conversation
import network.loki.messenger.libsession_util.util.ExpiryMode
import network.loki.messenger.libsession_util.util.GroupInfo import network.loki.messenger.libsession_util.util.GroupInfo
import network.loki.messenger.libsession_util.util.UserPic import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Kind import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Kind
@ -126,6 +127,8 @@ class UserProfile(pointer: Long) : ConfigBase(pointer) {
external fun setPic(userPic: UserPic) external fun setPic(userPic: UserPic)
external fun setNtsPriority(priority: Int) external fun setNtsPriority(priority: Int)
external fun getNtsPriority(): Int external fun getNtsPriority(): Int
external fun setNtsExpiry(expiryMode: ExpiryMode)
external fun getNtsExpiry(): ExpiryMode
} }
class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) { class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {

View File

@ -182,7 +182,7 @@ interface StorageProtocol {
fun setContact(contact: Contact) fun setContact(contact: Contact)
fun getRecipientForThread(threadId: Long): Recipient? fun getRecipientForThread(threadId: Long): Recipient?
fun getRecipientSettings(address: Address): RecipientSettings? fun getRecipientSettings(address: Address): RecipientSettings?
fun addLibSessionContacts(contacts: List<LibSessionContact>) fun addLibSessionContacts(contacts: List<LibSessionContact>, timestamp: Long)
fun addContacts(contacts: List<ConfigurationMessage.Contact>) fun addContacts(contacts: List<ConfigurationMessage.Contact>)
// Attachments // Attachments
@ -229,7 +229,7 @@ interface StorageProtocol {
fun updateDisappearingState(threadID: Long, disappearingState: Recipient.DisappearingState) fun updateDisappearingState(threadID: Long, disappearingState: Recipient.DisappearingState)
// Shared configs // Shared configs
fun notifyConfigUpdates(forConfigObject: ConfigBase) fun notifyConfigUpdates(forConfigObject: ConfigBase, messageTimestamp: Long)
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
fun canPerformConfigChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean fun canPerformConfigChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
} }

View File

@ -65,11 +65,13 @@ abstract class Message {
if (config.isEnabled && config.expiryMode != null) { if (config.isEnabled && config.expiryMode != null) {
expirationTimer = config.expiryMode.expirySeconds.toInt() expirationTimer = config.expiryMode.expirySeconds.toInt()
lastDisappearingMessageChangeTimestamp = config.updatedTimestampMs lastDisappearingMessageChangeTimestamp = config.updatedTimestampMs
config.expiryMode.let { expiryMode -> if (ExpirationConfiguration.isNewConfigEnabled) {
when (expiryMode) { config.expiryMode.let { expiryMode ->
is ExpiryMode.AfterSend -> expirationType = ExpirationType.DELETE_AFTER_SEND when (expiryMode) {
is ExpiryMode.AfterRead -> expirationType = ExpirationType.DELETE_AFTER_READ is ExpiryMode.AfterSend -> expirationType = ExpirationType.DELETE_AFTER_SEND
ExpiryMode.NONE -> { /* do nothing */ } is ExpiryMode.AfterRead -> expirationType = ExpirationType.DELETE_AFTER_READ
ExpiryMode.NONE -> { /* do nothing */ }
}
} }
} }
} }

View File

@ -3,8 +3,8 @@ package org.session.libsession.messaging.messages.control
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.ExpirationConfiguration import org.session.libsession.messaging.messages.ExpirationConfiguration
import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsignal.utilities.Log
import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Log
class ExpirationTimerUpdate() : ControlMessage() { class ExpirationTimerUpdate() : ControlMessage() {
/** 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.
@ -26,7 +26,9 @@ class ExpirationTimerUpdate() : ControlMessage() {
fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? { fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? {
val dataMessageProto = if (proto.hasDataMessage()) proto.dataMessage else return null val dataMessageProto = if (proto.hasDataMessage()) proto.dataMessage else 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
if (!isExpirationTimerUpdate) return null if (!isExpirationTimerUpdate) return null
val syncTarget = dataMessageProto.syncTarget val syncTarget = dataMessageProto.syncTarget
val duration = if (proto.hasExpirationTimer()) proto.expirationTimer else dataMessageProto.expireTimer val duration = if (proto.hasExpirationTimer()) proto.expirationTimer else dataMessageProto.expireTimer

View File

@ -69,7 +69,7 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content,
// Do nothing if the message was outdated // Do nothing if the message was outdated
if (MessageReceiver.messageIsOutdated(message, threadId, openGroupID)) { return } if (MessageReceiver.messageIsOutdated(message, threadId, openGroupID)) { return }
MessageReceiver.updateExpiryIfNeeded(message, proto, openGroupID, ) MessageReceiver.updateExpiryIfNeeded(message, proto, openGroupID)
when (message) { when (message) {
is ReadReceipt -> handleReadReceipt(message) is ReadReceipt -> handleReadReceipt(message)
is TypingIndicator -> handleTypingIndicator(message) is TypingIndicator -> handleTypingIndicator(message)

View File

@ -19,5 +19,5 @@ interface ConfigFactoryProtocol {
} }
interface ConfigFactoryUpdateListener { interface ConfigFactoryUpdateListener {
fun notifyUpdates(forConfigObject: ConfigBase) fun notifyUpdates(forConfigObject: ConfigBase, messageTimestamp: Long)
} }

View File

@ -1,6 +1,5 @@
package org.session.libsession.utilities package org.session.libsession.utilities
import network.loki.messenger.libsession_util.util.GroupInfo
import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import java.io.IOException import java.io.IOException
@ -104,6 +103,11 @@ object GroupUtil {
return Hex.toStringCondensed(getDecodedGroupIDAsData(getDecodedGroupID(groupID))) return Hex.toStringCondensed(getDecodedGroupIDAsData(getDecodedGroupID(groupID)))
} }
@JvmStatic
fun addressToGroupSessionId(address: Address): String {
return doubleDecodeGroupId(address.toGroupString())
}
fun createConfigMemberMap( fun createConfigMemberMap(
members: Collection<String>, members: Collection<String>,
admins: Collection<String> admins: Collection<String>