mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-28 20:45:17 +00:00
feat: add contacts expiry serialization/deserialization, more LGC, timestamps to add closed group encryption info (for latest tracking)
This commit is contained in:
parent
0b4cff71e3
commit
3318b53a1f
@ -458,9 +458,8 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
return ECKeyPair(DjbECPublicKey(keyPair.publicKey.serialize().removingIdPrefixIfNeeded()), DjbECPrivateKey(keyPair.privateKey.serialize()))
|
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 database = databaseHelper.writableDatabase
|
||||||
val timestamp = Date().time.toString()
|
|
||||||
val index = "$groupPublicKey-$timestamp"
|
val index = "$groupPublicKey-$timestamp"
|
||||||
val encryptionKeyPairPublicKey = encryptionKeyPair.publicKey.serialize().toHexString().removingIdPrefixIfNeeded()
|
val encryptionKeyPairPublicKey = encryptionKeyPair.publicKey.serialize().toHexString().removingIdPrefixIfNeeded()
|
||||||
val encryptionKeyPairPrivateKey = encryptionKeyPair.privateKey.serialize().toHexString()
|
val encryptionKeyPairPrivateKey = encryptionKeyPair.privateKey.serialize().toHexString()
|
||||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.database
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import network.loki.messenger.libsession_util.*
|
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.Conversation
|
||||||
import network.loki.messenger.libsession_util.util.UserPic
|
import network.loki.messenger.libsession_util.util.UserPic
|
||||||
import org.session.libsession.avatars.AvatarHelper
|
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.attachments.DatabaseAttachment
|
||||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
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.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.sending_receiving.quotes.QuoteModel
|
||||||
import org.session.libsession.messaging.utilities.SessionId
|
import org.session.libsession.messaging.utilities.SessionId
|
||||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||||
import org.session.libsession.messaging.utilities.UpdateMessageData
|
import org.session.libsession.messaging.utilities.UpdateMessageData
|
||||||
import org.session.libsession.snode.OnionRequestAPI
|
import org.session.libsession.snode.OnionRequestAPI
|
||||||
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsession.utilities.*
|
import org.session.libsession.utilities.*
|
||||||
import org.session.libsession.utilities.Address.Companion.fromSerialized
|
import org.session.libsession.utilities.Address.Companion.fromSerialized
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
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.crypto.ecc.ECKeyPair
|
||||||
import org.session.libsignal.messages.SignalServiceAttachmentPointer
|
import org.session.libsignal.messages.SignalServiceAttachmentPointer
|
||||||
import org.session.libsignal.messages.SignalServiceGroup
|
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.database.model.ReactionRecord
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
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.groups.OpenGroupManager
|
||||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority
|
import org.thoughtcrime.securesms.mms.PartAuthority
|
||||||
@ -119,7 +125,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
// recipient is open group
|
// recipient is open group
|
||||||
recipient.isOpenGroupRecipient -> {
|
recipient.isOpenGroupRecipient -> {
|
||||||
val openGroupJoinUrl = getOpenGroup(threadId)?.joinURL ?: return
|
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)
|
config.getOrConstructCommunity(base, room, pubKey)
|
||||||
} ?: return
|
} ?: return
|
||||||
}
|
}
|
||||||
@ -269,6 +275,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
return DatabaseComponent.get(context).sessionJobDatabase().isJobCanceled(job)
|
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? {
|
override fun getAuthToken(room: String, server: String): String? {
|
||||||
val id = "$server.$room"
|
val id = "$server.$room"
|
||||||
return DatabaseComponent.get(context).lokiAPIDatabase().getAuthToken(id)
|
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) {
|
private fun updateUserGroups(userGroups: UserGroupsConfig) {
|
||||||
val threadDb = DatabaseComponent.get(context).threadDatabase()
|
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 communities = userGroups.allCommunityInfo()
|
||||||
val lgc = userGroups.allLegacyGroupInfo()
|
val lgc = userGroups.allLegacyGroupInfo()
|
||||||
val allOpenGroups = getAllOpenGroups()
|
val allOpenGroups = getAllOpenGroups()
|
||||||
@ -378,7 +393,14 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
OpenGroupManager.delete(openGroup.server, openGroup.room, context)
|
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) {
|
for (groupInfo in communities) {
|
||||||
val groupBaseCommunity = groupInfo.community
|
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 admins = group.members.filter { it.value /*admin = true*/ }.keys.map { Address.fromSerialized(it) }
|
||||||
val groupId = GroupUtil.doubleEncodeGroupID(group.sessionId)
|
val groupId = GroupUtil.doubleEncodeGroupID(group.sessionId)
|
||||||
val title = group.name
|
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)
|
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)
|
DatabaseComponent.get(context).lokiAPIDatabase().removeClosedGroupPublicKey(groupPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String) {
|
override fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String, timestamp: Long) {
|
||||||
DatabaseComponent.get(context).lokiAPIDatabase().addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
DatabaseComponent.get(context).lokiAPIDatabase().addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String) {
|
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) {
|
override fun setExpirationTimer(groupID: String, duration: Int) {
|
||||||
val recipient = Recipient.from(context, fromSerialized(groupID), false)
|
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<String>) {
|
override fun setServerCapabilities(server: String, capabilities: List<String>) {
|
||||||
@ -917,6 +955,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
return threadDB.isPinned(threadID)
|
return threadDB.isPinned(threadID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deleteConversation(threadID: Long) {
|
||||||
|
val threadDB = DatabaseComponent.get(context).threadDatabase()
|
||||||
|
threadDB.deleteConversation(threadID)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
|
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
|
||||||
return PartAuthority.getAttachmentDataUri(attachmentId)
|
return PartAuthority.getAttachmentDataUri(attachmentId)
|
||||||
}
|
}
|
||||||
|
@ -514,7 +514,7 @@ public class ThreadDatabase extends Database {
|
|||||||
public void setLastSeen(long threadId, long timestamp) {
|
public void setLastSeen(long threadId, long timestamp) {
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues(1);
|
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);
|
contentValues.put(LAST_SEEN, lastSeenTime);
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(threadId)});
|
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(threadId)});
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,8 +13,7 @@ inline session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) {
|
|||||||
|
|
||||||
inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info) {
|
inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info) {
|
||||||
jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact");
|
jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact");
|
||||||
jmethodID constructor = env->GetMethodID(contactClass, "<init>",
|
jmethodID constructor = env->GetMethodID(contactClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;ILnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V");
|
||||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;I)V");
|
|
||||||
jstring id = env->NewStringUTF(info.session_id.data());
|
jstring id = env->NewStringUTF(info.session_id.data());
|
||||||
jstring name = env->NewStringUTF(info.name.data());
|
jstring name = env->NewStringUTF(info.name.data());
|
||||||
jstring nickname = env->NewStringUTF(info.nickname.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;
|
approvedMe = info.approved_me;
|
||||||
blocked = info.blocked;
|
blocked = info.blocked;
|
||||||
jobject profilePic = util::serialize_user_pic(env, info.profile_picture);
|
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;
|
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");
|
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;");
|
getId = env->GetFieldID(contactClass, "id", "Ljava/lang/String;");
|
||||||
getName = env->GetFieldID(contactClass, "name", "Ljava/lang/String;");
|
getName = env->GetFieldID(contactClass, "name", "Ljava/lang/String;");
|
||||||
getNick = env->GetFieldID(contactClass, "nickname", "Ljava/lang/String;");
|
getNick = env->GetFieldID(contactClass, "nickname", "Ljava/lang/String;");
|
||||||
getApproved = env->GetFieldID(contactClass, "approved", "Z");
|
getApproved = env->GetFieldID(contactClass, "approved", "Z");
|
||||||
getApprovedMe = env->GetFieldID(contactClass, "approvedMe", "Z");
|
getApprovedMe = env->GetFieldID(contactClass, "approvedMe", "Z");
|
||||||
getBlocked = env->GetFieldID(contactClass, "blocked", "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");
|
getPriority = env->GetFieldID(contactClass, "priority", "I");
|
||||||
|
getExpiry = env->GetFieldID(contactClass, "expiryMode", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;");
|
||||||
jstring name, nickname, session_id;
|
jstring name, nickname, session_id;
|
||||||
session_id = static_cast<jstring>(env->GetObjectField(info, getId));
|
session_id = static_cast<jstring>(env->GetObjectField(info, getId));
|
||||||
name = static_cast<jstring>(env->GetObjectField(info, getName));
|
name = static_cast<jstring>(env->GetObjectField(info, getName));
|
||||||
@ -49,6 +53,9 @@ inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject in
|
|||||||
approvedMe = env->GetBooleanField(info, getApprovedMe);
|
approvedMe = env->GetBooleanField(info, getApprovedMe);
|
||||||
blocked = env->GetBooleanField(info, getBlocked);
|
blocked = env->GetBooleanField(info, getBlocked);
|
||||||
jobject user_pic = env->GetObjectField(info, getUserPic);
|
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;
|
std::string url;
|
||||||
session::ustring key;
|
session::ustring key;
|
||||||
@ -91,6 +98,8 @@ inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject in
|
|||||||
}
|
}
|
||||||
|
|
||||||
contact_info.priority = priority;
|
contact_info.priority = priority;
|
||||||
|
contact_info.exp_mode = expiry_pair.first;
|
||||||
|
contact_info.exp_timer = std::chrono::seconds(expiry_pair.second);
|
||||||
|
|
||||||
return contact_info;
|
return contact_info;
|
||||||
}
|
}
|
||||||
|
@ -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_pub_key_field = env->GetFieldID(clazz, "encPubKey", "[B");
|
||||||
auto enc_sec_key_field = env->GetFieldID(clazz, "encSecKey", "[B");
|
auto enc_sec_key_field = env->GetFieldID(clazz, "encSecKey", "[B");
|
||||||
auto priority_field = env->GetFieldID(clazz, "priority", "I");
|
auto priority_field = env->GetFieldID(clazz, "priority", "I");
|
||||||
|
auto disappearing_timer_field = env->GetFieldID(clazz, "disappearingTimer", "J");
|
||||||
jstring id = static_cast<jstring>(env->GetObjectField(info, id_field));
|
jstring id = static_cast<jstring>(env->GetObjectField(info, id_field));
|
||||||
jstring name = static_cast<jstring>(env->GetObjectField(info, name_field));
|
jstring name = static_cast<jstring>(env->GetObjectField(info, name_field));
|
||||||
jobject members_map = env->GetObjectField(info, members_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.hidden = hidden;
|
||||||
info_deserialized.enc_pubkey = enc_pub_key_bytes;
|
info_deserialized.enc_pubkey = enc_pub_key_bytes;
|
||||||
info_deserialized.enc_seckey = enc_sec_key_bytes;
|
info_deserialized.enc_seckey = enc_sec_key_bytes;
|
||||||
// TODO: this
|
info_deserialized.disappearing_timer = std::chrono::seconds(env->GetLongField(info, disappearing_timer_field));
|
||||||
// info_deserialized.disappearing_timer
|
|
||||||
env->ReleaseStringUTFChars(id, id_bytes);
|
env->ReleaseStringUTFChars(id, id_bytes);
|
||||||
env->ReleaseStringUTFChars(name, name_bytes);
|
env->ReleaseStringUTFChars(name, name_bytes);
|
||||||
return info_deserialized;
|
return info_deserialized;
|
||||||
@ -119,8 +119,8 @@ inline jobject serialize_legacy_group_info(JNIEnv *env, session::config::legacy_
|
|||||||
bool hidden = info.hidden;
|
bool hidden = info.hidden;
|
||||||
|
|
||||||
jclass legacy_group_class = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
jclass legacy_group_class = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
||||||
jmethodID constructor = env->GetMethodID(legacy_group_class, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Z[B[BI)V");
|
jmethodID constructor = env->GetMethodID(legacy_group_class, "<init>", "(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);
|
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;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,40 @@ namespace util {
|
|||||||
return community;
|
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, "<init>", "(J)V");
|
||||||
|
jclass after_read = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead");
|
||||||
|
jmethodID read_init = env->GetMethodID(after_read, "<init>", "(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<session::config::expiration_mode, long> 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"
|
extern "C"
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "session/types.hpp"
|
#include "session/types.hpp"
|
||||||
#include "session/config/profile_pic.hpp"
|
#include "session/config/profile_pic.hpp"
|
||||||
#include "session/config/user_groups.hpp"
|
#include "session/config/user_groups.hpp"
|
||||||
|
#include "session/config/expiring.hpp"
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
jbyteArray bytes_from_ustring(JNIEnv* env, session::ustring_view from_str);
|
jbyteArray bytes_from_ustring(JNIEnv* env, session::ustring_view from_str);
|
||||||
@ -15,6 +16,8 @@ namespace util {
|
|||||||
std::pair<jstring, jbyteArray> deserialize_user_pic(JNIEnv *env, jobject user_pic);
|
std::pair<jstring, jbyteArray> deserialize_user_pic(JNIEnv *env, jobject user_pic);
|
||||||
jobject serialize_base_community(JNIEnv *env, const session::config::community& base_community);
|
jobject serialize_base_community(JNIEnv *env, const session::config::community& base_community);
|
||||||
session::config::community deserialize_base_community(JNIEnv *env, jobject 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<session::config::expiration_mode, long> deserialize_expiry(JNIEnv *env, jobject expiry_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -2,11 +2,12 @@ package network.loki.messenger.libsession_util.util
|
|||||||
|
|
||||||
data class Contact(
|
data class Contact(
|
||||||
val id: String,
|
val id: String,
|
||||||
var name: String = "",
|
val name: String = "",
|
||||||
var nickname: String = "",
|
val nickname: String = "",
|
||||||
var approved: Boolean = false,
|
val approved: Boolean = false,
|
||||||
var approvedMe: Boolean = false,
|
val approvedMe: Boolean = false,
|
||||||
var blocked: Boolean = false,
|
val blocked: Boolean = false,
|
||||||
var profilePicture: UserPic = UserPic.DEFAULT,
|
val profilePicture: UserPic = UserPic.DEFAULT,
|
||||||
var priority: Int = 0
|
val priority: Int = 0,
|
||||||
|
val expiryMode: ExpiryMode
|
||||||
)
|
)
|
@ -1,7 +1,7 @@
|
|||||||
package network.loki.messenger.libsession_util.util
|
package network.loki.messenger.libsession_util.util
|
||||||
|
|
||||||
sealed class ExpiryMode(val expiryMinutes: Long) {
|
sealed class ExpiryMode(val expirySeconds: Long) {
|
||||||
object NONE: ExpiryMode(0)
|
object NONE: ExpiryMode(0)
|
||||||
class AfterSend(minutes: Long): ExpiryMode(minutes)
|
class AfterSend(seconds: Long): ExpiryMode(seconds)
|
||||||
class AfterRead(minutes: Long): ExpiryMode(minutes)
|
class AfterRead(seconds: Long): ExpiryMode(seconds)
|
||||||
}
|
}
|
@ -11,7 +11,8 @@ sealed class GroupInfo {
|
|||||||
val hidden: Boolean,
|
val hidden: Boolean,
|
||||||
val encPubKey: ByteArray,
|
val encPubKey: ByteArray,
|
||||||
val encSecKey: ByteArray,
|
val encSecKey: ByteArray,
|
||||||
val priority: Int = 0
|
val priority: Int = 0,
|
||||||
|
val disappearingTimer: Long
|
||||||
): GroupInfo() {
|
): GroupInfo() {
|
||||||
companion object {
|
companion object {
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
|
@ -56,6 +56,7 @@ interface StorageProtocol {
|
|||||||
fun getConfigSyncJob(destination: Destination): Job?
|
fun getConfigSyncJob(destination: Destination): Job?
|
||||||
fun resumeMessageSendJobIfNeeded(messageSendJobID: String)
|
fun resumeMessageSendJobIfNeeded(messageSendJobID: String)
|
||||||
fun isJobCanceled(job: Job): Boolean
|
fun isJobCanceled(job: Job): Boolean
|
||||||
|
fun cancelPendingMessageSendJobs(threadID: Long)
|
||||||
|
|
||||||
// Authorization
|
// Authorization
|
||||||
fun getAuthToken(room: String, server: String): String?
|
fun getAuthToken(room: String, server: String): String?
|
||||||
@ -130,7 +131,7 @@ interface StorageProtocol {
|
|||||||
fun getAllActiveClosedGroupPublicKeys(): Set<String>
|
fun getAllActiveClosedGroupPublicKeys(): Set<String>
|
||||||
fun addClosedGroupPublicKey(groupPublicKey: String)
|
fun addClosedGroupPublicKey(groupPublicKey: String)
|
||||||
fun removeClosedGroupPublicKey(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 removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String)
|
||||||
fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type,
|
fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type,
|
||||||
name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long)
|
name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long)
|
||||||
@ -163,6 +164,7 @@ interface StorageProtocol {
|
|||||||
fun getMessageCount(threadID: Long): Long
|
fun getMessageCount(threadID: Long): Long
|
||||||
fun setPinned(threadID: Long, isPinned: Boolean)
|
fun setPinned(threadID: Long, isPinned: Boolean)
|
||||||
fun isPinned(threadID: Long): Boolean
|
fun isPinned(threadID: Long): Boolean
|
||||||
|
fun deleteConversation(threadID: Long)
|
||||||
|
|
||||||
// Contacts
|
// Contacts
|
||||||
fun getContactWithSessionID(sessionID: String): Contact?
|
fun getContactWithSessionID(sessionID: String): Contact?
|
||||||
|
Loading…
Reference in New Issue
Block a user