Update sender key store and MSL to be recipient-remap-safe.

The MSL is now remapped in the merge, and the sender key store is now
just keyed off of UUIDs.
fork-5.53.8
Greyson Parrelli 2021-10-08 12:41:47 -04:00
rodzic 88074134af
commit f65de84c19
6 zmienionych plików z 67 dodań i 25 usunięć

Wyświetl plik

@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.crypto.storage.SignalSenderKeyStore;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.signalservice.api.SignalSessionLock; import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
@ -20,7 +21,7 @@ public final class SenderKeyUtil {
*/ */
public static void rotateOurKey(@NonNull Context context, @NonNull DistributionId distributionId) { public static void rotateOurKey(@NonNull Context context, @NonNull DistributionId distributionId) {
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
ApplicationDependencies.getSenderKeyStore().deleteAllFor(Recipient.self().getId(), distributionId); ApplicationDependencies.getSenderKeyStore().deleteAllFor(Recipient.self().requireServiceId(), distributionId);
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(distributionId); DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(distributionId);
} }
} }
@ -29,7 +30,8 @@ public final class SenderKeyUtil {
* Gets when the sender key session was created, or -1 if it doesn't exist. * Gets when the sender key session was created, or -1 if it doesn't exist.
*/ */
public static long getCreateTimeForOurKey(@NonNull Context context, @NonNull DistributionId distributionId) { public static long getCreateTimeForOurKey(@NonNull Context context, @NonNull DistributionId distributionId) {
return DatabaseFactory.getSenderKeyDatabase(context).getCreatedTime(Recipient.self().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID, distributionId); SignalProtocolAddress address = new SignalProtocolAddress(Recipient.self().requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
return DatabaseFactory.getSenderKeyDatabase(context).getCreatedTime(address, distributionId);
} }
/** /**

Wyświetl plik

@ -34,16 +34,14 @@ public final class SignalSenderKeyStore implements SignalServiceSenderKeyStore {
@Override @Override
public void storeSenderKey(@NonNull SignalProtocolAddress sender, @NonNull UUID distributionId, @NonNull SenderKeyRecord record) { public void storeSenderKey(@NonNull SignalProtocolAddress sender, @NonNull UUID distributionId, @NonNull SenderKeyRecord record) {
synchronized (LOCK) { synchronized (LOCK) {
RecipientId recipientId = RecipientId.fromExternalPush(sender.getName()); DatabaseFactory.getSenderKeyDatabase(context).store(sender, DistributionId.from(distributionId), record);
DatabaseFactory.getSenderKeyDatabase(context).store(recipientId, sender.getDeviceId(), DistributionId.from(distributionId), record);
} }
} }
@Override @Override
public @Nullable SenderKeyRecord loadSenderKey(@NonNull SignalProtocolAddress sender, @NonNull UUID distributionId) { public @Nullable SenderKeyRecord loadSenderKey(@NonNull SignalProtocolAddress sender, @NonNull UUID distributionId) {
synchronized (LOCK) { synchronized (LOCK) {
RecipientId recipientId = RecipientId.fromExternalPush(sender.getName()); return DatabaseFactory.getSenderKeyDatabase(context).load(sender, DistributionId.from(distributionId));
return DatabaseFactory.getSenderKeyDatabase(context).load(recipientId, sender.getDeviceId(), DistributionId.from(distributionId));
} }
} }
@ -71,9 +69,9 @@ public final class SignalSenderKeyStore implements SignalServiceSenderKeyStore {
/** /**
* Removes all sender key session state for all devices for the provided recipient-distributionId pair. * Removes all sender key session state for all devices for the provided recipient-distributionId pair.
*/ */
public void deleteAllFor(@NonNull RecipientId recipientId, @NonNull DistributionId distributionId) { public void deleteAllFor(@NonNull String addressName, @NonNull DistributionId distributionId) {
synchronized (LOCK) { synchronized (LOCK) {
DatabaseFactory.getSenderKeyDatabase(context).deleteAllFor(recipientId, distributionId); DatabaseFactory.getSenderKeyDatabase(context).deleteAllFor(addressName, distributionId);
} }
} }

Wyświetl plik

@ -362,5 +362,17 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: SQLC
db.delete(PayloadTable.TABLE_NAME, query, args) db.delete(PayloadTable.TABLE_NAME, query, args)
} }
fun remapRecipient(oldRecipientId: RecipientId, newRecipientId: RecipientId) {
val values = ContentValues().apply {
put(RecipientTable.RECIPIENT_ID, newRecipientId.serialize())
}
val db = databaseHelper.signalWritableDatabase
val query = "${RecipientTable.RECIPIENT_ID} = ?"
val args = SqlUtil.buildArgs(oldRecipientId.serialize())
db.update(RecipientTable.TABLE_NAME, values, query, args)
}
private data class RecipientDevice(val recipientId: RecipientId, val devices: List<Int>) private data class RecipientDevice(val recipientId: RecipientId, val devices: List<Int>)
} }

