mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-11 17:27:42 +00:00
remove shared sender keys
This commit is contained in:
@@ -75,7 +75,6 @@ import org.thoughtcrime.securesms.loki.api.PublicChatManager;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase;
|
||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
|
||||
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
|
||||
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
|
||||
@@ -182,12 +181,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
|
||||
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
||||
SharedSenderKeysDatabase sskDatabase = DatabaseFactory.getSSKDatabase(this);
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||
SessionResetImplementation sessionResetImpl = new SessionResetImplementation(this);
|
||||
MessagingConfiguration.Companion.configure(this,
|
||||
DatabaseFactory.getStorage(this),
|
||||
sskDatabase,
|
||||
DatabaseFactory.getAttachmentProvider(this),
|
||||
new SessionProtocolImpl(this));
|
||||
if (userPublicKey != null) {
|
||||
@@ -507,8 +504,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
SharedSenderKeysDatabase sskDatabase = DatabaseFactory.getSSKDatabase(this);
|
||||
ClosedGroupPoller.Companion.configureIfNeeded(this, sskDatabase);
|
||||
ClosedGroupPoller.Companion.configureIfNeeded(this);
|
||||
closedGroupPoller = ClosedGroupPoller.Companion.getShared();
|
||||
}
|
||||
|
||||
|
@@ -1098,16 +1098,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
builder.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
Recipient groupRecipient = getRecipient();
|
||||
String groupPublicKey;
|
||||
boolean isSSKBasedClosedGroup;
|
||||
boolean isClosedGroup;
|
||||
try {
|
||||
groupPublicKey = HexEncodingKt.toHexString(GroupUtil.doubleDecodeGroupID(groupRecipient.getAddress().toString()));
|
||||
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(this).isSSKBasedClosedGroup(groupPublicKey);
|
||||
isClosedGroup = DatabaseFactory.getLokiAPIDatabase(this).isClosedGroup(groupPublicKey);
|
||||
} catch (IOException e) {
|
||||
groupPublicKey = null;
|
||||
isSSKBasedClosedGroup = false;
|
||||
isClosedGroup = false;
|
||||
}
|
||||
try {
|
||||
if (isSSKBasedClosedGroup) {
|
||||
if (isClosedGroup) {
|
||||
ClosedGroupsProtocolV2.explicitLeave(this, groupPublicKey);
|
||||
initializeEnabledCheck();
|
||||
} else {
|
||||
|
@@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionJobDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase;
|
||||
|
||||
public class DatabaseFactory {
|
||||
|
||||
@@ -67,7 +66,6 @@ public class DatabaseFactory {
|
||||
private final LokiThreadDatabase lokiThreadDatabase;
|
||||
private final LokiUserDatabase lokiUserDatabase;
|
||||
private final LokiBackupFilesDatabase lokiBackupFilesDatabase;
|
||||
private final SharedSenderKeysDatabase sskDatabase;
|
||||
private final SessionJobDatabase sessionJobDatabase;
|
||||
|
||||
// Refactor
|
||||
@@ -176,10 +174,6 @@ public class DatabaseFactory {
|
||||
return getInstance(context).lokiBackupFilesDatabase;
|
||||
}
|
||||
|
||||
public static SharedSenderKeysDatabase getSSKDatabase(Context context) {
|
||||
return getInstance(context).sskDatabase;
|
||||
}
|
||||
|
||||
public static SessionJobDatabase getSessionJobDatabase(Context context) {
|
||||
return getInstance(context).sessionJobDatabase;
|
||||
}
|
||||
@@ -229,7 +223,6 @@ public class DatabaseFactory {
|
||||
this.lokiThreadDatabase = new LokiThreadDatabase(context, databaseHelper);
|
||||
this.lokiUserDatabase = new LokiUserDatabase(context, databaseHelper);
|
||||
this.lokiBackupFilesDatabase = new LokiBackupFilesDatabase(context, databaseHelper);
|
||||
this.sskDatabase = new SharedSenderKeysDatabase(context, databaseHelper);
|
||||
this.storage = new Storage(context, databaseHelper);
|
||||
this.attachmentProvider = new DatabaseAttachmentProvider(context, databaseHelper);
|
||||
this.sessionJobDatabase = new SessionJobDatabase(context, databaseHelper);
|
||||
|
@@ -417,9 +417,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
}
|
||||
|
||||
override fun isClosedGroup(publicKey: String): Boolean {
|
||||
val isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(context).isSSKBasedClosedGroup(publicKey)
|
||||
val isClosedGroup = DatabaseFactory.getLokiAPIDatabase(context).isClosedGroup(publicKey)
|
||||
val address = Address.fromSerialized(publicKey)
|
||||
return address.isClosedGroup || isSSKBasedClosedGroup
|
||||
return address.isClosedGroup || isClosedGroup
|
||||
}
|
||||
|
||||
override fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList<ECKeyPair> {
|
||||
@@ -431,7 +431,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
}
|
||||
|
||||
override fun getAllClosedGroupPublicKeys(): Set<String> {
|
||||
return DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()
|
||||
return DatabaseFactory.getLokiAPIDatabase(context).getAllClosedGroupPublicKeys()
|
||||
}
|
||||
|
||||
override fun addClosedGroupPublicKey(groupPublicKey: String) {
|
||||
|
@@ -32,7 +32,6 @@ import org.thoughtcrime.securesms.loki.database.LokiBackupFilesDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase;
|
||||
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsMigration;
|
||||
|
||||
public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
@@ -131,9 +130,6 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand());
|
||||
db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand());
|
||||
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
|
||||
db.execSQL(SharedSenderKeysDatabase.getCreateOldClosedGroupRatchetTableCommand());
|
||||
db.execSQL(SharedSenderKeysDatabase.getCreateCurrentClosedGroupRatchetTableCommand());
|
||||
db.execSQL(SharedSenderKeysDatabase.getCreateClosedGroupPrivateKeyTableCommand());
|
||||
|
||||
executeStatements(db, SmsDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, MmsDatabase.CREATE_INDEXS);
|
||||
@@ -186,8 +182,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
if (oldVersion < lokiV12) {
|
||||
db.execSQL(LokiAPIDatabase.getCreateLastMessageHashValueTable2Command());
|
||||
db.execSQL(SharedSenderKeysDatabase.getCreateCurrentClosedGroupRatchetTableCommand());
|
||||
db.execSQL(SharedSenderKeysDatabase.getCreateClosedGroupPrivateKeyTableCommand());
|
||||
db.execSQL(ClosedGroupsMigration.getCreateCurrentClosedGroupRatchetTableCommand());
|
||||
db.execSQL(ClosedGroupsMigration.getCreateClosedGroupPrivateKeyTableCommand());
|
||||
}
|
||||
|
||||
if (oldVersion < lokiV13) {
|
||||
@@ -199,7 +195,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
if (oldVersion < lokiV15) {
|
||||
db.execSQL(SharedSenderKeysDatabase.getCreateOldClosedGroupRatchetTableCommand());
|
||||
db.execSQL(ClosedGroupsMigration.getCreateOldClosedGroupRatchetTableCommand());
|
||||
}
|
||||
|
||||
if (oldVersion < lokiV16) {
|
||||
|
@@ -98,7 +98,6 @@ public class SignalCommunicationModule {
|
||||
Optional.of(new MessageSenderEventListener(context)),
|
||||
TextSecurePreferences.getLocalNumber(context),
|
||||
DatabaseFactory.getLokiAPIDatabase(context),
|
||||
DatabaseFactory.getSSKDatabase(context),
|
||||
DatabaseFactory.getLokiThreadDatabase(context),
|
||||
DatabaseFactory.getLokiMessageDatabase(context),
|
||||
null, // DatabaseFactory.getLokiPreKeyBundleDatabase(context)
|
||||
|
@@ -248,7 +248,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context);
|
||||
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
|
||||
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(context);
|
||||
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, DatabaseFactory.getSSKDatabase(context), new SessionProtocolImpl(context), sessionResetProtocol, apiDB, UnidentifiedAccessUtil.getCertificateValidator());
|
||||
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, new SessionProtocolImpl(context), sessionResetProtocol, apiDB, UnidentifiedAccessUtil.getCertificateValidator());
|
||||
|
||||
SignalServiceContent content = cipher.decrypt(envelope);
|
||||
|
||||
|
@@ -246,21 +246,21 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
val admins = members.toSet() //TODO For now, consider all the users to be admins.
|
||||
|
||||
var isSSKBasedClosedGroup: Boolean
|
||||
var isClosedGroup: Boolean
|
||||
var groupPublicKey: String?
|
||||
try {
|
||||
groupPublicKey = GroupUtil.doubleDecodeGroupID(groupID).toHexString()
|
||||
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(this).isSSKBasedClosedGroup(groupPublicKey)
|
||||
isClosedGroup = DatabaseFactory.getLokiAPIDatabase(this).isClosedGroup(groupPublicKey)
|
||||
} catch (e: IOException) {
|
||||
groupPublicKey = null
|
||||
isSSKBasedClosedGroup = false
|
||||
isClosedGroup = false
|
||||
}
|
||||
|
||||
if (members.isEmpty()) {
|
||||
return Toast.makeText(this, R.string.activity_edit_closed_group_not_enough_group_members_error, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
val maxGroupMembers = if (isSSKBasedClosedGroup) ClosedGroupsProtocolV2.groupSizeLimit else legacyGroupSizeLimit
|
||||
val maxGroupMembers = if (isClosedGroup) ClosedGroupsProtocolV2.groupSizeLimit else legacyGroupSizeLimit
|
||||
if (members.size >= maxGroupMembers) {
|
||||
return Toast.makeText(this, R.string.activity_create_closed_group_too_many_group_members_error, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
@@ -273,7 +273,7 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
return Toast.makeText(this@EditClosedGroupActivity, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
if (isSSKBasedClosedGroup) {
|
||||
if (isClosedGroup) {
|
||||
isLoading = true
|
||||
loaderContainer.fadeIn()
|
||||
val promise: Promise<Any, Exception> = if (!members.contains(Recipient.from(this, Address.fromSerialized(userPublicKey), false))) {
|
||||
|
@@ -167,7 +167,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(this)
|
||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
||||
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
||||
val sskDatabase = DatabaseFactory.getSSKDatabase(this)
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
val sessionResetImpl = SessionResetImplementation(this)
|
||||
if (userPublicKey != null) {
|
||||
@@ -315,7 +314,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
val threadID = thread.threadId
|
||||
val recipient = thread.recipient
|
||||
val threadDB = DatabaseFactory.getThreadDatabase(this)
|
||||
val isClosedGroup = recipient.address.isClosedGroup
|
||||
val dialogMessage: String
|
||||
if (recipient.isGroupRecipient) {
|
||||
val group = DatabaseFactory.getGroupDatabase(this).getGroup(recipient.address.toString()).orNull()
|
||||
@@ -333,17 +331,17 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
val context = this@HomeActivity as Context
|
||||
|
||||
// Send a leave group message if this is an active closed group
|
||||
if (isClosedGroup && DatabaseFactory.getGroupDatabase(context).isActive(recipient.address.toGroupString())) {
|
||||
var isSSKBasedClosedGroup: Boolean
|
||||
if (recipient.address.isClosedGroup && DatabaseFactory.getGroupDatabase(context).isActive(recipient.address.toGroupString())) {
|
||||
var isClosedGroup: Boolean
|
||||
var groupPublicKey: String?
|
||||
try {
|
||||
groupPublicKey = GroupUtil.doubleDecodeGroupID(recipient.address.toString()).toHexString()
|
||||
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(context).isSSKBasedClosedGroup(groupPublicKey)
|
||||
isClosedGroup = DatabaseFactory.getLokiAPIDatabase(context).isClosedGroup(groupPublicKey)
|
||||
} catch (e: IOException) {
|
||||
groupPublicKey = null
|
||||
isSSKBasedClosedGroup = false
|
||||
isClosedGroup = false
|
||||
}
|
||||
if (isSSKBasedClosedGroup) {
|
||||
if (isClosedGroup) {
|
||||
ClosedGroupsProtocolV2.explicitLeave(context, groupPublicKey!!)
|
||||
} else {
|
||||
Toast.makeText(context, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show()
|
||||
|
@@ -76,8 +76,7 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
|
||||
promises.add(privateChatsPromise)
|
||||
|
||||
// Closed groups
|
||||
val sskDatabase = DatabaseFactory.getSSKDatabase(context)
|
||||
ClosedGroupPoller.configureIfNeeded(context, sskDatabase)
|
||||
ClosedGroupPoller.configureIfNeeded(context)
|
||||
promises.addAll(ClosedGroupPoller.shared.pollOnce())
|
||||
|
||||
// Open Groups
|
||||
|
@@ -7,14 +7,14 @@ import nl.komponents.kovenant.functional.bind
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob
|
||||
import org.session.libsignal.utilities.logging.Log
|
||||
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase
|
||||
import org.session.libsignal.utilities.successBackground
|
||||
import org.session.libsignal.service.api.messages.SignalServiceEnvelope
|
||||
import org.session.libsignal.service.loki.api.SnodeAPI
|
||||
import org.session.libsignal.service.loki.api.SwarmAPI
|
||||
import org.session.libsignal.service.loki.utilities.getRandomElementOrNull
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
|
||||
class ClosedGroupPoller private constructor(private val context: Context, private val database: SharedSenderKeysDatabase) {
|
||||
class ClosedGroupPoller private constructor(private val context: Context) {
|
||||
private var isPolling = false
|
||||
private val handler: Handler by lazy { Handler() }
|
||||
|
||||
@@ -32,9 +32,9 @@ class ClosedGroupPoller private constructor(private val context: Context, privat
|
||||
|
||||
public lateinit var shared: ClosedGroupPoller
|
||||
|
||||
public fun configureIfNeeded(context: Context, sskDatabase: SharedSenderKeysDatabase) {
|
||||
public fun configureIfNeeded(context: Context) {
|
||||
if (::shared.isInitialized) { return; }
|
||||
shared = ClosedGroupPoller(context, sskDatabase)
|
||||
shared = ClosedGroupPoller(context)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
@@ -66,7 +66,7 @@ class ClosedGroupPoller private constructor(private val context: Context, privat
|
||||
// region Private API
|
||||
private fun poll(): List<Promise<Unit, Exception>> {
|
||||
if (!isPolling) { return listOf() }
|
||||
val publicKeys = database.getAllClosedGroupPublicKeys()
|
||||
val publicKeys = DatabaseFactory.getLokiAPIDatabase(context).getAllClosedGroupPublicKeys()
|
||||
return publicKeys.map { publicKey ->
|
||||
val promise = SwarmAPI.shared.getSwarm(publicKey).bind { swarm ->
|
||||
val snode = swarm.getRandomElementOrNull() ?: throw InsufficientSnodesException() // Should be cryptographically secure
|
||||
|
@@ -53,7 +53,7 @@ object LokiPushNotificationManager {
|
||||
}
|
||||
}
|
||||
// Unsubscribe from all closed groups
|
||||
val allClosedGroupPublicKeys = DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()
|
||||
val allClosedGroupPublicKeys = DatabaseFactory.getLokiAPIDatabase(context).getAllClosedGroupPublicKeys()
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
||||
allClosedGroupPublicKeys.forEach { closedGroup ->
|
||||
performOperation(context, ClosedGroupOperation.Unsubscribe, closedGroup, userPublicKey)
|
||||
@@ -84,7 +84,7 @@ object LokiPushNotificationManager {
|
||||
}
|
||||
}
|
||||
// Subscribe to all closed groups
|
||||
val allClosedGroupPublicKeys = DatabaseFactory.getSSKDatabase(context).getAllClosedGroupPublicKeys()
|
||||
val allClosedGroupPublicKeys = DatabaseFactory.getLokiAPIDatabase(context).getAllClosedGroupPublicKeys()
|
||||
allClosedGroupPublicKeys.forEach { closedGroup ->
|
||||
performOperation(context, ClosedGroupOperation.Subscribe, closedGroup, publicKey)
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ import org.session.libsignal.service.loki.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.service.loki.utilities.PublicKeyValidation
|
||||
import java.util.*
|
||||
|
||||
class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiAPIDatabaseProtocol {
|
||||
@@ -454,6 +455,11 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
override fun isClosedGroup(groupPublicKey: String): Boolean {
|
||||
if (!PublicKeyValidation.isValid(groupPublicKey)) { return false }
|
||||
return getAllClosedGroupPublicKeys().contains(groupPublicKey)
|
||||
}
|
||||
|
||||
fun removeClosedGroupPublicKey(groupPublicKey: String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
database.delete(closedGroupPublicKeysTable, "${Companion.groupPublicKey} = ?", wrap(groupPublicKey))
|
||||
|
@@ -1,143 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.database
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.utilities.*
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupRatchet
|
||||
import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupRatchetCollectionType
|
||||
import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey
|
||||
import org.session.libsignal.service.loki.protocol.closedgroups.SharedSenderKeysDatabaseProtocol
|
||||
import org.session.libsignal.service.loki.utilities.PublicKeyValidation
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
|
||||
class SharedSenderKeysDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), SharedSenderKeysDatabaseProtocol {
|
||||
|
||||
companion object {
|
||||
// Shared
|
||||
public val closedGroupPublicKey = "closed_group_public_key"
|
||||
// Ratchets
|
||||
private val oldClosedGroupRatchetTable = "old_closed_group_ratchet_table"
|
||||
private val currentClosedGroupRatchetTable = "closed_group_ratchet_table"
|
||||
private val senderPublicKey = "sender_public_key"
|
||||
private val chainKey = "chain_key"
|
||||
private val keyIndex = "key_index"
|
||||
private val messageKeys = "message_keys"
|
||||
@JvmStatic val createOldClosedGroupRatchetTableCommand
|
||||
= "CREATE TABLE $oldClosedGroupRatchetTable ($closedGroupPublicKey STRING, $senderPublicKey STRING, $chainKey STRING, " +
|
||||
"$keyIndex INTEGER DEFAULT 0, $messageKeys TEXT, PRIMARY KEY ($closedGroupPublicKey, $senderPublicKey));"
|
||||
// Private keys
|
||||
@JvmStatic val createCurrentClosedGroupRatchetTableCommand
|
||||
= "CREATE TABLE $currentClosedGroupRatchetTable ($closedGroupPublicKey STRING, $senderPublicKey STRING, $chainKey STRING, " +
|
||||
"$keyIndex INTEGER DEFAULT 0, $messageKeys TEXT, PRIMARY KEY ($closedGroupPublicKey, $senderPublicKey));"
|
||||
// Private keys
|
||||
public val closedGroupPrivateKeyTable = "closed_group_private_key_table"
|
||||
public val closedGroupPrivateKey = "closed_group_private_key"
|
||||
@JvmStatic val createClosedGroupPrivateKeyTableCommand
|
||||
= "CREATE TABLE $closedGroupPrivateKeyTable ($closedGroupPublicKey STRING PRIMARY KEY, $closedGroupPrivateKey STRING);"
|
||||
}
|
||||
|
||||
private fun getTable(collection: ClosedGroupRatchetCollectionType): String {
|
||||
return when (collection) {
|
||||
ClosedGroupRatchetCollectionType.Old -> oldClosedGroupRatchetTable
|
||||
ClosedGroupRatchetCollectionType.Current -> currentClosedGroupRatchetTable
|
||||
}
|
||||
}
|
||||
|
||||
// region Ratchets & Sender Keys
|
||||
override fun getClosedGroupRatchet(groupPublicKey: String, senderPublicKey: String, collection: ClosedGroupRatchetCollectionType): ClosedGroupRatchet? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val query = "${Companion.closedGroupPublicKey} = ? AND ${Companion.senderPublicKey} = ?"
|
||||
return database.get(getTable(collection), query, arrayOf( groupPublicKey, senderPublicKey )) { cursor ->
|
||||
val chainKey = cursor.getString(Companion.chainKey)
|
||||
val keyIndex = cursor.getInt(Companion.keyIndex)
|
||||
val messageKeys = cursor.getString(Companion.messageKeys).split("-")
|
||||
ClosedGroupRatchet(chainKey, keyIndex, messageKeys)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setClosedGroupRatchet(groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, collection: ClosedGroupRatchetCollectionType) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val values = ContentValues()
|
||||
values.put(Companion.closedGroupPublicKey, groupPublicKey)
|
||||
values.put(Companion.senderPublicKey, senderPublicKey)
|
||||
values.put(Companion.chainKey, ratchet.chainKey)
|
||||
values.put(Companion.keyIndex, ratchet.keyIndex)
|
||||
values.put(Companion.messageKeys, ratchet.messageKeys.joinToString("-"))
|
||||
val query = "${Companion.closedGroupPublicKey} = ? AND ${Companion.senderPublicKey} = ?"
|
||||
database.insertOrUpdate(getTable(collection), values, query, arrayOf( groupPublicKey, senderPublicKey ))
|
||||
}
|
||||
|
||||
override fun removeAllClosedGroupRatchets(groupPublicKey: String, collection: ClosedGroupRatchetCollectionType) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val query = "${Companion.closedGroupPublicKey} = ?"
|
||||
database.delete(getTable(collection), query, arrayOf( groupPublicKey ))
|
||||
}
|
||||
|
||||
override fun getAllClosedGroupRatchets(groupPublicKey: String, collection: ClosedGroupRatchetCollectionType): Set<Pair<String, ClosedGroupRatchet>> {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val query = "${Companion.closedGroupPublicKey} = ?"
|
||||
return database.getAll(getTable(collection), query, arrayOf( groupPublicKey )) { cursor ->
|
||||
val chainKey = cursor.getString(Companion.chainKey)
|
||||
val keyIndex = cursor.getInt(Companion.keyIndex)
|
||||
val messageKeys = cursor.getString(Companion.messageKeys).split("-")
|
||||
val senderPublicKey = cursor.getString(Companion.senderPublicKey)
|
||||
val ratchet = ClosedGroupRatchet(chainKey, keyIndex, messageKeys)
|
||||
Pair(senderPublicKey, ratchet)
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
override fun getAllClosedGroupSenderKeys(groupPublicKey: String, collection: ClosedGroupRatchetCollectionType): Set<ClosedGroupSenderKey> {
|
||||
return getAllClosedGroupRatchets(groupPublicKey, collection).map { pair ->
|
||||
val senderPublicKey = pair.first
|
||||
val ratchet = pair.second
|
||||
ClosedGroupSenderKey(Hex.fromStringCondensed(ratchet.chainKey), ratchet.keyIndex, Hex.fromStringCondensed(senderPublicKey))
|
||||
}.toSet()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Public & Private Keys
|
||||
override fun getClosedGroupPrivateKey(groupPublicKey: String): String? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val query = "${Companion.closedGroupPublicKey} = ?"
|
||||
return database.get(closedGroupPrivateKeyTable, query, arrayOf( groupPublicKey )) { cursor ->
|
||||
cursor.getString(Companion.closedGroupPrivateKey)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setClosedGroupPrivateKey(groupPublicKey: String, groupPrivateKey: String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val values = ContentValues()
|
||||
values.put(Companion.closedGroupPublicKey, groupPublicKey)
|
||||
values.put(Companion.closedGroupPrivateKey, groupPrivateKey)
|
||||
val query = "${Companion.closedGroupPublicKey} = ?"
|
||||
database.insertOrUpdate(closedGroupPrivateKeyTable, values, query, arrayOf( groupPublicKey ))
|
||||
}
|
||||
|
||||
override fun removeClosedGroupPrivateKey(groupPublicKey: String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val query = "${Companion.closedGroupPublicKey} = ?"
|
||||
database.delete(closedGroupPrivateKeyTable, query, arrayOf( groupPublicKey ))
|
||||
}
|
||||
|
||||
override fun getAllClosedGroupPublicKeys(): Set<String> {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val result = mutableSetOf<String>()
|
||||
result.addAll(database.getAll(closedGroupPrivateKeyTable, null, null) { cursor ->
|
||||
cursor.getString(Companion.closedGroupPublicKey)
|
||||
}.filter {
|
||||
PublicKeyValidation.isValid(it)
|
||||
})
|
||||
result.addAll(DatabaseFactory.getLokiAPIDatabase(context).getAllClosedGroupPublicKeys())
|
||||
return result
|
||||
}
|
||||
// endregion
|
||||
|
||||
override fun isSSKBasedClosedGroup(groupPublicKey: String): Boolean {
|
||||
if (!PublicKeyValidation.isValid(groupPublicKey)) { return false }
|
||||
return getAllClosedGroupPublicKeys().contains(groupPublicKey)
|
||||
}
|
||||
// endregion
|
||||
}
|
@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.loki.protocol
|
||||
|
||||
import android.content.ContentValues
|
||||
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase
|
||||
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase
|
||||
import org.thoughtcrime.securesms.loki.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.utilities.getAll
|
||||
import org.thoughtcrime.securesms.loki.utilities.getString
|
||||
@@ -18,17 +17,39 @@ import java.util.*
|
||||
|
||||
object ClosedGroupsMigration {
|
||||
|
||||
fun perform(database: net.sqlcipher.database.SQLiteDatabase) {
|
||||
val publicKeys = database.getAll(SharedSenderKeysDatabase.closedGroupPrivateKeyTable, null, null) { cursor ->
|
||||
cursor.getString(SharedSenderKeysDatabase.closedGroupPublicKey)
|
||||
public val closedGroupPublicKey = "closed_group_public_key"
|
||||
// Ratchets
|
||||
private val oldClosedGroupRatchetTable = "old_closed_group_ratchet_table"
|
||||
private val currentClosedGroupRatchetTable = "closed_group_ratchet_table"
|
||||
private val senderPublicKey = "sender_public_key"
|
||||
private val chainKey = "chain_key"
|
||||
private val keyIndex = "key_index"
|
||||
private val messageKeys = "message_keys"
|
||||
@JvmStatic val createOldClosedGroupRatchetTableCommand
|
||||
= "CREATE TABLE $oldClosedGroupRatchetTable ($closedGroupPublicKey STRING, $senderPublicKey STRING, $chainKey STRING, " +
|
||||
"$keyIndex INTEGER DEFAULT 0, $messageKeys TEXT, PRIMARY KEY ($closedGroupPublicKey, $senderPublicKey));"
|
||||
// Private keys
|
||||
@JvmStatic val createCurrentClosedGroupRatchetTableCommand
|
||||
= "CREATE TABLE $currentClosedGroupRatchetTable ($closedGroupPublicKey STRING, $senderPublicKey STRING, $chainKey STRING, " +
|
||||
"$keyIndex INTEGER DEFAULT 0, $messageKeys TEXT, PRIMARY KEY ($closedGroupPublicKey, $senderPublicKey));"
|
||||
// Private keys
|
||||
public val closedGroupPrivateKeyTable = "closed_group_private_key_table"
|
||||
public val closedGroupPrivateKey = "closed_group_private_key"
|
||||
@JvmStatic val createClosedGroupPrivateKeyTableCommand
|
||||
= "CREATE TABLE $closedGroupPrivateKeyTable ($closedGroupPublicKey STRING PRIMARY KEY, $closedGroupPrivateKey STRING);"
|
||||
|
||||
|
||||
fun perform(database: net.sqlcipher.database.SQLiteDatabase) {
|
||||
val publicKeys = database.getAll(closedGroupPrivateKeyTable, null, null) { cursor ->
|
||||
cursor.getString(closedGroupPublicKey)
|
||||
}.filter {
|
||||
PublicKeyValidation.isValid(it)
|
||||
}
|
||||
val keyPairs = mutableListOf<ECKeyPair>()
|
||||
for (publicKey in publicKeys) {
|
||||
val query = "${SharedSenderKeysDatabase.closedGroupPublicKey} = ?"
|
||||
val privateKey = database.get(SharedSenderKeysDatabase.closedGroupPrivateKeyTable, query, arrayOf( publicKey )) { cursor ->
|
||||
cursor.getString(SharedSenderKeysDatabase.closedGroupPrivateKey)
|
||||
val query = "${closedGroupPublicKey} = ?"
|
||||
val privateKey = database.get(closedGroupPrivateKeyTable, query, arrayOf( publicKey )) { cursor ->
|
||||
cursor.getString(closedGroupPrivateKey)
|
||||
}
|
||||
val keyPair = ECKeyPair(DjbECPublicKey(Hex.fromStringCondensed(publicKey.removing05PrefixIfNeeded())), DjbECPrivateKey(Hex.fromStringCondensed(privateKey)))
|
||||
keyPairs.add(keyPair)
|
||||
|
Reference in New Issue
Block a user