mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 09:20:19 +01:00
Separate session store for PNI.
This commit is contained in:
@@ -12,7 +12,7 @@ import org.whispersystems.libsignal.state.PreKeyRecord
|
||||
import org.whispersystems.signalservice.api.push.AccountIdentifier
|
||||
import java.io.IOException
|
||||
|
||||
class OneTimePreKeyDatabase internal constructor(context: Context?, databaseHelper: SignalDatabase?) : Database(context, databaseHelper) {
|
||||
class OneTimePreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
|
||||
companion object {
|
||||
private val TAG = Log.tag(OneTimePreKeyDatabase::class.java)
|
||||
|
||||
|
||||
@@ -2604,19 +2604,20 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||
}
|
||||
|
||||
// Sessions
|
||||
val localAci: ACI = Recipient.self().aci.get()
|
||||
val sessionDatabase = sessions
|
||||
val hasE164Session = sessionDatabase.getAllFor(e164Record.e164).size > 0
|
||||
val hasAciSession = sessionDatabase.getAllFor(aciRecord.aci.toString()).size > 0
|
||||
val hasE164Session = sessionDatabase.getAllFor(localAci, e164Record.e164).isNotEmpty()
|
||||
val hasAciSession = sessionDatabase.getAllFor(localAci, aciRecord.aci.toString()).isNotEmpty()
|
||||
|
||||
if (hasE164Session && hasAciSession) {
|
||||
Log.w(TAG, "Had a session for both users. Deleting the E164.", true)
|
||||
sessionDatabase.deleteAllFor(e164Record.e164)
|
||||
sessionDatabase.deleteAllFor(localAci, e164Record.e164)
|
||||
} else if (hasE164Session && !hasAciSession) {
|
||||
Log.w(TAG, "Had a session for E164, but not ACI. Re-assigning to the ACI.", true)
|
||||
val values = ContentValues().apply {
|
||||
put(SessionDatabase.ADDRESS, aciRecord.aci.toString())
|
||||
}
|
||||
db.update(SessionDatabase.TABLE_NAME, values, SessionDatabase.ADDRESS + " = ?", SqlUtil.buildArgs(e164Record.e164))
|
||||
db.update(SessionDatabase.TABLE_NAME, values, "${SessionDatabase.ACCOUNT_ID} = ? AND ${SessionDatabase.ADDRESS} = ?", SqlUtil.buildArgs(localAci, e164Record.e164))
|
||||
} else if (!hasE164Session && hasAciSession) {
|
||||
Log.w(TAG, "Had a session for ACI, but not E164. No action necessary.", true)
|
||||
} else {
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.zetetic.database.sqlcipher.SQLiteStatement;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class SessionDatabase extends Database {
|
||||
|
||||
private static final String TAG = Log.tag(SessionDatabase.class);
|
||||
|
||||
public static final String TABLE_NAME = "sessions";
|
||||
|
||||
private static final String ID = "_id";
|
||||
public static final String ADDRESS = "address";
|
||||
public static final String DEVICE = "device";
|
||||
public static final String RECORD = "record";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
ADDRESS + " TEXT NOT NULL, " +
|
||||
DEVICE + " INTEGER NOT NULL, " +
|
||||
RECORD + " BLOB NOT NULL, " +
|
||||
"UNIQUE(" + ADDRESS + "," + DEVICE + "));";
|
||||
|
||||
SessionDatabase(Context context, SignalDatabase databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public void store(@NonNull SignalProtocolAddress address, @NonNull SessionRecord record) {
|
||||
if (address.getName().charAt(0) == '+') {
|
||||
throw new IllegalArgumentException("Cannot insert an e164 into this table!");
|
||||
}
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
|
||||
try (SQLiteStatement statement = db.compileStatement("INSERT INTO " + TABLE_NAME + " (" + ADDRESS + ", " + DEVICE + ", " + RECORD + ") VALUES (?, ?, ?) " +
|
||||
"ON CONFLICT (" + ADDRESS + ", " + DEVICE + ") DO UPDATE SET " + RECORD + " = excluded." + RECORD))
|
||||
{
|
||||
statement.bindString(1, address.getName());
|
||||
statement.bindLong(2, address.getDeviceId());
|
||||
statement.bindBlob(3, record.serialize());
|
||||
statement.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable SessionRecord load(@NonNull SignalProtocolAddress address) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
String[] projection = new String[] { RECORD };
|
||||
String selection = ADDRESS + " = ? AND " + DEVICE + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(address.getName(), address.getDeviceId());
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, projection, selection, args, null, null, null)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
try {
|
||||
return new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public @NonNull List<SessionRecord> load(@NonNull List<SignalProtocolAddress> addresses) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
String query = ADDRESS + " = ? AND " + DEVICE + " = ?";
|
||||
List<String[]> args = new ArrayList<>(addresses.size());
|
||||
|
||||
HashMap<SignalProtocolAddress, SessionRecord> sessions = new LinkedHashMap<>(addresses.size());
|
||||
|
||||
for (SignalProtocolAddress address : addresses) {
|
||||
args.add(SqlUtil.buildArgs(address.getName(), address.getDeviceId()));
|
||||
sessions.put(address, null);
|
||||
}
|
||||
|
||||
String[] projection = new String[] { ADDRESS, DEVICE, RECORD };
|
||||
|
||||
for (SqlUtil.Query combinedQuery : SqlUtil.buildCustomCollectionQuery(query, args)) {
|
||||
try (Cursor cursor = database.query(TABLE_NAME, projection, combinedQuery.getWhere(), combinedQuery.getWhereArgs(), null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
String address = CursorUtil.requireString(cursor, ADDRESS);
|
||||
int device = CursorUtil.requireInt(cursor, DEVICE);
|
||||
|
||||
try {
|
||||
SessionRecord record = new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)));
|
||||
sessions.put(new SignalProtocolAddress(address, device), record);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(sessions.values());
|
||||
}
|
||||
|
||||
public @NonNull List<SessionRow> getAllFor(@NonNull String addressName) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
List<SessionRow> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", SqlUtil.buildArgs(addressName), null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(new SessionRow(CursorUtil.requireString(cursor, ADDRESS),
|
||||
CursorUtil.requireInt(cursor, DEVICE),
|
||||
new SessionRecord(CursorUtil.requireBlob(cursor, RECORD))));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public @NonNull List<SessionRow> getAllFor(@NonNull List<String> addressNames) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
SqlUtil.Query query = SqlUtil.buildCollectionQuery(ADDRESS, addressNames);
|
||||
List<SessionRow> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, null, query.getWhere(), query.getWhereArgs(), null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(new SessionRow(CursorUtil.requireString(cursor, ADDRESS),
|
||||
CursorUtil.requireInt(cursor, DEVICE),
|
||||
new SessionRecord(CursorUtil.requireBlob(cursor, RECORD))));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public @NonNull List<SessionRow> getAll() {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
List<SessionRow> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, null, null, null, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(new SessionRow(CursorUtil.requireString(cursor, ADDRESS),
|
||||
CursorUtil.requireInt(cursor, DEVICE),
|
||||
new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)))));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public @NonNull List<Integer> getSubDevices(@NonNull String addressName) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
List<Integer> results = new LinkedList<>();
|
||||
String[] projection = new String[] { DEVICE };
|
||||
String selection = ADDRESS + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(addressName);
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, projection, selection, args, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
int device = cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE));
|
||||
|
||||
if (device != SignalServiceAddress.DEFAULT_DEVICE_ID) {
|
||||
results.add(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void delete(@NonNull SignalProtocolAddress address) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
String selection = ADDRESS + " = ? AND " + DEVICE + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(address.getName(), address.getDeviceId());
|
||||
|
||||
|
||||
database.delete(TABLE_NAME, selection, args);
|
||||
}
|
||||
|
||||
public void deleteAllFor(@NonNull String addressName) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
database.delete(TABLE_NAME, ADDRESS + " = ?", SqlUtil.buildArgs(addressName));
|
||||
}
|
||||
|
||||
public boolean hasSessionFor(@NonNull String addressName) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
String query = ADDRESS + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(addressName);
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, new String[] { "1" }, query, args, null, null, null, "1")) {
|
||||
return cursor.moveToFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SessionRow {
|
||||
private final String address;
|
||||
private final int deviceId;
|
||||
private final SessionRecord record;
|
||||
|
||||
public SessionRow(@NonNull String address, int deviceId, SessionRecord record) {
|
||||
this.address = address;
|
||||
this.deviceId = deviceId;
|
||||
this.record = record;
|
||||
}
|
||||
|
||||
public @NonNull String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public int getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public SessionRecord getRecord() {
|
||||
return record;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.util.CursorUtil
|
||||
import org.thoughtcrime.securesms.util.SqlUtil
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress
|
||||
import org.whispersystems.libsignal.state.SessionRecord
|
||||
import org.whispersystems.signalservice.api.push.AccountIdentifier
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import java.io.IOException
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import java.util.LinkedHashMap
|
||||
import java.util.LinkedList
|
||||
|
||||
class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
|
||||
companion object {
|
||||
private val TAG = Log.tag(SessionDatabase::class.java)
|
||||
|
||||
const val TABLE_NAME = "sessions"
|
||||
const val ID = "_id"
|
||||
const val ACCOUNT_ID = "account_id"
|
||||
const val ADDRESS = "address"
|
||||
const val DEVICE = "device"
|
||||
const val RECORD = "record"
|
||||
const val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$ACCOUNT_ID TEXT NOT NULL,
|
||||
$ADDRESS TEXT NOT NULL,
|
||||
$DEVICE INTEGER NOT NULL,
|
||||
$RECORD BLOB NOT NULL,
|
||||
UNIQUE($ACCOUNT_ID, $ADDRESS, $DEVICE)
|
||||
"""
|
||||
}
|
||||
|
||||
fun store(accountId: AccountIdentifier, address: SignalProtocolAddress, record: SessionRecord) {
|
||||
require(address.name[0] != '+') { "Cannot insert an e164 into this table!" }
|
||||
|
||||
writableDatabase.compileStatement("INSERT INTO $TABLE_NAME ($ACCOUNT_ID, $ADDRESS, $DEVICE, $RECORD) VALUES (?, ?, ?, ?) ON CONFLICT ($ACCOUNT_ID, $ADDRESS, $DEVICE) DO UPDATE SET $RECORD = excluded.$RECORD").use { statement ->
|
||||
statement.apply {
|
||||
bindString(1, accountId.toString())
|
||||
bindString(2, address.name)
|
||||
bindLong(3, address.deviceId.toLong())
|
||||
bindBlob(4, record.serialize())
|
||||
execute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun load(accountId: AccountIdentifier, address: SignalProtocolAddress): SessionRecord? {
|
||||
val projection = arrayOf(RECORD)
|
||||
val selection = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?"
|
||||
val args = SqlUtil.buildArgs(accountId, address.name, address.deviceId)
|
||||
|
||||
readableDatabase.query(TABLE_NAME, projection, selection, args, null, null, null).use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
try {
|
||||
return SessionRecord(cursor.requireNonNullBlob(RECORD))
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun load(accountId: AccountIdentifier, addresses: List<SignalProtocolAddress>): List<SessionRecord?> {
|
||||
val projection = arrayOf(ADDRESS, DEVICE, RECORD)
|
||||
val query = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?"
|
||||
val args: MutableList<Array<String>> = ArrayList(addresses.size)
|
||||
val sessions: HashMap<SignalProtocolAddress, SessionRecord?> = LinkedHashMap(addresses.size)
|
||||
|
||||
for (address in addresses) {
|
||||
args.add(SqlUtil.buildArgs(accountId, address.name, address.deviceId))
|
||||
sessions[address] = null
|
||||
}
|
||||
|
||||
for (combinedQuery in SqlUtil.buildCustomCollectionQuery(query, args)) {
|
||||
readableDatabase.query(TABLE_NAME, projection, combinedQuery.where, combinedQuery.whereArgs, null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
val address = cursor.requireNonNullString(ADDRESS)
|
||||
val device = cursor.requireInt(DEVICE)
|
||||
try {
|
||||
val record = SessionRecord(cursor.requireNonNullBlob(RECORD))
|
||||
sessions[SignalProtocolAddress(address, device)] = record
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sessions.values.toList()
|
||||
}
|
||||
|
||||
fun getAllFor(accountId: AccountIdentifier, addressName: String): List<SessionRow> {
|
||||
val results: MutableList<SessionRow> = mutableListOf()
|
||||
|
||||
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $ADDRESS = ?", SqlUtil.buildArgs(accountId, addressName), null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(
|
||||
SessionRow(
|
||||
CursorUtil.requireString(cursor, ADDRESS),
|
||||
CursorUtil.requireInt(cursor, DEVICE),
|
||||
SessionRecord(CursorUtil.requireBlob(cursor, RECORD))
|
||||
)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
fun getAllFor(accountId: AccountIdentifier, addressNames: List<String?>): List<SessionRow> {
|
||||
val query: SqlUtil.Query = SqlUtil.buildCollectionQuery(ADDRESS, addressNames)
|
||||
val results: MutableList<SessionRow> = LinkedList()
|
||||
|
||||
val queryString = "$ACCOUNT_ID = ? AND (${query.where})"
|
||||
val queryArgs: Array<String> = arrayOf(accountId.toString()) + query.whereArgs
|
||||
|
||||
readableDatabase.query(TABLE_NAME, null, queryString, queryArgs, null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(
|
||||
SessionRow(
|
||||
address = CursorUtil.requireString(cursor, ADDRESS),
|
||||
deviceId = CursorUtil.requireInt(cursor, DEVICE),
|
||||
record = SessionRecord(cursor.requireNonNullBlob(RECORD))
|
||||
)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
fun getAll(accountId: AccountIdentifier): List<SessionRow> {
|
||||
val results: MutableList<SessionRow> = mutableListOf()
|
||||
|
||||
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(accountId), null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(
|
||||
SessionRow(
|
||||
address = cursor.requireNonNullString(ADDRESS),
|
||||
deviceId = cursor.requireInt(DEVICE),
|
||||
record = SessionRecord(cursor.requireNonNullBlob(RECORD))
|
||||
)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
fun getSubDevices(accountId: AccountIdentifier, addressName: String): List<Int> {
|
||||
val projection = arrayOf(DEVICE)
|
||||
val selection = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE != ?"
|
||||
val args = SqlUtil.buildArgs(accountId, addressName, SignalServiceAddress.DEFAULT_DEVICE_ID)
|
||||
|
||||
val results: MutableList<Int> = mutableListOf()
|
||||
|
||||
readableDatabase.query(TABLE_NAME, projection, selection, args, null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
results.add(cursor.requireInt(DEVICE))
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
fun delete(accountId: AccountIdentifier, address: SignalProtocolAddress) {
|
||||
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?", SqlUtil.buildArgs(accountId, address.name, address.deviceId))
|
||||
}
|
||||
|
||||
fun deleteAllFor(accountId: AccountIdentifier, addressName: String) {
|
||||
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $ADDRESS = ?", SqlUtil.buildArgs(accountId, addressName))
|
||||
}
|
||||
|
||||
fun hasSessionFor(accountId: AccountIdentifier, addressName: String): Boolean {
|
||||
val query = "$ACCOUNT_ID = ? AND $ADDRESS = ?"
|
||||
val args = SqlUtil.buildArgs(accountId, addressName)
|
||||
readableDatabase.query(TABLE_NAME, arrayOf("1"), query, args, null, null, null, "1").use { cursor ->
|
||||
return cursor.moveToFirst()
|
||||
}
|
||||
}
|
||||
|
||||
class SessionRow(val address: String, val deviceId: Int, val record: SessionRecord)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.whispersystems.signalservice.api.push.AccountIdentifier
|
||||
import java.io.IOException
|
||||
import java.util.LinkedList
|
||||
|
||||
class SignedPreKeyDatabase internal constructor(context: Context?, databaseHelper: SignalDatabase?) : Database(context, databaseHelper) {
|
||||
class SignedPreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
|
||||
companion object {
|
||||
private val TAG = Log.tag(SignedPreKeyDatabase::class.java)
|
||||
|
||||
|
||||
@@ -2363,6 +2363,39 @@ object SignalDatabaseMigrations {
|
||||
|
||||
db.execSQL("DROP TABLE signed_prekeys")
|
||||
db.execSQL("ALTER TABLE signed_prekeys_tmp RENAME TO signed_prekeys")
|
||||
|
||||
// Sessions
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE sessions_tmp (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id TEXT NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
device INTEGER NOT NULL,
|
||||
record BLOB NOT NULL,
|
||||
UNIQUE(account_id, address, device)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
if (localAci != null) {
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO sessions_tmp (account_id, address, device, record)
|
||||
SELECT
|
||||
'$localAci' AS account_id,
|
||||
sessions.address,
|
||||
sessions.device,
|
||||
sessions.record
|
||||
FROM sessions
|
||||
""".trimIndent()
|
||||
)
|
||||
} else {
|
||||
Log.w(TAG, "No local ACI set. Not migrating any existing sessions.")
|
||||
}
|
||||
|
||||
db.execSQL("DROP TABLE sessions")
|
||||
db.execSQL("ALTER TABLE sessions_tmp RENAME TO sessions")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user