From d51c62ecaf4b3d2379070e1a2a5042a0954c4c3d Mon Sep 17 00:00:00 2001 From: Mikunj Varsani Date: Tue, 24 Sep 2019 13:33:42 +1000 Subject: [PATCH] Moved LokiMultiDeviceDatabase into LokiAPIDatabase. --- .../securesms/ApplicationContext.java | 6 +- .../securesms/database/DatabaseFactory.java | 6 -- .../database/helpers/SQLCipherOpenHelper.java | 4 +- .../securesms/jobs/PushDecryptJob.java | 6 +- .../securesms/loki/DatabaseUtilities.kt | 17 ++++ .../securesms/loki/LokiAPIDatabase.kt | 36 ++++++++ .../securesms/loki/LokiMultiDeviceDatabase.kt | 83 ------------------- 7 files changed, 63 insertions(+), 95 deletions(-) delete mode 100644 src/org/thoughtcrime/securesms/loki/LokiMultiDeviceDatabase.kt diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 9cdc9f07f5..007058f5fd 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -36,6 +36,7 @@ import org.jetbrains.annotations.NotNull; import org.signal.aesgcmprovider.AesGcmProvider; import org.thoughtcrime.securesms.components.TypingStatusRepository; import org.thoughtcrime.securesms.components.TypingStatusSender; +import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.database.DatabaseContentProviders; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule; @@ -411,7 +412,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // region Loki public void setUpStorageAPI() { - LokiStorageAPI.Companion.configure(DatabaseFactory.getLokiMultiDeviceDatabase(this)); + String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this); + byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); + LokiAPIDatabaseProtocol database = DatabaseFactory.getLokiAPIDatabase(this); + LokiStorageAPI.Companion.configure(userHexEncodedPublicKey, userPrivateKey, database); } public void setUpP2PAPI() { diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index f5e376db73..f6a54ece79 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -63,7 +63,6 @@ public class DatabaseFactory { // Loki private final LokiAPIDatabase lokiAPIDatabase; - private final LokiMultiDeviceDatabase lokiMultiDeviceDatabase; private final LokiPreKeyRecordDatabase lokiContactPreKeyDatabase; private final LokiPreKeyBundleDatabase lokiPreKeyBundleDatabase; private final LokiMessageDatabase lokiMessageDatabase; @@ -164,10 +163,6 @@ public class DatabaseFactory { return getInstance(context).lokiAPIDatabase; } - public static LokiMultiDeviceDatabase getLokiMultiDeviceDatabase(Context context) { - return getInstance(context).lokiMultiDeviceDatabase; - } - public static LokiPreKeyRecordDatabase getLokiPreKeyRecordDatabase(Context context) { return getInstance(context).lokiContactPreKeyDatabase; } @@ -221,7 +216,6 @@ public class DatabaseFactory { this.jobDatabase = new JobDatabase(context, databaseHelper); this.stickerDatabase = new StickerDatabase(context, databaseHelper, attachmentSecret); this.lokiAPIDatabase = new LokiAPIDatabase(context, databaseHelper); - this.lokiMultiDeviceDatabase = new LokiMultiDeviceDatabase(context, databaseHelper); this.lokiContactPreKeyDatabase = new LokiPreKeyRecordDatabase(context, databaseHelper); this.lokiPreKeyBundleDatabase = new LokiPreKeyBundleDatabase(context, databaseHelper); this.lokiMessageDatabase = new LokiMessageDatabase(context, databaseHelper); diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index cb1d0bbb2f..d30ae74dfd 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -125,6 +125,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateGroupChatAuthTokenTableCommand()); db.execSQL(LokiAPIDatabase.getCreateLastMessageServerIDTableCommand()); db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand()); + db.execSQL(LokiAPIDatabase.getCreateMultiDeviceAuthTableCommand()); db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand()); db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand()); db.execSQL(LokiMessageDatabase.getCreateTableCommand()); @@ -132,7 +133,6 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand()); db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand()); db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand()); - db.execSQL(LokiMultiDeviceDatabase.getCreateTableCommand()); executeStatements(db, SmsDatabase.CREATE_INDEXS); executeStatements(db, MmsDatabase.CREATE_INDEXS); @@ -496,7 +496,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { } if (oldVersion < lokiV3) { - db.execSQL(LokiMultiDeviceDatabase.getCreateTableCommand()); + db.execSQL(LokiAPIDatabase.getCreateMultiDeviceAuthTableCommand()); } db.setTransactionSuccessful(); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 3a08ad14a2..67637703e4 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -1046,7 +1046,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { LokiDeviceLinkingSession linkingSession = LokiDeviceLinkingSession.Companion.getShared(); if (valid && linkingSession.isListeningForLinkingRequest()) { // Save to the database and trigger the event - DatabaseFactory.getLokiMultiDeviceDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); + DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); linkingSession.receivedLinkingRequest(authorisation); } else { // Remove pre key bundle from the user @@ -1070,7 +1070,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // Set the current device as secondary Log.d("Loki", "Receiving pairing authorisation from: " + authorisation.getPrimaryDevicePubKey()); - DatabaseFactory.getLokiMultiDeviceDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); + DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); TextSecurePreferences.setIsSecondaryDevice(context, true); // TODO: Trigger an event here? @@ -1093,7 +1093,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { LokiThreadFriendRequestStatus threadFriendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID); if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS) { // If we're friends then save and send a background message if needed for friend request accept - DatabaseFactory.getLokiMultiDeviceDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); + DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); sendBackgroundMessage(authorisation.getSecondaryDevicePubKey()); } } diff --git a/src/org/thoughtcrime/securesms/loki/DatabaseUtilities.kt b/src/org/thoughtcrime/securesms/loki/DatabaseUtilities.kt index e488ca5144..32edff8401 100644 --- a/src/org/thoughtcrime/securesms/loki/DatabaseUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/DatabaseUtilities.kt @@ -18,6 +18,23 @@ fun SQLiteDatabase.get(table: String, query: String, arguments: Array SQLiteDatabase.getAll(table: String, query: String, arguments: Array, get: (Cursor) -> T): List { + var list = mutableListOf() + var cursor: Cursor? = null + try { + cursor = query(table, null, query, arguments, null, null, null) + while (cursor != null && cursor.moveToNext()) { + list.add(get(cursor)) + } + return list + } catch (e: Exception) { + // Do nothing + } finally { + cursor?.close() + } + return listOf() +} + fun SQLiteDatabase.insertOrUpdate(table: String, values: ContentValues, query: String, arguments: Array) { val id = insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE).toInt() if (id == -1) { diff --git a/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt index 862d68b0ce..39f45ebbe0 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt @@ -4,9 +4,11 @@ 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.util.Base64 import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol import org.whispersystems.signalservice.loki.api.LokiAPITarget +import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation // TODO: Clean this up a bit @@ -45,6 +47,14 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( private val lastDeletionServerIDCacheIndex = "loki_api_last_deletion_server_id_cache_index" private val lastDeletionServerID = "last_deletion_server_id" @JvmStatic val createLastDeletionServerIDTableCommand = "CREATE TABLE $lastDeletionServerIDCache ($lastDeletionServerIDCacheIndex STRING PRIMARY KEY, $lastDeletionServerID INTEGER DEFAULT 0);" + + // Authorisation + private val multiDeviceAuthTable = "loki_multi_device_authorisation" + private val primaryDevice = "primary_device" + private val secondaryDevice = "secondary_device" + private val requestSignature = "request_signature" + private val grantSignature = "grant_signature" + @JvmStatic val createMultiDeviceAuthTableCommand = "CREATE TABLE $multiDeviceAuthTable(_id INTEGER PRIMARY KEY AUTOINCREMENT, $primaryDevice TEXT, $secondaryDevice TEXT, $requestSignature TEXT NULLABLE DEFAULT NULL, $grantSignature TEXT NULLABLE DEFAULT NULL);" } override fun getSwarmCache(hexEncodedPublicKey: String): Set? { @@ -141,6 +151,32 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( val row = wrap(mapOf( lastDeletionServerIDCacheIndex to index, lastDeletionServerID to newValue.toString() )) database.insertOrUpdate(lastDeletionServerIDCache, row, "$lastDeletionServerIDCacheIndex = ?", wrap(index)) } + + override fun getPairingAuthorisations(pubKey: String): List { + val database = databaseHelper.readableDatabase + return database.getAll(multiDeviceAuthTable, "$primaryDevice = ? OR $secondaryDevice = ?", arrayOf(pubKey)) { cursor -> + val primaryDevicePubKey = cursor.getString(primaryDevice) + val secondaryDevicePubKey = cursor.getString(secondaryDevice) + val requestSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(requestSignature))) null else cursor.getBase64EncodedData(requestSignature) + val grantSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(grantSignature))) null else cursor.getBase64EncodedData(grantSignature) + LokiPairingAuthorisation(primaryDevicePubKey, secondaryDevicePubKey, requestSignature, grantSignature) + } + } + + override fun insertOrUpdatePairingAuthorisation(authorisation: LokiPairingAuthorisation) { + val database = databaseHelper.writableDatabase + val values = ContentValues() + values.put(primaryDevice, authorisation.primaryDevicePubKey) + values.put(secondaryDevice, authorisation.secondaryDevicePubKey) + if (authorisation.requestSignature != null) { values.put(requestSignature, Base64.encodeBytes(authorisation.requestSignature)) } + if (authorisation.grantSignature != null) { values.put(grantSignature, Base64.encodeBytes(authorisation.grantSignature)) } + database.insertOrUpdate(multiDeviceAuthTable, values, "$primaryDevice = ? AND $secondaryDevice = ?", arrayOf(authorisation.primaryDevicePubKey, authorisation.secondaryDevicePubKey)) + } + + override fun removePairingAuthorisations(pubKey: String) { + val database = databaseHelper.readableDatabase + database.delete(multiDeviceAuthTable, "$primaryDevice = ? OR $secondaryDevice = ?", arrayOf(pubKey)) + } } // region Convenience diff --git a/src/org/thoughtcrime/securesms/loki/LokiMultiDeviceDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiMultiDeviceDatabase.kt deleted file mode 100644 index 7c11166308..0000000000 --- a/src/org/thoughtcrime/securesms/loki/LokiMultiDeviceDatabase.kt +++ /dev/null @@ -1,83 +0,0 @@ -package org.thoughtcrime.securesms.loki - -import android.content.ContentValues -import android.content.Context -import net.sqlcipher.Cursor -import org.thoughtcrime.securesms.database.Database -import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper -import org.thoughtcrime.securesms.util.Base64 -import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation -import org.whispersystems.signalservice.loki.api.LokiStorageAPIDatabaseProtocol -import java.util.* - -class LokiMultiDeviceDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiStorageAPIDatabaseProtocol { - - companion object { - // Authorisation - private val authorisation_table = "loki_multi_device_authorisation" - private val primaryDevice = "primary_device" - private val secondaryDevice = "secondary_device" - private val requestSignature = "request_signature" - private val grantSignature = "grant_signature" - @JvmStatic - val createTableCommand = "CREATE TABLE $authorisation_table(_id INTEGER PRIMARY KEY AUTOINCREMENT," + - "$primaryDevice TEXT," + - "$secondaryDevice TEXT," + - "$requestSignature TEXT NULLABLE" + - "$grantSignature TEXT NULLABLE" + - ");" - } - - override fun insertOrUpdatePairingAuthorisation(authorisation: LokiPairingAuthorisation) { - val database = databaseHelper.writableDatabase - val values = ContentValues() - values.put(primaryDevice, authorisation.primaryDevicePubKey) - values.put(secondaryDevice, authorisation.secondaryDevicePubKey) - if (authorisation.requestSignature != null) { values.put(requestSignature, Base64.encodeBytes(authorisation.requestSignature)) } - if (authorisation.grantSignature != null) { values.put(grantSignature, Base64.encodeBytes(authorisation.grantSignature)) } - database.insertOrUpdate(authorisation_table, values, "$primaryDevice = ? AND $secondaryDevice = ?", arrayOf(authorisation.primaryDevicePubKey, authorisation.secondaryDevicePubKey)) - } - - override fun removePairingAuthorisations(pubKey: String) { - val database = databaseHelper.readableDatabase - database.delete(authorisation_table, "$primaryDevice = ? OR $secondaryDevice = ?", arrayOf(pubKey, pubKey)) - } - - fun getAuthorisationForSecondaryDevice(pubKey: String): LokiPairingAuthorisation? { - val database = databaseHelper.readableDatabase - return database.get(authorisation_table, "$secondaryDevice = ?", arrayOf(pubKey)) { cursor -> - val primaryDevicePubKey = cursor.getString(primaryDevice) - val secondaryDevicePubKey = cursor.getString(secondaryDevice) - val requestSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(requestSignature))) null else cursor.getBase64EncodedData(requestSignature) - val grantSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(grantSignature))) null else cursor.getBase64EncodedData(grantSignature) - LokiPairingAuthorisation(primaryDevicePubKey, secondaryDevicePubKey, requestSignature, grantSignature) - } - } - - override fun getSecondaryDevices(primaryDevicePubKey: String): List { - val database = databaseHelper.readableDatabase - - var cursor: Cursor? = null - val results = LinkedList() - - try { - cursor = database.query(authorisation_table, arrayOf(secondaryDevice), "$primaryDevice = ?", arrayOf(primaryDevicePubKey), null, null, null) - if (cursor != null && cursor.moveToNext()) { - results.add(cursor.getString(secondaryDevice)) - } - } catch (e: Exception) { - // Do nothing - } finally { - cursor?.close() - } - - return results - } - - override fun getPrimaryDevice(secondaryDevicePubKey: String): String? { - val database = databaseHelper.readableDatabase - return database.get(authorisation_table, "$secondaryDevice = ?", arrayOf(secondaryDevicePubKey)) { cursor -> - cursor.getString(primaryDevice) - } - } -} \ No newline at end of file