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.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.push.DistributionId;
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) {
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);
}
}
@ -29,7 +30,8 @@ public final class SenderKeyUtil {
* 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) {
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
public void storeSenderKey(@NonNull SignalProtocolAddress sender, @NonNull UUID distributionId, @NonNull SenderKeyRecord record) {
synchronized (LOCK) {
RecipientId recipientId = RecipientId.fromExternalPush(sender.getName());
DatabaseFactory.getSenderKeyDatabase(context).store(recipientId, sender.getDeviceId(), DistributionId.from(distributionId), record);
DatabaseFactory.getSenderKeyDatabase(context).store(sender, DistributionId.from(distributionId), record);
}
}
@Override
public @Nullable SenderKeyRecord loadSenderKey(@NonNull SignalProtocolAddress sender, @NonNull UUID distributionId) {
synchronized (LOCK) {
RecipientId recipientId = RecipientId.fromExternalPush(sender.getName());
return DatabaseFactory.getSenderKeyDatabase(context).load(recipientId, sender.getDeviceId(), DistributionId.from(distributionId));
return DatabaseFactory.getSenderKeyDatabase(context).load(sender, 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.
*/
public void deleteAllFor(@NonNull RecipientId recipientId, @NonNull DistributionId distributionId) {
public void deleteAllFor(@NonNull String addressName, @NonNull DistributionId distributionId) {
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)
}
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>)
}

Wyświetl plik

@ -3111,6 +3111,9 @@ public class RecipientDatabase extends Database {
Log.w(TAG, "Had no sessions. No action necessary.", true);
}
// MSL
DatabaseFactory.getMessageLogDatabase(context).remapRecipient(byE164, byUuid);
// Mentions
ContentValues mentionRecipientValues = new ContentValues();
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.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.CursorUtil;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.whispersystems.libsignal.groups.state.SenderKeyRecord;
@ -31,30 +31,30 @@ public class SenderKeyDatabase extends Database {
public static final String TABLE_NAME = "sender_keys";
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 DISTRIBUTION_ID = "distribution_id";
public static final String RECORD = "record";
public static final String CREATED_AT = "created_at";
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, " +
DISTRIBUTION_ID + " TEXT NOT NULL, " +
RECORD + " BLOB 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) {
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();
ContentValues values = new ContentValues();
values.put(RECIPIENT_ID, recipientId.serialize());
values.put(DEVICE, deviceId);
values.put(ADDRESS, address.getName());
values.put(DEVICE, address.getDeviceId());
values.put(DISTRIBUTION_ID, distributionId.toString());
values.put(RECORD, record.serialize());
values.put(CREATED_AT, System.currentTimeMillis());
@ -62,11 +62,11 @@ public class SenderKeyDatabase extends Database {
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();
String query = RECIPIENT_ID + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(recipientId, deviceId, distributionId);
String query = ADDRESS + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(address.getName(), address.getDeviceId(), distributionId);
try (Cursor cursor = db.query(TABLE_NAME, new String[]{ RECORD }, query, args, null, null, null)) {
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.
*/
public long getCreatedTime(@NonNull RecipientId recipientId, int deviceId, @NonNull DistributionId distributionId) {
public long getCreatedTime(@NonNull SignalProtocolAddress address, @NonNull DistributionId distributionId) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String query = RECIPIENT_ID + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(recipientId, deviceId, distributionId);
String query = ADDRESS + " = ? AND " + DEVICE + " = ? AND " + DISTRIBUTION_ID + " = ?";
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)) {
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.
*/
public void deleteAllFor(@NonNull RecipientId recipientId, @NonNull DistributionId distributionId) {
public void deleteAllFor(@NonNull String addressName, @NonNull DistributionId distributionId) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
String query = RECIPIENT_ID + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(recipientId, distributionId);
String query = ADDRESS + " = ? AND " + DISTRIBUTION_ID + " = ?";
String[] args = SqlUtil.buildArgs(addressName, distributionId);
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 RECEIPT_TIMESTAMP = 117;
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 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");
}
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();
} finally {
db.endTransaction();