diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt index b0f6a676c7..53f4ea3196 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt @@ -458,9 +458,8 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( return ECKeyPair(DjbECPublicKey(keyPair.publicKey.serialize().removingIdPrefixIfNeeded()), DjbECPrivateKey(keyPair.privateKey.serialize())) } - fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String) { + fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String, timestamp: Long) { val database = databaseHelper.writableDatabase - val timestamp = Date().time.toString() val index = "$groupPublicKey-$timestamp" val encryptionKeyPairPublicKey = encryptionKeyPair.publicKey.serialize().toHexString().removingIdPrefixIfNeeded() val encryptionKeyPairPrivateKey = encryptionKeyPair.privateKey.serialize().toHexString() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 72f5aa535f..905bf24174 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.database import android.content.Context import android.net.Uri import network.loki.messenger.libsession_util.* +import network.loki.messenger.libsession_util.util.BaseCommunityInfo import network.loki.messenger.libsession_util.util.Conversation import network.loki.messenger.libsession_util.util.UserPic import org.session.libsession.avatars.AvatarHelper @@ -27,14 +28,19 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview +import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI +import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2 import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.utilities.SessionId import org.session.libsession.messaging.utilities.SodiumUtilities import org.session.libsession.messaging.utilities.UpdateMessageData import org.session.libsession.snode.OnionRequestAPI +import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.* import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.recipients.Recipient +import org.session.libsignal.crypto.ecc.DjbECPrivateKey +import org.session.libsignal.crypto.ecc.DjbECPublicKey import org.session.libsignal.crypto.ecc.ECKeyPair import org.session.libsignal.messages.SignalServiceAttachmentPointer import org.session.libsignal.messages.SignalServiceGroup @@ -49,7 +55,7 @@ import org.thoughtcrime.securesms.database.model.MessageId import org.thoughtcrime.securesms.database.model.ReactionRecord import org.thoughtcrime.securesms.dependencies.ConfigFactory import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.groups.GroupManager +import org.thoughtcrime.securesms.groups.ClosedGroupManager import org.thoughtcrime.securesms.groups.OpenGroupManager import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob import org.thoughtcrime.securesms.mms.PartAuthority @@ -119,7 +125,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF // recipient is open group recipient.isOpenGroupRecipient -> { val openGroupJoinUrl = getOpenGroup(threadId)?.joinURL ?: return - Conversation.Community.parseFullUrl(openGroupJoinUrl)?.let { (base, room, pubKey) -> + BaseCommunityInfo.parseFullUrl(openGroupJoinUrl)?.let { (base, room, pubKey) -> config.getOrConstructCommunity(base, room, pubKey) } ?: return } @@ -269,6 +275,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF return DatabaseComponent.get(context).sessionJobDatabase().isJobCanceled(job) } + override fun cancelPendingMessageSendJobs(threadID: Long) { + val jobDb = DatabaseComponent.get(context).sessionJobDatabase() + jobDb.cancelPendingMessageSendJobs(threadID) + } + override fun getAuthToken(room: String, server: String): String? { val id = "$server.$room" return DatabaseComponent.get(context).lokiAPIDatabase().getAuthToken(id) @@ -361,6 +372,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF private fun updateUserGroups(userGroups: UserGroupsConfig) { val threadDb = DatabaseComponent.get(context).threadDatabase() + val localUserPublicKey = getUserPublicKey() ?: return Log.w( + "Loki-DBG", + "No user public key when trying to update user groups from config" + ) val communities = userGroups.allCommunityInfo() val lgc = userGroups.allLegacyGroupInfo() val allOpenGroups = getAllOpenGroups() @@ -378,7 +393,14 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF OpenGroupManager.delete(openGroup.server, openGroup.room, context) } -// GroupManager.deleteGroup() + toDeleteClosedGroups.forEach { deleteGroup -> + val threadId = getThreadId(deleteGroup.encodedId) + if (threadId == null) { + Log.w("Loki-DBG", "Existing group had no thread to delete") + } else { + ClosedGroupManager.silentlyRemoveGroup(context,threadId,GroupUtil.doubleDecodeGroupId(deleteGroup.encodedId), deleteGroup.encodedId, localUserPublicKey, delete = true) + } + } for (groupInfo in communities) { val groupBaseCommunity = groupInfo.community @@ -407,8 +429,24 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF 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 formationTimestamp = 0L + val formationTimestamp = SnodeAPI.nowWithOffset // TODO: formation timestamp for legacy ? current time? createGroup(groupId, title, members, null, null, admins, formationTimestamp) + setProfileSharing(Address.fromSerialized(groupId), true) + // Add the group to the user's set of public keys to poll for + addClosedGroupPublicKey(group.sessionId) + // Store the encryption key pair + val keyPair = ECKeyPair(DjbECPublicKey(group.encPubKey), DjbECPrivateKey(group.encSecKey)) + addClosedGroupEncryptionKeyPair(keyPair, group.sessionId, SnodeAPI.nowWithOffset) + // Set expiration timer + val expireTimer = group.expiration + setExpirationTimer(groupId, expireTimer) + // Notify the PN server + PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, group.sessionId, localUserPublicKey) + // Notify the user + val threadID = getOrCreateThreadIdFor(Address.fromSerialized(groupId)) + insertOutgoingInfoMessage(context, groupId, SignalServiceGroup.Type.CREATION, title, members.map { it.serialize() }, admins.map { it.serialize() }, threadID, formationTimestamp) + // Start polling + ClosedGroupPollerV2.shared.startPolling(group.sessionId) } } } @@ -696,8 +734,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF DatabaseComponent.get(context).lokiAPIDatabase().removeClosedGroupPublicKey(groupPublicKey) } - override fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String) { - DatabaseComponent.get(context).lokiAPIDatabase().addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey) + override fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String, timestamp: Long) { + DatabaseComponent.get(context).lokiAPIDatabase().addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey, timestamp) } override fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String) { @@ -716,7 +754,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF override fun setExpirationTimer(groupID: String, duration: Int) { val recipient = Recipient.from(context, fromSerialized(groupID), false) - DatabaseComponent.get(context).recipientDatabase().setExpireMessages(recipient, duration); + DatabaseComponent.get(context).recipientDatabase().setExpireMessages(recipient, duration) } override fun setServerCapabilities(server: String, capabilities: List) { @@ -917,6 +955,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF return threadDB.isPinned(threadID) } + override fun deleteConversation(threadID: Long) { + val threadDB = DatabaseComponent.get(context).threadDatabase() + threadDB.deleteConversation(threadID) + } + override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri { return PartAuthority.getAttachmentDataUri(attachmentId) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index 408bf6e621..1e3ab9e895 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -514,7 +514,7 @@ public class ThreadDatabase extends Database { public void setLastSeen(long threadId, long timestamp) { SQLiteDatabase db = databaseHelper.getWritableDatabase(); ContentValues contentValues = new ContentValues(1); - long lastSeenTime = timestamp == -1 ? SnodeAPI.INSTANCE.getNowWithOffset() : timestamp; + long lastSeenTime = timestamp == -1 ? SnodeAPI.getNowWithOffset() : timestamp; contentValues.put(LAST_SEEN, lastSeenTime); db.beginTransaction(); db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(threadId)}); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ClosedGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/ClosedGroupManager.kt new file mode 100644 index 0000000000..a61feaef1b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ClosedGroupManager.kt @@ -0,0 +1,31 @@ +package org.thoughtcrime.securesms.groups + +import android.content.Context +import org.session.libsession.messaging.MessagingModuleConfiguration +import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI +import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2 +import org.session.libsession.utilities.Address +import org.thoughtcrime.securesms.ApplicationContext + +object ClosedGroupManager { + + fun silentlyRemoveGroup(context: Context, threadId: Long, groupPublicKey: String, groupID: String, userPublicKey: String, delete: Boolean = true) { + val storage = MessagingModuleConfiguration.shared.storage + storage.removeClosedGroupPublicKey(groupPublicKey) + // Remove the key pairs + storage.removeAllClosedGroupEncryptionKeyPairs(groupPublicKey) + // Mark the group as inactive + storage.setActive(groupID, false) + storage.removeMember(groupID, Address.fromSerialized(userPublicKey)) + // Notify the PN server + PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey) + // Stop polling + ClosedGroupPollerV2.shared.stopPolling(groupPublicKey) + storage.cancelPendingMessageSendJobs(threadId) + ApplicationContext.getInstance(context).messageNotifier.updateNotification(context) + if (delete) { + storage.deleteConversation(threadId) + } + } + +} \ No newline at end of file diff --git a/libsession-util/src/main/cpp/contacts.h b/libsession-util/src/main/cpp/contacts.h index ae198a2d24..dbda80fb8f 100644 --- a/libsession-util/src/main/cpp/contacts.h +++ b/libsession-util/src/main/cpp/contacts.h @@ -13,8 +13,7 @@ inline session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) { inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info) { jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact"); - jmethodID constructor = env->GetMethodID(contactClass, "", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;I)V"); + jmethodID constructor = env->GetMethodID(contactClass, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;ILnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V"); jstring id = env->NewStringUTF(info.session_id.data()); jstring name = env->NewStringUTF(info.name.data()); jstring nickname = env->NewStringUTF(info.nickname.data()); @@ -23,22 +22,27 @@ inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info approvedMe = info.approved_me; blocked = info.blocked; jobject profilePic = util::serialize_user_pic(env, info.profile_picture); - jobject returnObj = env->NewObject(contactClass, constructor, id, name, nickname, approved, approvedMe, blocked, profilePic, info.priority); + jobject returnObj = env->NewObject(contactClass, constructor, id, name, nickname, approved, + approvedMe, blocked, profilePic, info.priority, + util::serialize_expiry(env, info.exp_mode, info.exp_timer)); return returnObj; } -inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf) { +inline session::config::contact_info +deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf) { jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact"); - jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic, getPriority; + jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic, getPriority, getExpiry; getId = env->GetFieldID(contactClass, "id", "Ljava/lang/String;"); getName = env->GetFieldID(contactClass, "name", "Ljava/lang/String;"); getNick = env->GetFieldID(contactClass, "nickname", "Ljava/lang/String;"); getApproved = env->GetFieldID(contactClass, "approved", "Z"); getApprovedMe = env->GetFieldID(contactClass, "approvedMe", "Z"); getBlocked = env->GetFieldID(contactClass, "blocked", "Z"); - getUserPic = env->GetFieldID(contactClass, "profilePicture", "Lnetwork/loki/messenger/libsession_util/util/UserPic;"); + getUserPic = env->GetFieldID(contactClass, "profilePicture", + "Lnetwork/loki/messenger/libsession_util/util/UserPic;"); getPriority = env->GetFieldID(contactClass, "priority", "I"); + getExpiry = env->GetFieldID(contactClass, "expiryMode", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;"); jstring name, nickname, session_id; session_id = static_cast(env->GetObjectField(info, getId)); name = static_cast(env->GetObjectField(info, getName)); @@ -49,6 +53,9 @@ inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject in approvedMe = env->GetBooleanField(info, getApprovedMe); blocked = env->GetBooleanField(info, getBlocked); jobject user_pic = env->GetObjectField(info, getUserPic); + jobject expiry_mode = env->GetObjectField(info, getExpiry); + + auto expiry_pair = util::deserialize_expiry(env, expiry_mode); std::string url; session::ustring key; @@ -91,6 +98,8 @@ inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject in } contact_info.priority = priority; + contact_info.exp_mode = expiry_pair.first; + contact_info.exp_timer = std::chrono::seconds(expiry_pair.second); return contact_info; } diff --git a/libsession-util/src/main/cpp/user_groups.h b/libsession-util/src/main/cpp/user_groups.h index 6dac6c95ec..7846054443 100644 --- a/libsession-util/src/main/cpp/user_groups.h +++ b/libsession-util/src/main/cpp/user_groups.h @@ -51,6 +51,7 @@ inline session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv * auto enc_pub_key_field = env->GetFieldID(clazz, "encPubKey", "[B"); auto enc_sec_key_field = env->GetFieldID(clazz, "encSecKey", "[B"); auto priority_field = env->GetFieldID(clazz, "priority", "I"); + auto disappearing_timer_field = env->GetFieldID(clazz, "disappearingTimer", "J"); jstring id = static_cast(env->GetObjectField(info, id_field)); jstring name = static_cast(env->GetObjectField(info, name_field)); jobject members_map = env->GetObjectField(info, members_field); @@ -72,8 +73,7 @@ inline session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv * info_deserialized.hidden = hidden; info_deserialized.enc_pubkey = enc_pub_key_bytes; info_deserialized.enc_seckey = enc_sec_key_bytes; - // TODO: this - // info_deserialized.disappearing_timer + info_deserialized.disappearing_timer = std::chrono::seconds(env->GetLongField(info, disappearing_timer_field)); env->ReleaseStringUTFChars(id, id_bytes); env->ReleaseStringUTFChars(name, name_bytes); return info_deserialized; @@ -119,8 +119,8 @@ inline jobject serialize_legacy_group_info(JNIEnv *env, session::config::legacy_ bool hidden = info.hidden; jclass legacy_group_class = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo"); - jmethodID constructor = env->GetMethodID(legacy_group_class, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Z[B[BI)V"); - jobject serialized = env->NewObject(legacy_group_class, constructor, session_id, name, members, hidden, enc_pubkey, enc_seckey, priority); + jmethodID constructor = env->GetMethodID(legacy_group_class, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Z[B[BIJ)V"); + jobject serialized = env->NewObject(legacy_group_class, constructor, session_id, name, members, hidden, enc_pubkey, enc_seckey, priority, (jlong) info.disappearing_timer.count()); return serialized; } diff --git a/libsession-util/src/main/cpp/util.cpp b/libsession-util/src/main/cpp/util.cpp index 50808891fd..d168e10d79 100644 --- a/libsession-util/src/main/cpp/util.cpp +++ b/libsession-util/src/main/cpp/util.cpp @@ -67,6 +67,40 @@ namespace util { return community; } + jobject serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds) { + jclass none = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE"); + jfieldID none_instance = env->GetStaticFieldID(none, "INSTANCE", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode$NONE;"); + jclass after_send = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend"); + jmethodID send_init = env->GetMethodID(after_send, "", "(J)V"); + jclass after_read = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead"); + jmethodID read_init = env->GetMethodID(after_read, "", "(J)V"); + + if (mode == session::config::expiration_mode::none) { + return env->GetStaticObjectField(none, none_instance); + } else if (mode == session::config::expiration_mode::after_send) { + return env->NewObject(after_send, send_init, time_seconds.count()); + } else if (mode == session::config::expiration_mode::after_read) { + return env->NewObject(after_read, read_init, time_seconds.count()); + } + return nullptr; + } + + std::pair deserialize_expiry(JNIEnv *env, jobject expiry_mode) { + jclass parent = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode"); + jclass after_read = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead"); + jclass after_send = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend"); + jfieldID duration_seconds = env->GetFieldID(parent, "expirySeconds", "J"); + + jclass object_class = env->GetObjectClass(expiry_mode); + + if (object_class == after_read) { + return std::pair(session::config::expiration_mode::after_read, env->GetLongField(expiry_mode, duration_seconds)); + } else if (object_class == after_send) { + return std::pair(session::config::expiration_mode::after_send, env->GetLongField(expiry_mode, duration_seconds)); + } + return std::pair(session::config::expiration_mode::none, 0); + } + } extern "C" diff --git a/libsession-util/src/main/cpp/util.h b/libsession-util/src/main/cpp/util.h index 78556629bc..9554b085b8 100644 --- a/libsession-util/src/main/cpp/util.h +++ b/libsession-util/src/main/cpp/util.h @@ -7,6 +7,7 @@ #include "session/types.hpp" #include "session/config/profile_pic.hpp" #include "session/config/user_groups.hpp" +#include "session/config/expiring.hpp" namespace util { jbyteArray bytes_from_ustring(JNIEnv* env, session::ustring_view from_str); @@ -15,6 +16,8 @@ namespace util { std::pair deserialize_user_pic(JNIEnv *env, jobject user_pic); jobject serialize_base_community(JNIEnv *env, const session::config::community& base_community); session::config::community deserialize_base_community(JNIEnv *env, jobject base_community); + jobject serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds); + std::pair deserialize_expiry(JNIEnv *env, jobject expiry_mode); } #endif \ No newline at end of file diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt index d842f6f97f..64e913bf78 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt @@ -2,11 +2,12 @@ package network.loki.messenger.libsession_util.util data class Contact( val id: String, - var name: String = "", - var nickname: String = "", - var approved: Boolean = false, - var approvedMe: Boolean = false, - var blocked: Boolean = false, - var profilePicture: UserPic = UserPic.DEFAULT, - var priority: Int = 0 + val name: String = "", + val nickname: String = "", + val approved: Boolean = false, + val approvedMe: Boolean = false, + val blocked: Boolean = false, + val profilePicture: UserPic = UserPic.DEFAULT, + val priority: Int = 0, + val expiryMode: ExpiryMode ) \ No newline at end of file diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt index 4e2ef42087..58e98a4392 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt @@ -1,7 +1,7 @@ package network.loki.messenger.libsession_util.util -sealed class ExpiryMode(val expiryMinutes: Long) { +sealed class ExpiryMode(val expirySeconds: Long) { object NONE: ExpiryMode(0) - class AfterSend(minutes: Long): ExpiryMode(minutes) - class AfterRead(minutes: Long): ExpiryMode(minutes) + class AfterSend(seconds: Long): ExpiryMode(seconds) + class AfterRead(seconds: Long): ExpiryMode(seconds) } \ No newline at end of file diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/GroupInfo.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/GroupInfo.kt index 92c68d1aab..0781bbc6d9 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/GroupInfo.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/GroupInfo.kt @@ -11,7 +11,8 @@ sealed class GroupInfo { val hidden: Boolean, val encPubKey: ByteArray, val encSecKey: ByteArray, - val priority: Int = 0 + val priority: Int = 0, + val disappearingTimer: Long ): GroupInfo() { companion object { @Suppress("FunctionName") diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index 184b36197a..381f513655 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -56,6 +56,7 @@ interface StorageProtocol { fun getConfigSyncJob(destination: Destination): Job? fun resumeMessageSendJobIfNeeded(messageSendJobID: String) fun isJobCanceled(job: Job): Boolean + fun cancelPendingMessageSendJobs(threadID: Long) // Authorization fun getAuthToken(room: String, server: String): String? @@ -130,7 +131,7 @@ interface StorageProtocol { fun getAllActiveClosedGroupPublicKeys(): Set fun addClosedGroupPublicKey(groupPublicKey: String) fun removeClosedGroupPublicKey(groupPublicKey: String) - fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String) + fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String, timestamp: Long) fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String) fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) @@ -163,6 +164,7 @@ interface StorageProtocol { fun getMessageCount(threadID: Long): Long fun setPinned(threadID: Long, isPinned: Boolean) fun isPinned(threadID: Long): Boolean + fun deleteConversation(threadID: Long) // Contacts fun getContactWithSessionID(sessionID: String): Contact? diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index 5adedc47ac..95c97a3f72 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -748,7 +748,7 @@ private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupCont } } -private fun isValidGroupUpdate(group: GroupRecord, sentTimestamp: Long, senderPublicKey: String): Boolean { +private fun isValidGroupUpdate(group: GroupRecord, sentTimestamp: Long, senderPublicKey: String): Boolean { val oldMembers = group.members.map { it.serialize() } // Check that the message isn't from before the group was created if (group.formationTimestamp > sentTimestamp) {