kopia lustrzana https://github.com/ryukoposting/Signal-Android
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
rodzic
88074134af
commit
f65de84c19
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Ładowanie…
Reference in New Issue