Wyświetl plik

@ -3111,6 +3111,9 @@ public class RecipientDatabase extends Database {
Log.w(TAG, "Had no sessions. No action necessary.", true); Log.w(TAG, "Had no sessions. No action necessary.", true);
} }
// MSL
DatabaseFactory.getMessageLogDatabase(context).remapRecipient(byE164, byUuid);
// Mentions // Mentions
ContentValues mentionRecipientValues = new ContentValues(); ContentValues mentionRecipientValues = new ContentValues();
mentionRecipientValues.put(MentionDatabase.RECIPIENT_ID, byUuid.serialize()); mentionRecipientValues.put(MentionDatabase.RECIPIENT_ID, byUuid.serialize());

Wyświetl plik

@ -10,8 +10,8 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.DistributionId;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.CursorUtil; import org.thoughtcrime.securesms.util.CursorUtil;
import org.thoughtcrime.securesms.util.SqlUtil; import org.thoughtcrime.securesms.util.SqlUtil;
import org.whispersystems.libsignal.groups.state.SenderKeyRecord; import org.whispersystems.libsignal.groups.state.SenderKeyRecord;
@ -31,30 +31,30 @@ public class SenderKeyDatabase extends Database {
public static final String TABLE_NAME = "sender_keys"; public static final String TABLE_NAME = "sender_keys";
private static final String ID = "_id"; private static final String ID = "_id";
public static final String RECIPIENT_ID = "recipient_id"; public static final String ADDRESS = "address";
public static final String DEVICE = "device"; public static final String DEVICE = "device";
public static final String DISTRIBUTION_ID = "distribution_id"; public static final String DISTRIBUTION_ID = "distribution_id";
public static final String RECORD = "record"; public static final String RECORD = "record";
public static final String CREATED_AT = "created_at"; public static final String CREATED_AT = "created_at";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
RECIPIENT_ID + " INTEGER NOT NULL, " + ADDRESS + " TEXT NOT NULL, " +
DEVICE + " INTEGER NOT NULL, " + DEVICE + " INTEGER NOT NULL, " +
DISTRIBUTION_ID + " TEXT NOT NULL, " + DISTRIBUTION_ID + " TEXT NOT NULL, " +
RECORD + " BLOB NOT NULL, " + RECORD + " BLOB NOT NULL, " +
CREATED_AT + " INTEGER NOT NULL, " + CREATED_AT + " INTEGER NOT NULL, " +
"UNIQUE(" + RECIPIENT_ID + "," + DEVICE + ", " + DISTRIBUTION_ID + ") ON CONFLICT REPLACE);"; "UNIQUE(" + ADDRESS + "," + DEVICE + ", " + DISTRIBUTION_ID + ") ON CONFLICT REPLACE);";
SenderKeyDatabase(Context context, SQLCipherOpenHelper databaseHelper) { SenderKeyDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper); super(context, databaseHelper);
} }
public void store(@NonNull RecipientId recipientId, int deviceId, @NonNull DistributionId distributionId, @NonNull SenderKeyRecord record) { public void store(@NonNull SignalProtocolAddress address, @NonNull DistributionId distributionId, @NonNull SenderKeyRecord record) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(RECIPIENT_ID, recipientId.serialize()); values.put(ADDRESS, address.getName());
values.put(DEVICE, deviceId); values.put(DEVICE, address.getDeviceId());
values.put(DISTRIBUTION_ID, distributionId.toString()); values.put(DISTRIBUTION_ID, distributionId.toString());
values.put(RECORD, record.serialize()); values.put(RECORD, record.serialize());
values.put(CREATED_AT, System.currentTimeMillis()); values.put(CREATED_AT, System.currentTimeMillis());
@ -62,11 +62,11 @@ public class SenderKeyDatabase extends Database {
db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE); db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
} }
public @Nullable SenderKeyRecord load(@NonNull RecipientId recipientId, int deviceId, @NonNull DistributionId distributionId) { public @Nullable SenderKeyRecord load(@NonNull SignalProtocolAddress address, @NonNull DistributionId distributionId) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String query = RECIPIENT_ID + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?"; String query = ADDRESS + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(recipientId, deviceId, distributionId); String[] args = SqlUtil.buildArgs(address.getName(), address.getDeviceId(), distributionId);
try (Cursor cursor = db.query(TABLE_NAME, new String[]{ RECORD }, query, args, null, null, null)) { try (Cursor cursor = db.query(TABLE_NAME, new String[]{ RECORD }, query, args, null, null, null)) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@ -84,11 +84,11 @@ public class SenderKeyDatabase extends Database {
/** /**
* Gets when the sender key session was created, or -1 if it doesn't exist. * Gets when the sender key session was created, or -1 if it doesn't exist.
*/ */
public long getCreatedTime(@NonNull RecipientId recipientId, int deviceId, @NonNull DistributionId distributionId) { public long getCreatedTime(@NonNull SignalProtocolAddress address, @NonNull DistributionId distributionId) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String query = RECIPIENT_ID + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?"; String query = ADDRESS + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(recipientId, deviceId, distributionId); String[] args = SqlUtil.buildArgs(address.getName(), address.getDeviceId(), distributionId);
try (Cursor cursor = db.query(TABLE_NAME, new String[]{ CREATED_AT }, query, args, null, null, null)) { try (Cursor cursor = db.query(TABLE_NAME, new String[]{ CREATED_AT }, query, args, null, null, null)) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@ -102,10 +102,10 @@ public class SenderKeyDatabase extends Database {
/** /**
* Removes all sender key session state for all devices for the provided recipient-distributionId pair. * Removes all sender key session state for all devices for the provided recipient-distributionId pair.
*/ */
public void deleteAllFor(@NonNull RecipientId recipientId, @NonNull DistributionId distributionId) { public void deleteAllFor(@NonNull String addressName, @NonNull DistributionId distributionId) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
String query = RECIPIENT_ID + " = ? AND " + DISTRIBUTION_ID + " = ?"; String query = ADDRESS + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(recipientId, distributionId); String[] args = SqlUtil.buildArgs(addressName, distributionId);
db.delete(TABLE_NAME, query, args); db.delete(TABLE_NAME, query, args);
} }

Wyświetl plik

@ -217,8 +217,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
private static final int CLEANUP_SESSION_MIGRATION = 116; private static final int CLEANUP_SESSION_MIGRATION = 116;
private static final int RECEIPT_TIMESTAMP = 117; private static final int RECEIPT_TIMESTAMP = 117;
private static final int BADGES = 118; private static final int BADGES = 118;
private static final int SENDER_KEY_UUID = 119;
private static final int DATABASE_VERSION = 118; private static final int DATABASE_VERSION = 119;
private static final String DATABASE_NAME = "signal.db"; private static final String DATABASE_NAME = "signal.db";
private final Context context; private final Context context;
@ -2048,6 +2049,32 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
db.execSQL("ALTER TABLE recipient ADD COLUMN badges BLOB DEFAULT NULL"); db.execSQL("ALTER TABLE recipient ADD COLUMN badges BLOB DEFAULT NULL");
} }
if (oldVersion < SENDER_KEY_UUID) {
long start = System.currentTimeMillis();
db.execSQL("CREATE TABLE sender_keys_tmp (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"address TEXT NOT NULL, " +
"device INTEGER NOT NULL, " +
"distribution_id TEXT NOT NULL, " +
"record BLOB NOT NULL, " +
"created_at INTEGER NOT NULL, " +
"UNIQUE(address, device, distribution_id) ON CONFLICT REPLACE)");
db.execSQL("INSERT INTO sender_keys_tmp (address, device, distribution_id, record, created_at) " +
"SELECT recipient.uuid AS new_address, " +
"sender_keys.device, " +
"sender_keys.distribution_id, " +
"sender_keys.record, " +
"sender_keys.created_at " +
"FROM sender_keys INNER JOIN recipient ON sender_keys.recipient_id = recipient._id " +
"WHERE new_address NOT NULL");
db.execSQL("DROP TABLE sender_keys");
db.execSQL("ALTER TABLE sender_keys_tmp RENAME TO sender_keys");
Log.d(TAG, "Sender key migration took " + (System.currentTimeMillis() - start) + " ms");
}
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();