session-android/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java

355 lines
14 KiB
Java
Raw Normal View History

package org.thoughtcrime.securesms.database.helpers;
import android.content.Context;
import android.database.Cursor;
2020-08-20 02:32:31 +02:00
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;
import net.sqlcipher.database.SQLiteOpenHelper;
import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DraftDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
2019-06-18 01:57:36 +02:00
import org.thoughtcrime.securesms.database.JobDatabase;
2021-07-09 05:25:57 +02:00
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.database.LokiBackupFilesDatabase;
import org.thoughtcrime.securesms.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.database.LokiUserDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.PushDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.SearchDatabase;
2021-07-09 05:25:57 +02:00
import org.thoughtcrime.securesms.database.SessionContactDatabase;
import org.thoughtcrime.securesms.database.SessionJobDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
public class SQLCipherOpenHelper extends SQLiteOpenHelper {
@SuppressWarnings("unused")
private static final String TAG = SQLCipherOpenHelper.class.getSimpleName();
// First public release (1.0.0) DB version was 27.
// So we have to keep the migrations onwards.
2020-03-05 04:07:42 +01:00
private static final int lokiV7 = 28;
2020-05-22 02:41:31 +02:00
private static final int lokiV8 = 29;
2020-05-29 04:01:43 +02:00
private static final int lokiV9 = 30;
2020-07-16 01:44:00 +02:00
private static final int lokiV10 = 31;
2020-07-29 01:04:24 +02:00
private static final int lokiV11 = 32;
2020-08-06 08:32:14 +02:00
private static final int lokiV12 = 33;
2020-08-20 02:32:31 +02:00
private static final int lokiV13 = 34;
private static final int lokiV14_BACKUP_FILES = 35;
2020-10-19 00:27:34 +02:00
private static final int lokiV15 = 36;
2020-10-28 05:04:47 +01:00
private static final int lokiV16 = 37;
2020-10-28 06:06:48 +01:00
private static final int lokiV17 = 38;
private static final int lokiV18_CLEAR_BG_POLL_JOBS = 39;
2021-01-13 06:13:49 +01:00
private static final int lokiV19 = 40;
2021-02-17 01:30:37 +01:00
private static final int lokiV20 = 41;
private static final int lokiV21 = 42;
2021-03-02 02:24:09 +01:00
private static final int lokiV22 = 43;
private static final int lokiV23 = 44;
2021-05-06 07:46:22 +02:00
private static final int lokiV24 = 45;
2021-05-07 08:31:46 +02:00
private static final int lokiV25 = 46;
2021-05-21 07:21:24 +02:00
private static final int lokiV26 = 47;
private static final int lokiV27 = 48;
2021-01-13 06:13:49 +01:00
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
private static final int DATABASE_VERSION = lokiV27;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
private final DatabaseSecret databaseSecret;
public SQLCipherOpenHelper(@NonNull Context context, @NonNull DatabaseSecret databaseSecret) {
super(context, DATABASE_NAME, null, DATABASE_VERSION, new SQLiteDatabaseHook() {
@Override
public void preKey(SQLiteDatabase db) {
db.rawExecSQL("PRAGMA cipher_default_kdf_iter = 1;");
db.rawExecSQL("PRAGMA cipher_default_page_size = 4096;");
}
@Override
public void postKey(SQLiteDatabase db) {
db.rawExecSQL("PRAGMA kdf_iter = '1';");
db.rawExecSQL("PRAGMA cipher_page_size = 4096;");
}
});
this.context = context.getApplicationContext();
this.databaseSecret = databaseSecret;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SmsDatabase.CREATE_TABLE);
db.execSQL(MmsDatabase.CREATE_TABLE);
db.execSQL(AttachmentDatabase.CREATE_TABLE);
db.execSQL(ThreadDatabase.CREATE_TABLE);
db.execSQL(DraftDatabase.CREATE_TABLE);
db.execSQL(PushDatabase.CREATE_TABLE);
db.execSQL(GroupDatabase.CREATE_TABLE);
db.execSQL(RecipientDatabase.CREATE_TABLE);
db.execSQL(GroupReceiptDatabase.CREATE_TABLE);
for (String sql : SearchDatabase.CREATE_TABLE) {
db.execSQL(sql);
}
2019-03-28 16:56:35 +01:00
for (String sql : JobDatabase.CREATE_TABLE) {
db.execSQL(sql);
}
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateSnodePoolTableCommand());
db.execSQL(LokiAPIDatabase.getCreateOnionRequestPathTableCommand());
db.execSQL(LokiAPIDatabase.getCreateSwarmTableCommand());
db.execSQL(LokiAPIDatabase.getCreateLastMessageHashValueTable2Command());
2020-08-20 02:32:31 +02:00
db.execSQL(LokiAPIDatabase.getCreateReceivedMessageHashValuesTable3Command());
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateOpenGroupAuthTokenTableCommand());
db.execSQL(LokiAPIDatabase.getCreateLastMessageServerIDTableCommand());
db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand());
2020-06-01 02:33:47 +02:00
db.execSQL(LokiAPIDatabase.getCreateDeviceLinkCacheCommand());
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateUserCountTableCommand());
2020-06-01 02:33:47 +02:00
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampTableCommand());
db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampTableCommand());
db.execSQL(LokiAPIDatabase.getCreateOpenGroupPublicKeyTableCommand());
2020-10-19 06:12:06 +02:00
db.execSQL(LokiAPIDatabase.getCreateOpenGroupProfilePictureTableCommand());
2021-01-13 06:13:49 +01:00
db.execSQL(LokiAPIDatabase.getCreateClosedGroupEncryptionKeyPairsTable());
db.execSQL(LokiAPIDatabase.getCreateClosedGroupPublicKeysTable());
2020-07-15 06:26:20 +02:00
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand());
2020-03-05 04:07:42 +01:00
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
2019-07-22 01:38:12 +02:00
db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand());
db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand());
2021-05-24 03:35:05 +02:00
db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand());
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
2021-03-02 02:24:09 +01:00
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
db.execSQL(LokiMessageDatabase.getUpdateMessageIDTableForType());
db.execSQL(LokiMessageDatabase.getUpdateMessageMappingTable());
2021-05-07 08:31:46 +02:00
db.execSQL(SessionContactDatabase.getCreateSessionContactTableCommand());
db.execSQL(RecipientDatabase.getCreateNotificationTypeCommand());
executeStatements(db, SmsDatabase.CREATE_INDEXS);
executeStatements(db, MmsDatabase.CREATE_INDEXS);
executeStatements(db, AttachmentDatabase.CREATE_INDEXS);
executeStatements(db, ThreadDatabase.CREATE_INDEXS);
executeStatements(db, DraftDatabase.CREATE_INDEXS);
executeStatements(db, GroupDatabase.CREATE_INDEXS);
executeStatements(db, GroupReceiptDatabase.CREATE_INDEXES);
}
@Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
2020-05-11 08:54:31 +02:00
// Loki - Enable write ahead logging mode and increase the cache size.
// This should be disabled if we ever run into serious race condition bugs.
db.enableWriteAheadLogging();
db.execSQL("PRAGMA cache_size = 10000");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
2018-08-02 15:25:33 +02:00
Log.i(TAG, "Upgrading database: " + oldVersion + ", " + newVersion);
2018-02-16 05:33:10 +01:00
db.beginTransaction();
try {
2020-03-05 04:07:42 +01:00
if (oldVersion < lokiV7) {
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
}
2020-05-22 02:41:31 +02:00
if (oldVersion < lokiV8) {
2020-06-01 02:33:47 +02:00
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
2020-05-22 02:41:31 +02:00
}
2020-05-29 04:01:43 +02:00
if (oldVersion < lokiV9) {
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateSnodePoolTableCommand());
db.execSQL(LokiAPIDatabase.getCreateOnionRequestPathTableCommand());
2020-05-29 04:01:43 +02:00
}
2020-07-16 01:44:00 +02:00
if (oldVersion < lokiV10) {
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampTableCommand());
db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampTableCommand());
2020-07-16 01:44:00 +02:00
}
2020-07-29 01:04:24 +02:00
if (oldVersion < lokiV11) {
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateOpenGroupPublicKeyTableCommand());
2020-07-29 01:04:24 +02:00
}
2020-08-06 08:32:14 +02:00
if (oldVersion < lokiV12) {
2020-08-10 03:40:43 +02:00
db.execSQL(LokiAPIDatabase.getCreateLastMessageHashValueTable2Command());
2020-08-06 08:32:14 +02:00
}
2020-08-20 02:32:31 +02:00
if (oldVersion < lokiV13) {
db.execSQL(LokiAPIDatabase.getCreateReceivedMessageHashValuesTable3Command());
}
if (oldVersion < lokiV14_BACKUP_FILES) {
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
}
2020-10-28 05:04:47 +01:00
if (oldVersion < lokiV16) {
db.execSQL(LokiAPIDatabase.getCreateOpenGroupProfilePictureTableCommand());
}
2020-10-28 06:06:48 +01:00
if (oldVersion < lokiV17) {
2020-10-28 05:29:12 +01:00
db.execSQL("ALTER TABLE part ADD COLUMN audio_visual_samples BLOB");
db.execSQL("ALTER TABLE part ADD COLUMN audio_duration INTEGER");
}
if (oldVersion < lokiV18_CLEAR_BG_POLL_JOBS) {
// BackgroundPollJob was replaced with BackgroundPollWorker. Clear all the scheduled job records.
db.execSQL("DELETE FROM job_spec WHERE factory_key = 'BackgroundPollJob'");
db.execSQL("DELETE FROM constraint_spec WHERE factory_key = 'BackgroundPollJob'");
}
// Many classes were removed. We need to update DB structure and data to match the code changes.
2021-01-13 06:13:49 +01:00
if (oldVersion < lokiV19) {
db.execSQL(LokiAPIDatabase.getCreateClosedGroupEncryptionKeyPairsTable());
db.execSQL(LokiAPIDatabase.getCreateClosedGroupPublicKeysTable());
db.execSQL("DROP TABLE identities");
deleteJobRecords(db, "RetrieveProfileJob");
2020-12-16 03:36:20 +01:00
deleteJobRecords(db,
"RefreshAttributesJob",
2020-12-17 02:47:18 +01:00
"RotateProfileKeyJob",
"RefreshUnidentifiedDeliveryAbilityJob",
"RotateCertificateJob"
2020-12-16 03:36:20 +01:00
);
}
2021-02-17 01:30:37 +01:00
if (oldVersion < lokiV20) {
deleteJobRecords(db,
"CleanPreKeysJob",
"RefreshPreKeysJob",
2021-02-17 01:36:56 +01:00
"CreateSignedPreKeyJob",
"RotateSignedPreKeyJob",
"MultiDeviceBlockedUpdateJob",
"MultiDeviceConfigurationUpdateJob",
"MultiDeviceContactUpdateJob",
"MultiDeviceGroupUpdateJob",
"MultiDeviceOpenGroupUpdateJob",
"MultiDeviceProfileKeyUpdateJob",
"MultiDeviceReadUpdateJob",
"MultiDeviceStickerPackOperationJob",
"MultiDeviceStickerPackSyncJob",
"MultiDeviceVerifiedUpdateJob",
"ServiceOutageDetectionJob",
"SessionRequestMessageSendJob"
2021-02-17 01:30:37 +01:00
);
}
if (oldVersion < lokiV21) {
2021-02-19 01:03:58 +01:00
deleteJobRecords(db,
"ClosedGroupUpdateMessageSendJob",
"NullMessageSendJob",
"StickerDownloadJob",
2021-02-22 06:29:48 +01:00
"StickerPackDownloadJob",
"MmsSendJob",
"MmsReceiveJob",
"MmsDownloadJob",
"SmsSendJob",
"SmsSentJob",
2021-02-23 01:29:07 +01:00
"SmsReceiveJob",
"PushGroupUpdateJob",
2021-03-15 04:56:46 +01:00
"ResetThreadSessionJob");
}
2021-03-02 02:24:09 +01:00
if (oldVersion < lokiV22) {
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
2021-03-05 01:24:43 +01:00
deleteJobRecords(db,
"PushGroupSendJob",
"PushMediaSendJob",
"PushTextSendJob",
"SendReadReceiptJob",
2021-03-05 01:31:12 +01:00
"TypingSendJob",
2021-03-09 03:54:15 +01:00
"AttachmentUploadJob",
"RequestGroupInfoJob",
2021-03-15 04:56:46 +01:00
"ClosedGroupUpdateMessageSendJobV2",
"SendDeliveryReceiptJob");
2021-03-02 02:24:09 +01:00
}
if (oldVersion < lokiV23) {
db.execSQL("ALTER TABLE groups ADD COLUMN zombie_members TEXT");
db.execSQL(LokiMessageDatabase.getUpdateMessageIDTableForType());
db.execSQL(LokiMessageDatabase.getUpdateMessageMappingTable());
}
2021-05-06 07:46:22 +02:00
if (oldVersion < lokiV24) {
String swarmTable = LokiAPIDatabase.Companion.getSwarmTable();
String snodePoolTable = LokiAPIDatabase.Companion.getSnodePoolTable();
db.execSQL("DROP TABLE " + swarmTable);
db.execSQL("DROP TABLE " + snodePoolTable);
db.execSQL(LokiAPIDatabase.getCreateSnodePoolTableCommand());
db.execSQL(LokiAPIDatabase.getCreateSwarmTableCommand());
}
2021-05-07 08:31:46 +02:00
if (oldVersion < lokiV25) {
2021-05-21 01:08:16 +02:00
String jobTable = SessionJobDatabase.sessionJobTable;
db.execSQL("DROP TABLE " + jobTable);
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
}
2021-05-21 07:21:24 +02:00
if (oldVersion < lokiV26) {
2021-05-07 08:31:46 +02:00
db.execSQL(SessionContactDatabase.getCreateSessionContactTableCommand());
}
if (oldVersion < lokiV27) {
db.execSQL(RecipientDatabase.getCreateNotificationTypeCommand());
}
2018-02-16 05:33:10 +01:00
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
public SQLiteDatabase getReadableDatabase() {
return getReadableDatabase(databaseSecret.asString());
}
public SQLiteDatabase getWritableDatabase() {
return getWritableDatabase(databaseSecret.asString());
}
public void markCurrent(SQLiteDatabase db) {
db.setVersion(DATABASE_VERSION);
}
private void executeStatements(SQLiteDatabase db, String[] statements) {
for (String statement : statements)
db.execSQL(statement);
}
private static boolean columnExists(@NonNull SQLiteDatabase db, @NonNull String table, @NonNull String column) {
try (Cursor cursor = db.rawQuery("PRAGMA table_info(" + table + ")", null)) {
int nameColumnIndex = cursor.getColumnIndexOrThrow("name");
while (cursor.moveToNext()) {
String name = cursor.getString(nameColumnIndex);
if (name.equals(column)) {
return true;
}
}
}
return false;
}
/**
* Cleans up all the records related to the job keys specified.
* This method should be called once the Signal job class is deleted from the project.
*/
private static void deleteJobRecords(SQLiteDatabase db, String... jobKeys) {
for (String jobKey : jobKeys) {
db.execSQL("DELETE FROM job_spec WHERE factory_key = ?", new String[]{jobKey});
db.execSQL("DELETE FROM constraint_spec WHERE factory_key = ?", new String[]{jobKey});
}
}
}