session-android/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt

456 lines
24 KiB
Kotlin
Raw Normal View History

2021-07-09 05:25:57 +02:00
package org.thoughtcrime.securesms.database
2019-06-04 01:35:18 +02:00
2019-06-04 03:05:03 +02:00
import android.content.ContentValues
2019-06-04 01:35:18 +02:00
import android.content.Context
import org.session.libsession.utilities.TextSecurePreferences
2021-05-18 01:21:56 +02:00
import org.session.libsignal.crypto.ecc.DjbECPrivateKey
import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.crypto.ecc.ECKeyPair
2021-05-18 01:50:16 +02:00
import org.session.libsignal.database.LokiAPIDatabaseProtocol
import org.session.libsignal.utilities.*
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
2021-07-09 05:18:48 +02:00
import org.thoughtcrime.securesms.database.*
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
2021-07-09 05:18:48 +02:00
import org.thoughtcrime.securesms.util.*
import java.util.*
import kotlin.Array
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.Pair
import kotlin.String
import kotlin.arrayOf
import kotlin.to
2019-06-04 01:35:18 +02:00
2019-06-11 01:46:42 +02:00
class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiAPIDatabaseProtocol {
2019-06-04 01:35:18 +02:00
companion object {
2020-07-16 01:46:10 +02:00
// Shared
private val publicKey = "public_key"
private val timestamp = "timestamp"
2020-08-10 03:40:43 +02:00
private val snode = "snode"
// Snode pool
2021-05-06 07:46:22 +02:00
public val snodePoolTable = "loki_snode_pool_cache"
2020-05-29 04:01:43 +02:00
private val dummyKey = "dummy_key"
2020-06-01 02:33:47 +02:00
private val snodePool = "snode_pool_key"
@JvmStatic val createSnodePoolTableCommand = "CREATE TABLE $snodePoolTable ($dummyKey TEXT PRIMARY KEY, $snodePool TEXT);"
2020-08-10 03:40:43 +02:00
// Onion request paths
private val onionRequestPathTable = "loki_path_cache"
private val indexPath = "index_path"
@JvmStatic val createOnionRequestPathTableCommand = "CREATE TABLE $onionRequestPathTable ($indexPath TEXT PRIMARY KEY, $snode TEXT);"
2020-08-10 03:40:43 +02:00
// Swarms
2021-05-06 07:46:22 +02:00
public val swarmTable = "loki_api_swarm_cache"
2020-07-15 04:24:43 +02:00
private val swarmPublicKey = "hex_encoded_public_key"
2019-06-04 03:05:03 +02:00
private val swarm = "swarm"
@JvmStatic val createSwarmTableCommand = "CREATE TABLE $swarmTable ($swarmPublicKey TEXT PRIMARY KEY, $swarm TEXT);"
2020-08-10 03:40:43 +02:00
// Last message hash values
private val lastMessageHashValueTable2 = "last_message_hash_value_table"
2019-06-04 03:05:03 +02:00
private val lastMessageHashValue = "last_message_hash_value"
2020-08-10 03:40:43 +02:00
@JvmStatic val createLastMessageHashValueTable2Command
2020-08-12 02:00:35 +02:00
= "CREATE TABLE $lastMessageHashValueTable2 ($snode TEXT, $publicKey TEXT, $lastMessageHashValue TEXT, PRIMARY KEY ($snode, $publicKey));"
2020-08-10 03:40:43 +02:00
// Received message hash values
2020-08-20 02:32:31 +02:00
private val receivedMessageHashValuesTable3 = "received_message_hash_values_table_3"
2019-06-04 03:05:03 +02:00
private val receivedMessageHashValues = "received_message_hash_values"
2020-08-20 02:32:31 +02:00
@JvmStatic val createReceivedMessageHashValuesTable3Command
= "CREATE TABLE $receivedMessageHashValuesTable3 ($publicKey STRING PRIMARY KEY, $receivedMessageHashValues TEXT);"
2020-08-10 03:40:43 +02:00
// Open group auth tokens
private val openGroupAuthTokenTable = "loki_api_group_chat_auth_token_database"
2019-08-28 04:09:05 +02:00
private val server = "server"
2019-08-23 08:57:26 +02:00
private val token = "token"
@JvmStatic val createOpenGroupAuthTokenTableCommand = "CREATE TABLE $openGroupAuthTokenTable ($server TEXT PRIMARY KEY, $token TEXT);"
2020-08-10 03:40:43 +02:00
// Last message server IDs
private val lastMessageServerIDTable = "loki_api_last_message_server_id_cache"
private val lastMessageServerIDTableIndex = "loki_api_last_message_server_id_cache_index"
2019-08-26 05:55:45 +02:00
private val lastMessageServerID = "last_message_server_id"
2020-08-10 03:40:43 +02:00
@JvmStatic val createLastMessageServerIDTableCommand = "CREATE TABLE $lastMessageServerIDTable ($lastMessageServerIDTableIndex STRING PRIMARY KEY, $lastMessageServerID INTEGER DEFAULT 0);"
// Last deletion server IDs
private val lastDeletionServerIDTable = "loki_api_last_deletion_server_id_cache"
private val lastDeletionServerIDTableIndex = "loki_api_last_deletion_server_id_cache_index"
private val lastDeletionServerID = "last_deletion_server_id"
2020-08-10 03:40:43 +02:00
@JvmStatic val createLastDeletionServerIDTableCommand = "CREATE TABLE $lastDeletionServerIDTable ($lastDeletionServerIDTableIndex STRING PRIMARY KEY, $lastDeletionServerID INTEGER DEFAULT 0);"
// User counts
private val userCountTable = "loki_user_count_cache"
2020-01-22 00:46:04 +01:00
private val publicChatID = "public_chat_id"
private val userCount = "user_count"
2020-08-10 03:40:43 +02:00
@JvmStatic val createUserCountTableCommand = "CREATE TABLE $userCountTable ($publicChatID STRING PRIMARY KEY, $userCount INTEGER DEFAULT 0);"
// Session request sent timestamps
private val sessionRequestSentTimestampTable = "session_request_sent_timestamp_cache"
@JvmStatic val createSessionRequestSentTimestampTableCommand = "CREATE TABLE $sessionRequestSentTimestampTable ($publicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);"
2020-07-16 01:44:00 +02:00
// Session request processed timestamp cache
2020-08-10 03:40:43 +02:00
private val sessionRequestProcessedTimestampTable = "session_request_processed_timestamp_cache"
@JvmStatic val createSessionRequestProcessedTimestampTableCommand = "CREATE TABLE $sessionRequestProcessedTimestampTable ($publicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);"
2020-07-29 01:04:24 +02:00
// Open group public keys
2020-08-10 03:40:43 +02:00
private val openGroupPublicKeyTable = "open_group_public_keys"
@JvmStatic val createOpenGroupPublicKeyTableCommand = "CREATE TABLE $openGroupPublicKeyTable ($server STRING PRIMARY KEY, $publicKey INTEGER DEFAULT 0);"
2020-10-19 06:12:06 +02:00
// Open group profile picture cache
public val openGroupProfilePictureTable = "open_group_avatar_cache"
2020-10-19 06:12:06 +02:00
private val openGroupProfilePicture = "open_group_avatar"
@JvmStatic val createOpenGroupProfilePictureTableCommand = "CREATE TABLE $openGroupProfilePictureTable ($publicChatID STRING PRIMARY KEY, $openGroupProfilePicture TEXT NULLABLE DEFAULT NULL);"
2021-01-13 06:13:49 +01:00
// Closed groups (V2)
public val closedGroupEncryptionKeyPairsTable = "closed_group_encryption_key_pairs_table"
public val closedGroupsEncryptionKeyPairIndex = "closed_group_encryption_key_pair_index"
public val encryptionKeyPairPublicKey = "encryption_key_pair_public_key"
public val encryptionKeyPairPrivateKey = "encryption_key_pair_private_key"
@JvmStatic
val createClosedGroupEncryptionKeyPairsTable = "CREATE TABLE $closedGroupEncryptionKeyPairsTable ($closedGroupsEncryptionKeyPairIndex STRING PRIMARY KEY, $encryptionKeyPairPublicKey STRING, $encryptionKeyPairPrivateKey STRING)"
public val closedGroupPublicKeysTable = "closed_group_public_keys_table"
public val groupPublicKey = "group_public_key"
@JvmStatic
val createClosedGroupPublicKeysTable = "CREATE TABLE $closedGroupPublicKeysTable ($groupPublicKey STRING PRIMARY KEY)"
2020-07-16 01:44:00 +02:00
// region Deprecated
2020-08-10 03:40:43 +02:00
private val deviceLinkCache = "loki_pairing_authorisation_cache"
private val masterPublicKey = "primary_device"
private val slavePublicKey = "secondary_device"
private val requestSignature = "request_signature"
private val authorizationSignature = "grant_signature"
@JvmStatic val createDeviceLinkCacheCommand = "CREATE TABLE $deviceLinkCache ($masterPublicKey STRING, $slavePublicKey STRING, " +
"$requestSignature STRING NULLABLE DEFAULT NULL, $authorizationSignature STRING NULLABLE DEFAULT NULL, PRIMARY KEY ($masterPublicKey, $slavePublicKey));"
2020-05-22 02:41:31 +02:00
private val sessionRequestTimestampCache = "session_request_timestamp_cache"
2020-07-29 01:04:24 +02:00
@JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($publicKey STRING PRIMARY KEY, $timestamp STRING);"
2020-07-16 01:44:00 +02:00
// endregion
2019-06-04 01:35:18 +02:00
}
2020-07-08 09:05:26 +02:00
override fun getSnodePool(): Set<Snode> {
2020-05-29 04:01:43 +02:00
val database = databaseHelper.readableDatabase
2020-08-10 03:40:43 +02:00
return database.get(snodePoolTable, "${Companion.dummyKey} = ?", wrap("dummy_key")) { cursor ->
2020-06-01 02:33:47 +02:00
val snodePoolAsString = cursor.getString(cursor.getColumnIndexOrThrow(snodePool))
2020-05-29 04:01:43 +02:00
snodePoolAsString.split(", ").mapNotNull { snodeAsString ->
val components = snodeAsString.split("-")
val address = components[0]
val port = components.getOrNull(1)?.toIntOrNull() ?: return@mapNotNull null
val ed25519Key = components.getOrNull(2) ?: return@mapNotNull null
val x25519Key = components.getOrNull(3) ?: return@mapNotNull null
2020-07-08 09:05:26 +02:00
Snode(address, port, Snode.KeySet(ed25519Key, x25519Key))
2020-05-29 04:01:43 +02:00
}
}?.toSet() ?: setOf()
}
2020-07-08 09:05:26 +02:00
override fun setSnodePool(newValue: Set<Snode>) {
2020-05-29 04:01:43 +02:00
val database = databaseHelper.writableDatabase
val snodePoolAsString = newValue.joinToString(", ") { snode ->
var string = "${snode.address}-${snode.port}"
val keySet = snode.publicKeySet
if (keySet != null) {
string += "-${keySet.ed25519Key}-${keySet.x25519Key}"
}
string
}
2020-08-12 02:00:35 +02:00
val row = wrap(mapOf( Companion.dummyKey to "dummy_key", snodePool to snodePoolAsString ))
2020-08-10 03:40:43 +02:00
database.insertOrUpdate(snodePoolTable, row, "${Companion.dummyKey} = ?", wrap("dummy_key"))
2020-05-29 04:01:43 +02:00
}
2020-10-09 04:57:52 +02:00
override fun setOnionRequestPaths(newValue: List<List<Snode>>) {
// FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this.
val database = databaseHelper.writableDatabase
fun set(indexPath: String, snode: Snode) {
var snodeAsString = "${snode.address}-${snode.port}"
val keySet = snode.publicKeySet
if (keySet != null) {
snodeAsString += "-${keySet.ed25519Key}-${keySet.x25519Key}"
}
val row = wrap(mapOf( Companion.indexPath to indexPath, Companion.snode to snodeAsString ))
database.insertOrUpdate(onionRequestPathTable, row, "${Companion.indexPath} = ?", wrap(indexPath))
}
Log.d("Loki", "Persisting onion request paths to database.")
2020-10-09 05:38:29 +02:00
clearOnionRequestPaths()
2020-10-09 04:57:52 +02:00
if (newValue.count() < 1) { return }
val path0 = newValue[0]
if (path0.count() != 3) { return }
set("0-0", path0[0]); set("0-1", path0[1]); set("0-2", path0[2])
if (newValue.count() < 2) { return }
val path1 = newValue[1]
if (path1.count() != 3) { return }
set("1-0", path1[0]); set("1-1", path1[1]); set("1-2", path1[2])
}
2020-07-08 09:05:26 +02:00
override fun getOnionRequestPaths(): List<List<Snode>> {
val database = databaseHelper.readableDatabase
2020-07-08 09:05:26 +02:00
fun get(indexPath: String): Snode? {
2020-08-10 03:40:43 +02:00
return database.get(onionRequestPathTable, "${Companion.indexPath} = ?", wrap(indexPath)) { cursor ->
val snodeAsString = cursor.getString(cursor.getColumnIndexOrThrow(snode))
val components = snodeAsString.split("-")
val address = components[0]
val port = components.getOrNull(1)?.toIntOrNull()
val ed25519Key = components.getOrNull(2)
val x25519Key = components.getOrNull(3)
if (port != null && ed25519Key != null && x25519Key != null) {
2020-07-08 09:05:26 +02:00
Snode(address, port, Snode.KeySet(ed25519Key, x25519Key))
} else {
null
}
}
}
2020-10-09 04:57:52 +02:00
val result = mutableListOf<List<Snode>>()
val path0Snode0 = get("0-0"); val path0Snode1 = get("0-1"); val path0Snode2 = get("0-2")
if (path0Snode0 != null && path0Snode1 != null && path0Snode2 != null) {
result.add(listOf( path0Snode0, path0Snode1, path0Snode2 ))
}
val path1Snode0 = get("1-0"); val path1Snode1 = get("1-1"); val path1Snode2 = get("1-2")
if (path1Snode0 != null && path1Snode1 != null && path1Snode2 != null) {
result.add(listOf( path1Snode0, path1Snode1, path1Snode2 ))
}
return result
}
2020-09-01 10:30:54 +02:00
override fun clearOnionRequestPaths() {
val database = databaseHelper.writableDatabase
fun delete(indexPath: String) {
2020-08-10 03:40:43 +02:00
database.delete(onionRequestPathTable, "${Companion.indexPath} = ?", wrap(indexPath))
}
delete("0-0"); delete("0-1")
delete("0-2"); delete("1-0")
delete("1-1"); delete("1-2")
}
2020-07-15 04:24:43 +02:00
override fun getSwarm(publicKey: String): Set<Snode>? {
2019-06-04 04:12:40 +02:00
val database = databaseHelper.readableDatabase
2020-08-10 03:40:43 +02:00
return database.get(swarmTable, "${Companion.swarmPublicKey} = ?", wrap(publicKey)) { cursor ->
2019-06-04 03:05:03 +02:00
val swarmAsString = cursor.getString(cursor.getColumnIndexOrThrow(swarm))
swarmAsString.split(", ").mapNotNull { targetAsString ->
val components = targetAsString.split("-")
val address = components[0]
2020-01-28 00:18:18 +01:00
val port = components.getOrNull(1)?.toIntOrNull() ?: return@mapNotNull null
2020-05-11 08:19:26 +02:00
val ed25519Key = components.getOrNull(2) ?: return@mapNotNull null
val x25519Key = components.getOrNull(3) ?: return@mapNotNull null
2020-07-08 09:05:26 +02:00
Snode(address, port, Snode.KeySet(ed25519Key, x25519Key))
}
2019-07-15 05:19:58 +02:00
}?.toSet()
2019-06-04 01:35:18 +02:00
}
2020-07-15 04:24:43 +02:00
override fun setSwarm(publicKey: String, newValue: Set<Snode>) {
2019-06-04 03:05:03 +02:00
val database = databaseHelper.writableDatabase
2019-06-19 07:45:40 +02:00
val swarmAsString = newValue.joinToString(", ") { target ->
var string = "${target.address}-${target.port}"
2020-01-28 00:18:18 +01:00
val keySet = target.publicKeySet
if (keySet != null) {
2020-04-09 05:38:15 +02:00
string += "-${keySet.ed25519Key}-${keySet.x25519Key}"
}
string
}
2020-08-12 02:00:35 +02:00
val row = wrap(mapOf( Companion.swarmPublicKey to publicKey, swarm to swarmAsString ))
2020-08-10 03:40:43 +02:00
database.insertOrUpdate(swarmTable, row, "${Companion.swarmPublicKey} = ?", wrap(publicKey))
2019-06-04 01:35:18 +02:00
}
2020-08-10 03:40:43 +02:00
override fun getLastMessageHashValue(snode: Snode, publicKey: String): String? {
2019-06-04 04:12:40 +02:00
val database = databaseHelper.readableDatabase
2020-08-10 03:40:43 +02:00
val query = "${Companion.snode} = ? AND ${Companion.publicKey} = ?"
2020-08-12 02:00:35 +02:00
return database.get(lastMessageHashValueTable2, query, arrayOf( snode.toString(), publicKey )) { cursor ->
2019-06-04 03:05:03 +02:00
cursor.getString(cursor.getColumnIndexOrThrow(lastMessageHashValue))
}
2019-06-04 01:35:18 +02:00
}
2020-08-10 03:40:43 +02:00
override fun setLastMessageHashValue(snode: Snode, publicKey: String, newValue: String) {
2019-06-04 03:05:03 +02:00
val database = databaseHelper.writableDatabase
2020-08-12 02:00:35 +02:00
val row = wrap(mapOf( Companion.snode to snode.toString(), Companion.publicKey to publicKey, lastMessageHashValue to newValue ))
2020-08-10 03:40:43 +02:00
val query = "${Companion.snode} = ? AND ${Companion.publicKey} = ?"
2020-08-12 02:00:35 +02:00
database.insertOrUpdate(lastMessageHashValueTable2, row, query, arrayOf( snode.toString(), publicKey ))
2019-06-04 01:35:18 +02:00
}
2020-08-10 03:40:43 +02:00
override fun getReceivedMessageHashValues(publicKey: String): Set<String>? {
2019-06-04 04:12:40 +02:00
val database = databaseHelper.readableDatabase
val query = "${Companion.publicKey} = ?"
2020-08-20 02:32:31 +02:00
return database.get(receivedMessageHashValuesTable3, query, arrayOf( publicKey )) { cursor ->
val receivedMessageHashValuesAsString = cursor.getString(cursor.getColumnIndexOrThrow(Companion.receivedMessageHashValues))
2020-08-12 02:00:35 +02:00
receivedMessageHashValuesAsString.split("-").toSet()
2019-06-04 03:05:03 +02:00
}
2019-06-04 01:35:18 +02:00
}
2020-08-10 03:40:43 +02:00
override fun setReceivedMessageHashValues(publicKey: String, newValue: Set<String>) {
2019-06-04 03:05:03 +02:00
val database = databaseHelper.writableDatabase
2020-08-12 02:00:35 +02:00
val receivedMessageHashValuesAsString = newValue.joinToString("-")
val row = wrap(mapOf( Companion.publicKey to publicKey, Companion.receivedMessageHashValues to receivedMessageHashValuesAsString ))
val query = "${Companion.publicKey} = ?"
2020-08-20 02:32:31 +02:00
database.insertOrUpdate(receivedMessageHashValuesTable3, row, query, arrayOf( publicKey ))
2019-06-04 01:35:18 +02:00
}
2019-08-23 08:57:26 +02:00
2019-10-07 06:30:20 +02:00
override fun getAuthToken(server: String): String? {
2019-08-23 08:57:26 +02:00
val database = databaseHelper.readableDatabase
2020-08-10 03:40:43 +02:00
return database.get(openGroupAuthTokenTable, "${Companion.server} = ?", wrap(server)) { cursor ->
2019-08-23 08:57:26 +02:00
cursor.getString(cursor.getColumnIndexOrThrow(token))
}
}
2019-10-07 06:30:20 +02:00
override fun setAuthToken(server: String, newValue: String?) {
2019-08-23 08:57:26 +02:00
val database = databaseHelper.writableDatabase
2019-08-26 05:55:45 +02:00
if (newValue != null) {
2020-08-12 02:00:35 +02:00
val row = wrap(mapOf( Companion.server to server, token to newValue ))
2020-08-10 03:40:43 +02:00
database.insertOrUpdate(openGroupAuthTokenTable, row, "${Companion.server} = ?", wrap(server))
2019-08-23 08:57:26 +02:00
} else {
2020-08-10 03:40:43 +02:00
database.delete(openGroupAuthTokenTable, "${Companion.server} = ?", wrap(server))
2019-08-23 08:57:26 +02:00
}
}
2019-08-26 05:55:45 +02:00
override fun getLastMessageServerID(room: String, server: String): Long? {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
return database.get(lastMessageServerIDTable, "$lastMessageServerIDTableIndex = ?", wrap(index)) { cursor ->
cursor.getInt(lastMessageServerID)
}?.toLong()
}
override fun setLastMessageServerID(room: String, server: String, newValue: Long) {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
val row = wrap(mapOf( lastMessageServerIDTableIndex to index, lastMessageServerID to newValue.toString() ))
database.insertOrUpdate(lastMessageServerIDTable, row, "$lastMessageServerIDTableIndex = ?", wrap(index))
}
fun removeLastMessageServerID(room: String, server:String) {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
database.delete(lastMessageServerIDTable, "$lastMessageServerIDTableIndex = ?", wrap(index))
}
override fun getLastDeletionServerID(room: String, server: String): Long? {
val database = databaseHelper.readableDatabase
val index = "$server.$room"
return database.get(lastDeletionServerIDTable, "$lastDeletionServerIDTableIndex = ?", wrap(index)) { cursor ->
cursor.getInt(lastDeletionServerID)
}?.toLong()
}
override fun setLastDeletionServerID(room: String, server: String, newValue: Long) {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
val row = wrap(mapOf(lastDeletionServerIDTableIndex to index, lastDeletionServerID to newValue.toString()))
database.insertOrUpdate(lastDeletionServerIDTable, row, "$lastDeletionServerIDTableIndex = ?", wrap(index))
}
fun removeLastDeletionServerID(room: String, server: String) {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
Merge remote-tracking branch 'upstream/dev' into open_groups_V2, working on compact poller implementation # Conflicts: # app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java # app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java # app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt # app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt # app/src/main/java/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt # app/src/main/java/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt # app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt # app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt # app/src/main/java/org/thoughtcrime/securesms/loki/utilities/MentionManagerUtilities.kt # app/src/main/java/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt # app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt # app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt # libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt # libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt # libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt # libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt # libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt # libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPIV2.kt # libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupMessageV2.kt # libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupV2.kt # libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt # libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt # libsession/src/main/java/org/session/libsession/messaging/utilities/DotNetAPI.kt # libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt # libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt # libsession/src/main/java/org/session/libsession/snode/SnodeMessage.kt # libsession/src/main/java/org/session/libsession/utilities/mentions/MentionsManager.kt # libsignal/src/main/java/org/session/libsignal/service/loki/api/SwarmAPI.kt # libsignal/src/main/java/org/session/libsignal/service/loki/api/opengroups/PublicChat.kt # libsignal/src/main/java/org/session/libsignal/service/loki/utilities/mentions/MentionsManager.kt
2021-04-28 09:41:30 +02:00
database.delete(lastDeletionServerIDTable, "$lastDeletionServerIDTableIndex = ?", wrap(index))
}
fun removeLastDeletionServerID(group: Long, server: String) {
val database = databaseHelper.writableDatabase
val index = "$server.$group"
2020-08-10 03:40:43 +02:00
database.delete(lastDeletionServerIDTable,"$lastDeletionServerIDTableIndex = ?", wrap(index))
2019-11-19 23:50:40 +01:00
}
2020-01-22 00:46:04 +01:00
fun getUserCount(group: Long, server: String): Int? {
val database = databaseHelper.readableDatabase
val index = "$server.$group"
2020-08-10 03:40:43 +02:00
return database.get(userCountTable, "$publicChatID = ?", wrap(index)) { cursor ->
2020-01-22 00:46:04 +01:00
cursor.getInt(userCount)
}?.toInt()
}
fun getUserCount(room: String, server: String): Int? {
val database = databaseHelper.readableDatabase
val index = "$server.$room"
return database.get(userCountTable, "$publicChatID = ?", wrap(index)) { cursor ->
cursor.getInt(userCount)
}?.toInt()
}
2020-07-29 01:04:24 +02:00
override fun setUserCount(group: Long, server: String, newValue: Int) {
2020-01-22 00:46:04 +01:00
val database = databaseHelper.writableDatabase
val index = "$server.$group"
2020-08-12 02:00:35 +02:00
val row = wrap(mapOf( publicChatID to index, Companion.userCount to newValue.toString() ))
2020-08-10 03:40:43 +02:00
database.insertOrUpdate(userCountTable, row, "$publicChatID = ?", wrap(index))
2020-01-22 00:46:04 +01:00
}
2020-05-22 02:41:31 +02:00
override fun setUserCount(room: String, server: String, newValue: Int) {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
val row = wrap(mapOf( publicChatID to index, userCount to newValue.toString() ))
database.insertOrUpdate(userCountTable, row, "$publicChatID = ?", wrap(index))
}
2020-07-29 01:04:24 +02:00
override fun getOpenGroupPublicKey(server: String): String? {
val database = databaseHelper.readableDatabase
2020-08-10 03:40:43 +02:00
return database.get(openGroupPublicKeyTable, "${LokiAPIDatabase.server} = ?", wrap(server)) { cursor ->
2020-07-29 01:04:24 +02:00
cursor.getString(LokiAPIDatabase.publicKey)
}
}
override fun setOpenGroupPublicKey(server: String, newValue: String) {
val database = databaseHelper.writableDatabase
2020-08-12 02:00:35 +02:00
val row = wrap(mapOf( LokiAPIDatabase.server to server, LokiAPIDatabase.publicKey to newValue ))
2020-08-10 03:40:43 +02:00
database.insertOrUpdate(openGroupPublicKeyTable, row, "${LokiAPIDatabase.server} = ?", wrap(server))
}
override fun getLastSnodePoolRefreshDate(): Date? {
val time = TextSecurePreferences.getLastSnodePoolRefreshDate(context)
if (time <= 0) { return null }
return Date(time)
}
override fun setLastSnodePoolRefreshDate(date: Date) {
TextSecurePreferences.setLastSnodePoolRefreshDate(context, date)
}
2021-01-13 06:13:49 +01:00
override fun getUserX25519KeyPair(): ECKeyPair {
val keyPair = IdentityKeyUtil.getIdentityKeyPair(context)
return ECKeyPair(DjbECPublicKey(keyPair.publicKey.serialize().removing05PrefixIfNeeded()), DjbECPrivateKey(keyPair.privateKey.serialize()))
}
fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String) {
val database = databaseHelper.writableDatabase
val timestamp = Date().time.toString()
val index = "$groupPublicKey-$timestamp"
val encryptionKeyPairPublicKey = encryptionKeyPair.publicKey.serialize().toHexString().removing05PrefixIfNeeded()
val encryptionKeyPairPrivateKey = encryptionKeyPair.privateKey.serialize().toHexString()
val row = wrap(mapOf(closedGroupsEncryptionKeyPairIndex to index, Companion.encryptionKeyPairPublicKey to encryptionKeyPairPublicKey,
2021-01-13 06:13:49 +01:00
Companion.encryptionKeyPairPrivateKey to encryptionKeyPairPrivateKey ))
database.insertOrUpdate(closedGroupEncryptionKeyPairsTable, row, "${Companion.closedGroupsEncryptionKeyPairIndex} = ?", wrap(index))
}
override fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): List<ECKeyPair> {
val database = databaseHelper.readableDatabase
val timestampsAndKeyPairs = database.getAll(closedGroupEncryptionKeyPairsTable, "${Companion.closedGroupsEncryptionKeyPairIndex} LIKE ?", wrap("$groupPublicKey%")) { cursor ->
val timestamp = cursor.getString(cursor.getColumnIndexOrThrow(Companion.closedGroupsEncryptionKeyPairIndex)).split("-").last()
val encryptionKeyPairPublicKey = cursor.getString(cursor.getColumnIndexOrThrow(Companion.encryptionKeyPairPublicKey))
val encryptionKeyPairPrivateKey = cursor.getString(cursor.getColumnIndexOrThrow(Companion.encryptionKeyPairPrivateKey))
val keyPair = ECKeyPair(DjbECPublicKey(Hex.fromStringCondensed(encryptionKeyPairPublicKey)), DjbECPrivateKey(Hex.fromStringCondensed(encryptionKeyPairPrivateKey)))
Pair(timestamp, keyPair)
}
return timestampsAndKeyPairs.sortedBy { it.first.toLong() }.map { it.second }
}
override fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair? {
return getClosedGroupEncryptionKeyPairs(groupPublicKey).lastOrNull()
}
fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String) {
val database = databaseHelper.writableDatabase
database.delete(closedGroupEncryptionKeyPairsTable, "${Companion.closedGroupsEncryptionKeyPairIndex} LIKE ?", wrap("$groupPublicKey%"))
}
fun addClosedGroupPublicKey(groupPublicKey: String) {
val database = databaseHelper.writableDatabase
val row = wrap(mapOf( Companion.groupPublicKey to groupPublicKey ))
database.insertOrUpdate(closedGroupPublicKeysTable, row, "${Companion.groupPublicKey} = ?", wrap(groupPublicKey))
}
fun getAllClosedGroupPublicKeys(): Set<String> {
val database = databaseHelper.readableDatabase
return database.getAll(closedGroupPublicKeysTable, null, null) { cursor ->
cursor.getString(cursor.getColumnIndexOrThrow(Companion.groupPublicKey))
}.toSet()
}
2021-02-18 04:14:05 +01:00
override fun isClosedGroup(groupPublicKey: String): Boolean {
if (!PublicKeyValidation.isValid(groupPublicKey)) { return false }
return getAllClosedGroupPublicKeys().contains(groupPublicKey)
}
2021-01-13 06:13:49 +01:00
fun removeClosedGroupPublicKey(groupPublicKey: String) {
val database = databaseHelper.writableDatabase
database.delete(closedGroupPublicKeysTable, "${Companion.groupPublicKey} = ?", wrap(groupPublicKey))
}
2019-06-04 03:05:03 +02:00
}
2019-06-04 04:12:40 +02:00
// region Convenience
2019-06-04 03:05:03 +02:00
private inline fun <reified T> wrap(x: T): Array<T> {
return Array(1) { x }
}
private fun wrap(x: Map<String, String>): ContentValues {
val result = ContentValues(x.size)
Add a global search (#834) * feat: modifying search functionalities to include contacts * feat: add global search UI input layouts and color attributes * feat: add global search repository and model content * feat: adding diff callbacks and wiring up global search vm to views * feat: adding scroll to message, figuring out new query for recipient thread search * feat: messing with the search and highlighting functionality after wiring up bindings * fix: compile error from merge * fix: gradlew build errors * feat: filtering contacts by existing un-archived threads * refactor: prevent note to self breaking, update queries and logic in search repo to include member->group reverse searches * feat: adding home screen new redesigns for search * feat: replacing designs and adding new group subtitle text * feat: small design improvements and incrementing gradle build number to install on device * feat: add scrollbars for search * feat: replace isVisible for cancel button now that GlobalSearchInputLayout.kt replaces header * refactor: all queries are debounced not just all but 2 char * refactor: remove visibility modifiers for cancel icon * refactor: use simplified non-db and context related models in display, remove db get group members call from binding data * fix: use threadId instead of group's address * refactor: better close on cancel, removing only yourself from group member list in open groups * refactor: seed view back to inflated on create and visibility for empty placeholder and seed view text * refactor: fixing build issues and new designs for message list * refactor: use dynamic limit * refactor: include raw session ID string search for non-empty threads * fix: build lint errors * fix: build issues * feat: add in path to the settings activity * refactor: remove wildcard imports
2022-02-07 07:06:27 +01:00
x.iterator().forEach { result.put(it.key, it.value) }
2019-06-04 03:05:03 +02:00
return result
}
// endregion