mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-25 02:55:23 +00:00
feat: more usergroup functionality, storage functionality for checking pinned status, adding pinned status for NTS/contacts, move community info parse full url to base community, add StorageProtocol logic for group info
This commit is contained in:
parent
2a701f2cc3
commit
66c997dfb2
@ -745,6 +745,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
return getThreadId(address)
|
return getThreadId(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getThreadId(openGroup: OpenGroup): Long? {
|
||||||
|
val address = fromSerialized("${openGroup.server}.${openGroup.room}")
|
||||||
|
return getThreadId(address)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getThreadId(address: Address): Long? {
|
override fun getThreadId(address: Address): Long? {
|
||||||
val recipient = Recipient.from(context, address, false)
|
val recipient = Recipient.from(context, address, false)
|
||||||
return getThreadId(recipient)
|
return getThreadId(recipient)
|
||||||
@ -866,7 +871,15 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
return mmsSmsDb.getConversationCount(threadID)
|
return mmsSmsDb.getConversationCount(threadID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setPinned(threadID: Long, isPinned: Boolean) {
|
||||||
|
val threadDB = DatabaseComponent.get(context).threadDatabase()
|
||||||
|
threadDB.setPinned(threadID, isPinned)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isPinned(threadID: Long): Boolean {
|
||||||
|
val threadDB = DatabaseComponent.get(context).threadDatabase()
|
||||||
|
return threadDB.isPinned(threadID)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
|
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
|
||||||
return PartAuthority.getAttachmentDataUri(attachmentId)
|
return PartAuthority.getAttachmentDataUri(attachmentId)
|
||||||
|
@ -740,6 +740,19 @@ public class ThreadDatabase extends Database {
|
|||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPinned(long threadId) {
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
|
Cursor cursor = db.query(TABLE_NAME, new String[]{DATE}, ID_WHERE, new String[]{String.valueOf(threadId)}, null, null, null);
|
||||||
|
try {
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
return cursor.getInt(0) == 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void markAllAsRead(long threadId, boolean isGroupRecipient, long lastSeenTime) {
|
public void markAllAsRead(long threadId, boolean isGroupRecipient, long lastSeenTime) {
|
||||||
List<MarkedMessageInfo> messages = setRead(threadId, lastSeenTime);
|
List<MarkedMessageInfo> messages = setRead(threadId, lastSeenTime);
|
||||||
if (isGroupRecipient) {
|
if (isGroupRecipient) {
|
||||||
|
@ -4,9 +4,12 @@ import android.content.Context
|
|||||||
import network.loki.messenger.libsession_util.ConfigBase
|
import network.loki.messenger.libsession_util.ConfigBase
|
||||||
import network.loki.messenger.libsession_util.Contacts
|
import network.loki.messenger.libsession_util.Contacts
|
||||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||||
|
import network.loki.messenger.libsession_util.UserGroupsConfig
|
||||||
import network.loki.messenger.libsession_util.UserProfile
|
import network.loki.messenger.libsession_util.UserProfile
|
||||||
|
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
|
||||||
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.GroupInfo
|
||||||
import network.loki.messenger.libsession_util.util.UserPic
|
import network.loki.messenger.libsession_util.util.UserPic
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
@ -19,7 +22,9 @@ import org.session.libsession.messaging.utilities.SessionId
|
|||||||
import org.session.libsession.utilities.Address
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
|
import org.session.libsignal.utilities.toHexString
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||||
|
|
||||||
object ConfigurationMessageUtilities {
|
object ConfigurationMessageUtilities {
|
||||||
@ -103,6 +108,8 @@ object ConfigurationMessageUtilities {
|
|||||||
private fun maybeUserSecretKey() = MessagingModuleConfiguration.shared.getUserED25519KeyPair()?.secretKey?.asBytes
|
private fun maybeUserSecretKey() = MessagingModuleConfiguration.shared.getUserED25519KeyPair()?.secretKey?.asBytes
|
||||||
|
|
||||||
fun generateUserProfileConfigDump(): ByteArray? {
|
fun generateUserProfileConfigDump(): ByteArray? {
|
||||||
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
val ownPublicKey = storage.getUserPublicKey() ?: return null
|
||||||
val config = ConfigurationMessage.getCurrent(listOf()) ?: return null
|
val config = ConfigurationMessage.getCurrent(listOf()) ?: return null
|
||||||
val secretKey = maybeUserSecretKey() ?: return null
|
val secretKey = maybeUserSecretKey() ?: return null
|
||||||
val profile = UserProfile.newInstance(secretKey)
|
val profile = UserProfile.newInstance(secretKey)
|
||||||
@ -112,6 +119,13 @@ object ConfigurationMessageUtilities {
|
|||||||
if (!picUrl.isNullOrEmpty() && picKey.isNotEmpty()) {
|
if (!picUrl.isNullOrEmpty() && picKey.isNotEmpty()) {
|
||||||
profile.setPic(UserPic(picUrl, picKey))
|
profile.setPic(UserPic(picUrl, picKey))
|
||||||
}
|
}
|
||||||
|
val ownThreadId = storage.getThreadId(Address.fromSerialized(ownPublicKey))
|
||||||
|
profile.setNtsHidden(ownThreadId != null)
|
||||||
|
if (ownThreadId != null) {
|
||||||
|
// have NTS thread
|
||||||
|
val ntsPinned = storage.isPinned(ownThreadId)
|
||||||
|
profile.setNtsPriority(if (ntsPinned) 1 else 0) // TODO: implement the pinning priority here in future
|
||||||
|
}
|
||||||
val dump = profile.dump()
|
val dump = profile.dump()
|
||||||
profile.free()
|
profile.free()
|
||||||
return dump
|
return dump
|
||||||
@ -124,10 +138,16 @@ object ConfigurationMessageUtilities {
|
|||||||
val contactsWithSettings = storage.getAllContacts().filter { recipient ->
|
val contactsWithSettings = storage.getAllContacts().filter { recipient ->
|
||||||
recipient.sessionID != localUserKey
|
recipient.sessionID != localUserKey
|
||||||
}.map { contact ->
|
}.map { contact ->
|
||||||
contact to storage.getRecipientSettings(Address.fromSerialized(contact.sessionID))!!
|
val address = Address.fromSerialized(contact.sessionID)
|
||||||
|
val thread = storage.getThreadId(address)
|
||||||
|
val isPinned = if (thread != null) {
|
||||||
|
storage.isPinned(thread)
|
||||||
|
} else false
|
||||||
|
|
||||||
|
Triple(contact, storage.getRecipientSettings(address)!!, isPinned)
|
||||||
}
|
}
|
||||||
val contactConfig = Contacts.newInstance(secretKey)
|
val contactConfig = Contacts.newInstance(secretKey)
|
||||||
for ((contact, settings) in contactsWithSettings) {
|
for ((contact, settings, isPinned) in contactsWithSettings) {
|
||||||
val url = contact.profilePictureURL
|
val url = contact.profilePictureURL
|
||||||
val key = contact.profilePictureEncryptionKey
|
val key = contact.profilePictureEncryptionKey
|
||||||
val userPic = if (url.isNullOrEmpty() || key?.isNotEmpty() != true) {
|
val userPic = if (url.isNullOrEmpty() || key?.isNotEmpty() != true) {
|
||||||
@ -143,7 +163,7 @@ object ConfigurationMessageUtilities {
|
|||||||
approved = settings.isApproved,
|
approved = settings.isApproved,
|
||||||
approvedMe = settings.hasApprovedMe(),
|
approvedMe = settings.hasApprovedMe(),
|
||||||
profilePicture = userPic ?: UserPic.DEFAULT,
|
profilePicture = userPic ?: UserPic.DEFAULT,
|
||||||
priority = if ()
|
priority = if (isPinned) 1 else 0
|
||||||
)
|
)
|
||||||
contactConfig.set(contactInfo)
|
contactConfig.set(contactInfo)
|
||||||
}
|
}
|
||||||
@ -196,4 +216,45 @@ object ConfigurationMessageUtilities {
|
|||||||
return dump
|
return dump
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun generateUserGroupDump(context: Context): ByteArray? {
|
||||||
|
val secretKey = maybeUserSecretKey() ?: return null
|
||||||
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
val groupConfig = UserGroupsConfig.newInstance(secretKey)
|
||||||
|
val allOpenGroups = storage.getAllOpenGroups().values.mapNotNull { openGroup ->
|
||||||
|
val (baseUrl, room, pubKey) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return@mapNotNull null
|
||||||
|
val pubKeyHex = Hex.toStringCondensed(pubKey)
|
||||||
|
val baseInfo = BaseCommunityInfo(baseUrl, room, pubKeyHex)
|
||||||
|
val threadId = storage.getThreadId(openGroup) ?: return@mapNotNull null
|
||||||
|
val isPinned = storage.isPinned(threadId)
|
||||||
|
GroupInfo.CommunityGroupInfo(baseInfo, if (isPinned) 1 else 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val allLgc = storage.getAllGroups().filter { it.isClosedGroup }.mapNotNull { group ->
|
||||||
|
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
||||||
|
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: return@mapNotNull null
|
||||||
|
val threadId = storage.getThreadId(group.encodedId)
|
||||||
|
val isPinned = threadId?.let { storage.isPinned(threadId) } ?: false
|
||||||
|
val sessionId = GroupUtil.doubleEncodeGroupID(group.getId())
|
||||||
|
val admins = group.admins.map { it.serialize() to true }.toMap()
|
||||||
|
val members = group.members.filterNot { it.serialize() !in admins.keys }.map { it.serialize() to false }.toMap()
|
||||||
|
val encPub = storage.getClosedGroupEncryptionKeyPairs(group.)
|
||||||
|
GroupInfo.LegacyGroupInfo(
|
||||||
|
sessionId = sessionId,
|
||||||
|
name = group.title,
|
||||||
|
members = admins + members,
|
||||||
|
hidden = threadId == null,
|
||||||
|
priority = if (isPinned) 1 else 0,
|
||||||
|
encPubKey = encryptionKeyPair.publicKey.serialize(),
|
||||||
|
encSecKey = encryptionKeyPair.privateKey.serialize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
(allOpenGroups + allLgc).forEach { groupInfo ->
|
||||||
|
groupConfig.set(groupInfo)
|
||||||
|
}
|
||||||
|
val dump = groupConfig.dump()
|
||||||
|
groupConfig.free()
|
||||||
|
return dump
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,25 +3,6 @@
|
|||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jobject JNICALL
|
|
||||||
Java_network_loki_messenger_libsession_1util_util_Conversation_00024Community_00024Companion_parseFullUrl(
|
|
||||||
JNIEnv *env, jobject thiz, jstring full_url) {
|
|
||||||
auto bytes = env->GetStringUTFChars(full_url, nullptr);
|
|
||||||
auto [base, room, pk] = session::config::convo::community::parse_full_url(bytes);
|
|
||||||
env->ReleaseStringUTFChars(full_url, bytes);
|
|
||||||
|
|
||||||
jclass clazz = env->FindClass("kotlin/Triple");
|
|
||||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V");
|
|
||||||
|
|
||||||
auto base_j = env->NewStringUTF(base.data());
|
|
||||||
auto room_j = env->NewStringUTF(room.data());
|
|
||||||
auto pk_jbytes = util::bytes_from_ustring(env, pk);
|
|
||||||
|
|
||||||
jobject triple = env->NewObject(clazz, constructor, base_j, room_j, pk_jbytes);
|
|
||||||
return triple;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||||
JNIEXPORT jobject JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
|
@ -110,6 +110,22 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructLega
|
|||||||
return serialize_legacy_group_info(env, group);
|
return serialize_legacy_group_info(env, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_2(
|
||||||
|
JNIEnv *env, jobject thiz, jobject group_info) {
|
||||||
|
auto conf = ptrToUserGroups(env, thiz);
|
||||||
|
auto communityInfo = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo");
|
||||||
|
auto legacyInfo = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
||||||
|
if (env->GetObjectClass(group_info) == communityInfo) {
|
||||||
|
auto deserialized = deserialize_community_info(env, group_info);
|
||||||
|
conf->set(deserialized);
|
||||||
|
} else if (env->GetObjectClass(group_info) == legacyInfo) {
|
||||||
|
auto deserialized = deserialize_legacy_group_info(env, group_info);
|
||||||
|
conf->set(deserialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_CommunityGroupInfo_2(
|
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_CommunityGroupInfo_2(
|
||||||
|
@ -101,4 +101,22 @@ Java_network_loki_messenger_libsession_1util_util_Sodium_ed25519PkToCurve25519(J
|
|||||||
}
|
}
|
||||||
jbyteArray curve_pk_jarray = util::bytes_from_ustring(env, session::ustring_view {curve_pk.data(), curve_pk.size()});
|
jbyteArray curve_pk_jarray = util::bytes_from_ustring(env, session::ustring_view {curve_pk.data(), curve_pk.size()});
|
||||||
return curve_pk_jarray;
|
return curve_pk_jarray;
|
||||||
|
}
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_messenger_libsession_1util_util_BaseCommunityInfo_00024Companion_parseFullUrl(
|
||||||
|
JNIEnv *env, jobject thiz, jstring full_url) {
|
||||||
|
auto bytes = env->GetStringUTFChars(full_url, nullptr);
|
||||||
|
auto [base, room, pk] = session::config::community::parse_full_url(bytes);
|
||||||
|
env->ReleaseStringUTFChars(full_url, bytes);
|
||||||
|
|
||||||
|
jclass clazz = env->FindClass("kotlin/Triple");
|
||||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||||
|
|
||||||
|
auto base_j = env->NewStringUTF(base.data());
|
||||||
|
auto room_j = env->NewStringUTF(room.data());
|
||||||
|
auto pk_jbytes = util::bytes_from_ustring(env, pk);
|
||||||
|
|
||||||
|
jobject triple = env->NewObject(clazz, constructor, base_j, room_j, pk_jbytes);
|
||||||
|
return triple;
|
||||||
}
|
}
|
@ -155,6 +155,7 @@ class UserGroupsConfig(pointer: Long): ConfigBase(pointer) {
|
|||||||
external fun getLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo?
|
external fun getLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo?
|
||||||
external fun getOrConstructCommunityInfo(baseUrl: String, room: String, pubKeyHex: String): GroupInfo.CommunityGroupInfo
|
external fun getOrConstructCommunityInfo(baseUrl: String, room: String, pubKeyHex: String): GroupInfo.CommunityGroupInfo
|
||||||
external fun getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo
|
external fun getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo
|
||||||
|
external fun set(groupInfo: GroupInfo)
|
||||||
external fun set(communityInfo: GroupInfo.CommunityGroupInfo)
|
external fun set(communityInfo: GroupInfo.CommunityGroupInfo)
|
||||||
external fun set(legacyGroupInfo: GroupInfo.LegacyGroupInfo)
|
external fun set(legacyGroupInfo: GroupInfo.LegacyGroupInfo)
|
||||||
external fun erase(communityInfo: GroupInfo.CommunityGroupInfo)
|
external fun erase(communityInfo: GroupInfo.CommunityGroupInfo)
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
package network.loki.messenger.libsession_util.util
|
package network.loki.messenger.libsession_util.util
|
||||||
|
|
||||||
data class BaseCommunityInfo(val baseUrl: String, val room: String, val pubKeyHex: String)
|
data class BaseCommunityInfo(val baseUrl: String, val room: String, val pubKeyHex: String) {
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
System.loadLibrary("session_util")
|
||||||
|
}
|
||||||
|
external fun parseFullUrl(fullUrl: String): Triple<String, String, ByteArray>?
|
||||||
|
}
|
||||||
|
}
|
@ -153,6 +153,7 @@ interface StorageProtocol {
|
|||||||
fun getOrCreateThreadIdFor(address: Address): Long
|
fun getOrCreateThreadIdFor(address: Address): Long
|
||||||
fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long
|
fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long
|
||||||
fun getThreadId(publicKeyOrOpenGroupID: String): Long?
|
fun getThreadId(publicKeyOrOpenGroupID: String): Long?
|
||||||
|
fun getThreadId(openGroup: OpenGroup): Long?
|
||||||
fun getThreadId(address: Address): Long?
|
fun getThreadId(address: Address): Long?
|
||||||
fun getThreadId(recipient: Recipient): Long?
|
fun getThreadId(recipient: Recipient): Long?
|
||||||
fun getThreadIdForMms(mmsId: Long): Long
|
fun getThreadIdForMms(mmsId: Long): Long
|
||||||
@ -160,6 +161,8 @@ interface StorageProtocol {
|
|||||||
fun trimThread(threadID: Long, threadLimit: Int)
|
fun trimThread(threadID: Long, threadLimit: Int)
|
||||||
fun trimThreadBefore(threadID: Long, timestamp: Long)
|
fun trimThreadBefore(threadID: Long, timestamp: Long)
|
||||||
fun getMessageCount(threadID: Long): Long
|
fun getMessageCount(threadID: Long): Long
|
||||||
|
fun setPinned(threadID: Long, isPinned: Boolean)
|
||||||
|
fun isPinned(threadID: Long): Boolean
|
||||||
|
|
||||||
// Contacts
|
// Contacts
|
||||||
fun getContactWithSessionID(sessionID: String): Contact?
|
fun getContactWithSessionID(sessionID: String): Contact?
|
||||||
|
Loading…
Reference in New Issue
Block a user