mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Update the storage service.
This commit is contained in:
@@ -21,21 +21,24 @@ import org.thoughtcrime.securesms.contacts.sync.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
|
||||
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
||||
import org.whispersystems.signalservice.api.storage.StorageKey;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
@@ -62,6 +65,7 @@ public class RecipientDatabase extends Database {
|
||||
public static final String PHONE = "phone";
|
||||
public static final String EMAIL = "email";
|
||||
static final String GROUP_ID = "group_id";
|
||||
private static final String GROUP_TYPE = "group_type";
|
||||
private static final String BLOCKED = "blocked";
|
||||
private static final String MESSAGE_RINGTONE = "message_ringtone";
|
||||
private static final String MESSAGE_VIBRATE = "message_vibrate";
|
||||
@@ -100,7 +104,7 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
|
||||
private static final String[] RECIPIENT_PROJECTION = new String[] {
|
||||
UUID, USERNAME, PHONE, EMAIL, GROUP_ID,
|
||||
UUID, USERNAME, PHONE, EMAIL, GROUP_ID, GROUP_TYPE,
|
||||
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
|
||||
PROFILE_KEY, PROFILE_KEY_CREDENTIAL,
|
||||
SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_PHONE_TYPE, SYSTEM_CONTACT_URI,
|
||||
@@ -120,6 +124,7 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
public static final String[] CREATE_INDEXS = new String[] {
|
||||
"CREATE INDEX IF NOT EXISTS recipient_dirty_index ON " + TABLE_NAME + " (" + DIRTY + ");",
|
||||
"CREATE INDEX IF NOT EXISTS recipient_group_type_index ON " + TABLE_NAME + " (" + GROUP_TYPE + ");",
|
||||
};
|
||||
|
||||
private static final String[] ID_PROJECTION = new String[]{ID};
|
||||
@@ -219,6 +224,24 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public enum GroupType {
|
||||
NONE(0), MMS(1), SIGNAL_V1(2);
|
||||
|
||||
private final int id;
|
||||
|
||||
GroupType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static GroupType fromId(int id) {
|
||||
return values()[id];
|
||||
}
|
||||
}
|
||||
|
||||
public static final String CREATE_TABLE =
|
||||
"CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
UUID + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
@@ -226,6 +249,7 @@ public class RecipientDatabase extends Database {
|
||||
PHONE + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
EMAIL + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
GROUP_ID + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
GROUP_TYPE + " INTEGER DEFAULT " + GroupType.NONE.getId() + ", " +
|
||||
BLOCKED + " INTEGER DEFAULT 0," +
|
||||
MESSAGE_RINGTONE + " TEXT DEFAULT NULL, " +
|
||||
MESSAGE_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
@@ -255,7 +279,7 @@ public class RecipientDatabase extends Database {
|
||||
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0, " +
|
||||
UUID_SUPPORTED + " INTEGER DEFAULT 0, " +
|
||||
STORAGE_SERVICE_KEY + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
DIRTY + " INTEGER DEFAULT 0);";
|
||||
DIRTY + " INTEGER DEFAULT " + DirtyState.CLEAN.getId() + ");";
|
||||
|
||||
private static final String INSIGHTS_INVITEE_LIST = "SELECT " + TABLE_NAME + "." + ID +
|
||||
" FROM " + TABLE_NAME +
|
||||
@@ -305,19 +329,35 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
|
||||
public @NonNull RecipientId getOrInsertFromUuid(@NonNull UUID uuid) {
|
||||
return getOrInsertByColumn(UUID, uuid.toString());
|
||||
return getOrInsertByColumn(UUID, uuid.toString()).recipientId;
|
||||
}
|
||||
|
||||
public @NonNull RecipientId getOrInsertFromE164(@NonNull String e164) {
|
||||
return getOrInsertByColumn(PHONE, e164);
|
||||
return getOrInsertByColumn(PHONE, e164).recipientId;
|
||||
}
|
||||
|
||||
public RecipientId getOrInsertFromEmail(@NonNull String email) {
|
||||
return getOrInsertByColumn(EMAIL, email);
|
||||
public @NonNull RecipientId getOrInsertFromEmail(@NonNull String email) {
|
||||
return getOrInsertByColumn(EMAIL, email).recipientId;
|
||||
}
|
||||
|
||||
public RecipientId getOrInsertFromGroupId(@NonNull String groupId) {
|
||||
return getOrInsertByColumn(GROUP_ID, groupId);
|
||||
public @NonNull RecipientId getOrInsertFromGroupId(@NonNull String groupId) {
|
||||
GetOrInsertResult result = getOrInsertByColumn(GROUP_ID, groupId);
|
||||
|
||||
if (result.neededInsert) {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
if (GroupUtil.isMmsGroup(groupId)) {
|
||||
values.put(GROUP_TYPE, GroupType.MMS.getId());
|
||||
} else {
|
||||
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
||||
values.put(DIRTY, DirtyState.INSERT.getId());
|
||||
values.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
}
|
||||
|
||||
update(result.recipientId, values);
|
||||
}
|
||||
|
||||
return result.recipientId;
|
||||
}
|
||||
|
||||
public Cursor getBlocked() {
|
||||
@@ -355,15 +395,24 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientSettings> getPendingRecipientSyncUpdates() {
|
||||
return getRecipientSettings(DIRTY + " = ?", new String[] { String.valueOf(DirtyState.UPDATE.getId()) });
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_KEY + " NOT NULL";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.UPDATE.getId()) };
|
||||
|
||||
return getRecipientSettings(query, args);
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientSettings> getPendingRecipientSyncInsertions() {
|
||||
return getRecipientSettings(DIRTY + " = ?", new String[] { String.valueOf(DirtyState.INSERT.getId()) });
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_KEY + " NOT NULL";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.INSERT.getId()) };
|
||||
|
||||
return getRecipientSettings(query, args);
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientSettings> getPendingRecipientSyncDeletions() {
|
||||
return getRecipientSettings(DIRTY + " = ?", new String[] { String.valueOf(DirtyState.DELETE.getId()) });
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_KEY + " NOT NULL";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.DELETE.getId()) };
|
||||
|
||||
return getRecipientSettings(query, args);
|
||||
}
|
||||
|
||||
public @Nullable RecipientSettings getByStorageSyncKey(@NonNull byte[] key) {
|
||||
@@ -396,8 +445,10 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public void applyStorageSyncUpdates(@NonNull Collection<SignalContactRecord> inserts,
|
||||
@NonNull Collection<StorageSyncHelper.ContactUpdate> updates)
|
||||
public void applyStorageSyncUpdates(@NonNull Collection<SignalContactRecord> contactInserts,
|
||||
@NonNull Collection<StorageSyncHelper.ContactUpdate> contactUpdates,
|
||||
@NonNull Collection<SignalGroupV1Record> groupV1Inserts,
|
||||
@NonNull Collection<StorageSyncHelper.GroupV1Update> groupV1Updates)
|
||||
{
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
||||
@@ -405,7 +456,7 @@ public class RecipientDatabase extends Database {
|
||||
db.beginTransaction();
|
||||
|
||||
try {
|
||||
for (SignalContactRecord insert : inserts) {
|
||||
for (SignalContactRecord insert : contactInserts) {
|
||||
ContentValues values = getValuesForStorageContact(insert);
|
||||
long id = db.insertOrThrow(TABLE_NAME, null, values);
|
||||
RecipientId recipientId = RecipientId.from(id);
|
||||
@@ -420,17 +471,21 @@ public class RecipientDatabase extends Database {
|
||||
Log.w(TAG, "Failed to process identity key during insert! Skipping.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (Recipient.self().getId().equals(recipientId)) {
|
||||
TextSecurePreferences.setProfileName(context, ProfileName.fromParts(insert.getGivenName().orNull(), insert.getFamilyName().orNull()));
|
||||
}
|
||||
}
|
||||
|
||||
for (StorageSyncHelper.ContactUpdate update : updates) {
|
||||
ContentValues values = getValuesForStorageContact(update.getNewContact());
|
||||
int updateCount = db.update(TABLE_NAME, values, STORAGE_SERVICE_KEY + " = ?", new String[]{Base64.encodeBytes(update.getOldContact().getKey())});
|
||||
for (StorageSyncHelper.ContactUpdate update : contactUpdates) {
|
||||
ContentValues values = getValuesForStorageContact(update.getNew());
|
||||
int updateCount = db.update(TABLE_NAME, values, STORAGE_SERVICE_KEY + " = ?", new String[]{Base64.encodeBytes(update.getOld().getKey())});
|
||||
|
||||
if (updateCount < 1) {
|
||||
throw new AssertionError("Had an update, but it didn't match any rows!");
|
||||
}
|
||||
|
||||
RecipientId recipientId = getByStorageKeyOrThrow(update.getNewContact().getKey());
|
||||
RecipientId recipientId = getByStorageKeyOrThrow(update.getNew().getKey());
|
||||
|
||||
if (update.profileKeyChanged()) {
|
||||
clearProfileKeyCredential(recipientId);
|
||||
@@ -438,9 +493,11 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
try {
|
||||
Optional<IdentityRecord> oldIdentityRecord = identityDatabase.getIdentity(recipientId);
|
||||
IdentityKey identityKey = update.getNewContact().getIdentityKey().isPresent() ? new IdentityKey(update.getNewContact().getIdentityKey().get(), 0) : null;
|
||||
|
||||
DatabaseFactory.getIdentityDatabase(context).updateIdentityAfterSync(recipientId, identityKey, StorageSyncHelper.remoteToLocalIdentityStatus(update.getNewContact().getIdentityState()));
|
||||
if (update.getNew().getIdentityKey().isPresent()) {
|
||||
IdentityKey identityKey = new IdentityKey(update.getNew().getIdentityKey().get(), 0);
|
||||
DatabaseFactory.getIdentityDatabase(context).updateIdentityAfterSync(recipientId, identityKey, StorageSyncHelper.remoteToLocalIdentityStatus(update.getNew().getIdentityState()));
|
||||
}
|
||||
|
||||
Optional<IdentityRecord> newIdentityRecord = identityDatabase.getIdentity(recipientId);
|
||||
|
||||
@@ -458,6 +515,19 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
for (SignalGroupV1Record insert : groupV1Inserts) {
|
||||
db.insertOrThrow(TABLE_NAME, null, getValuesForStorageGroupV1(insert));
|
||||
}
|
||||
|
||||
for (StorageSyncHelper.GroupV1Update update : groupV1Updates) {
|
||||
ContentValues values = getValuesForStorageGroupV1(update.getNew());
|
||||
int updateCount = db.update(TABLE_NAME, values, STORAGE_SERVICE_KEY + " = ?", new String[]{Base64.encodeBytes(update.getOld().getKey())});
|
||||
|
||||
if (updateCount < 1) {
|
||||
throw new AssertionError("Had an update, but it didn't match any rows!");
|
||||
}
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
@@ -508,14 +578,14 @@ public class RecipientDatabase extends Database {
|
||||
values.put(UUID, contact.getAddress().getUuid().get().toString());
|
||||
}
|
||||
|
||||
ProfileName profileName = ProfileName.fromSerialized(contact.getProfileName().orNull());
|
||||
ProfileName profileName = ProfileName.fromParts(contact.getGivenName().orNull(), contact.getFamilyName().orNull());
|
||||
|
||||
values.put(PHONE, contact.getAddress().getNumber().orNull());
|
||||
values.put(PROFILE_GIVEN_NAME, profileName.getGivenName());
|
||||
values.put(PROFILE_FAMILY_NAME, profileName.getFamilyName());
|
||||
values.put(PROFILE_JOINED_NAME, profileName.toString());
|
||||
values.put(PROFILE_KEY, contact.getProfileKey().orNull());
|
||||
// TODO [greyson] Username
|
||||
values.put(PROFILE_KEY, contact.getProfileKey().transform(Base64::encodeBytes).orNull());
|
||||
values.put(USERNAME, contact.getUsername().orNull());
|
||||
values.put(PROFILE_SHARING, contact.isProfileSharingEnabled() ? "1" : "0");
|
||||
values.put(BLOCKED, contact.isBlocked() ? "1" : "0");
|
||||
values.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(contact.getKey()));
|
||||
@@ -523,6 +593,17 @@ public class RecipientDatabase extends Database {
|
||||
return values;
|
||||
}
|
||||
|
||||
private static @NonNull ContentValues getValuesForStorageGroupV1(@NonNull SignalGroupV1Record groupV1) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(GROUP_ID, GroupUtil.getEncodedId(groupV1.getGroupId(), false));
|
||||
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
||||
values.put(PROFILE_SHARING, groupV1.isProfileSharingEnabled() ? "1" : "0");
|
||||
values.put(BLOCKED, groupV1.isBlocked() ? "1" : "0");
|
||||
values.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(groupV1.getKey()));
|
||||
values.put(DIRTY, DirtyState.CLEAN.getId());
|
||||
return values;
|
||||
}
|
||||
|
||||
private List<RecipientSettings> getRecipientSettings(@Nullable String query, @Nullable String[] args) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String table = TABLE_NAME + " LEFT OUTER JOIN " + IdentityDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + ID + " = " + IdentityDatabase.TABLE_NAME + "." + IdentityDatabase.RECIPIENT_ID;
|
||||
@@ -555,27 +636,24 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID, STORAGE_SERVICE_KEY }, query, args, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||
RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||
String encodedKey = cursor.getString(cursor.getColumnIndexOrThrow(STORAGE_SERVICE_KEY));
|
||||
|
||||
try {
|
||||
out.put(id, Base64.decode(encodedKey));
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
out.put(id, Base64.decodeOrThrow(encodedKey));
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@NonNull RecipientSettings getRecipientSettings(@NonNull Cursor cursor) {
|
||||
private @NonNull RecipientSettings getRecipientSettings(@NonNull Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
UUID uuid = UuidUtil.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(UUID)));
|
||||
String username = cursor.getString(cursor.getColumnIndexOrThrow(USERNAME));
|
||||
String e164 = cursor.getString(cursor.getColumnIndexOrThrow(PHONE));
|
||||
String email = cursor.getString(cursor.getColumnIndexOrThrow(EMAIL));
|
||||
String groupId = cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
|
||||
int groupType = cursor.getInt(cursor.getColumnIndexOrThrow(GROUP_TYPE));
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKED)) == 1;
|
||||
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_RINGTONE));
|
||||
String callRingtone = cursor.getString(cursor.getColumnIndexOrThrow(CALL_RINGTONE));
|
||||
@@ -634,23 +712,12 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
byte[] storageKey = null;
|
||||
try {
|
||||
storageKey = storageKeyRaw != null ? Base64.decode(storageKeyRaw) : null;
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
byte[] identityKey = null;
|
||||
try {
|
||||
identityKey = identityKeyRaw != null ? Base64.decode(identityKeyRaw) : null;
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
byte[] storageKey = storageKeyRaw != null ? Base64.decodeOrThrow(storageKeyRaw) : null;
|
||||
byte[] identityKey = identityKeyRaw != null ? Base64.decodeOrThrow(identityKeyRaw) : null;
|
||||
|
||||
IdentityDatabase.VerifiedStatus identityStatus = IdentityDatabase.VerifiedStatus.forState(identityStatusRaw);
|
||||
|
||||
return new RecipientSettings(RecipientId.from(id), uuid, username, e164, email, groupId, blocked, muteUntil,
|
||||
return new RecipientSettings(RecipientId.from(id), uuid, username, e164, email, groupId, GroupType.fromId(groupType), blocked, muteUntil,
|
||||
VibrateState.fromId(messageVibrateState),
|
||||
VibrateState.fromId(callVibrateState),
|
||||
Util.uri(messageRingtone), Util.uri(callRingtone),
|
||||
@@ -820,6 +887,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(updateQuery, valuesToSet)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
ApplicationDependencies.getJobManager().add(new StorageSyncJob());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -865,6 +933,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
ApplicationDependencies.getJobManager().add(new StorageSyncJob());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,6 +951,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
ApplicationDependencies.getJobManager().add(new StorageSyncJob());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,7 +1017,6 @@ public class RecipientDatabase extends Database {
|
||||
ContentValues contentValues = new ContentValues(3);
|
||||
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
|
||||
contentValues.put(UUID, uuid.toString().toLowerCase());
|
||||
contentValues.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.INSERT);
|
||||
Recipient.live(id).refresh();
|
||||
@@ -962,7 +1031,6 @@ public class RecipientDatabase extends Database {
|
||||
public void markRegistered(@NonNull RecipientId id) {
|
||||
ContentValues contentValues = new ContentValues(2);
|
||||
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
|
||||
contentValues.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.INSERT);
|
||||
Recipient.live(id).refresh();
|
||||
@@ -1010,10 +1078,22 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
@Deprecated
|
||||
public void setRegistered(@NonNull RecipientId id, RegisteredState registeredState) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
ContentValues contentValues = new ContentValues(2);
|
||||
contentValues.put(REGISTERED, registeredState.getId());
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
|
||||
if (registeredState == RegisteredState.REGISTERED) {
|
||||
contentValues.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
}
|
||||
|
||||
if (update(id, contentValues)) {
|
||||
if (registeredState == RegisteredState.REGISTERED) {
|
||||
markDirty(id, DirtyState.INSERT);
|
||||
} else if (registeredState == RegisteredState.NOT_REGISTERED) {
|
||||
markDirty(id, DirtyState.DELETE);
|
||||
}
|
||||
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -1021,10 +1101,11 @@ public class RecipientDatabase extends Database {
|
||||
@NonNull Collection<RecipientId> inactiveIds)
|
||||
{
|
||||
for (RecipientId activeId : activeIds) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
|
||||
ContentValues registeredValues = new ContentValues(1);
|
||||
registeredValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
|
||||
|
||||
if (update(activeId, contentValues)) {
|
||||
if (update(activeId, registeredValues)) {
|
||||
markDirty(activeId, DirtyState.INSERT);
|
||||
Recipient.live(activeId).refresh();
|
||||
}
|
||||
}
|
||||
@@ -1034,6 +1115,7 @@ public class RecipientDatabase extends Database {
|
||||
contentValues.put(REGISTERED, RegisteredState.NOT_REGISTERED.getId());
|
||||
|
||||
if (update(inactiveId, contentValues)) {
|
||||
markDirty(inactiveId, DirtyState.DELETE);
|
||||
Recipient.live(inactiveId).refresh();
|
||||
}
|
||||
}
|
||||
@@ -1282,14 +1364,27 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
|
||||
void markDirty(@NonNull RecipientId recipientId, @NonNull DirtyState dirtyState) {
|
||||
if (!FeatureFlags.storageService()) return;
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(DIRTY, dirtyState.getId());
|
||||
|
||||
String query = ID + " = ? AND (" + UUID + " NOT NULL OR " + PHONE + " NOT NULL) AND " + DIRTY + " < ?";
|
||||
String query = ID + " = ? AND (" + UUID + " NOT NULL OR " + PHONE + " NOT NULL) AND ";
|
||||
String[] args = new String[] { recipientId.serialize(), String.valueOf(dirtyState.id) };
|
||||
|
||||
switch (dirtyState) {
|
||||
case INSERT:
|
||||
query += "(" + DIRTY + " < ? OR " + DIRTY + " = ?)";
|
||||
args = SqlUtil.appendArg(args, String.valueOf(DirtyState.DELETE.getId()));
|
||||
|
||||
contentValues.put(STORAGE_SERVICE_KEY, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
break;
|
||||
case DELETE:
|
||||
query += "(" + DIRTY + " < ? OR " + DIRTY + " = ?)";
|
||||
args = SqlUtil.appendArg(args, String.valueOf(DirtyState.INSERT.getId()));
|
||||
break;
|
||||
default:
|
||||
query += DIRTY + " < ?";
|
||||
}
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, query, args);
|
||||
}
|
||||
|
||||
@@ -1330,7 +1425,7 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull RecipientId getOrInsertByColumn(@NonNull String column, String value) {
|
||||
private @NonNull GetOrInsertResult getOrInsertByColumn(@NonNull String column, String value) {
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
throw new AssertionError(column + " cannot be empty.");
|
||||
}
|
||||
@@ -1338,7 +1433,7 @@ public class RecipientDatabase extends Database {
|
||||
Optional<RecipientId> existing = getByColumn(column, value);
|
||||
|
||||
if (existing.isPresent()) {
|
||||
return existing.get();
|
||||
return new GetOrInsertResult(existing.get(), false);
|
||||
} else {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(column, value);
|
||||
@@ -1349,12 +1444,12 @@ public class RecipientDatabase extends Database {
|
||||
existing = getByColumn(column, value);
|
||||
|
||||
if (existing.isPresent()) {
|
||||
return existing.get();
|
||||
return new GetOrInsertResult(existing.get(), false);
|
||||
} else {
|
||||
throw new AssertionError("Failed to insert recipient!");
|
||||
}
|
||||
} else {
|
||||
return RecipientId.from(id);
|
||||
return new GetOrInsertResult(RecipientId.from(id), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1445,6 +1540,7 @@ public class RecipientDatabase extends Database {
|
||||
private final String e164;
|
||||
private final String email;
|
||||
private final String groupId;
|
||||
private final GroupType groupType;
|
||||
private final boolean blocked;
|
||||
private final long muteUntil;
|
||||
private final VibrateState messageVibrateState;
|
||||
@@ -1479,7 +1575,9 @@ public class RecipientDatabase extends Database {
|
||||
@Nullable String e164,
|
||||
@Nullable String email,
|
||||
@Nullable String groupId,
|
||||
boolean blocked, long muteUntil,
|
||||
@NonNull GroupType groupType,
|
||||
boolean blocked,
|
||||
long muteUntil,
|
||||
@NonNull VibrateState messageVibrateState,
|
||||
@NonNull VibrateState callVibrateState,
|
||||
@Nullable Uri messageRingtone,
|
||||
@@ -1512,6 +1610,7 @@ public class RecipientDatabase extends Database {
|
||||
this.e164 = e164;
|
||||
this.email = email;
|
||||
this.groupId = groupId;
|
||||
this.groupType = groupType;
|
||||
this.blocked = blocked;
|
||||
this.muteUntil = muteUntil;
|
||||
this.messageVibrateState = messageVibrateState;
|
||||
@@ -1565,6 +1664,10 @@ public class RecipientDatabase extends Database {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public @NonNull GroupType getGroupType() {
|
||||
return groupType;
|
||||
}
|
||||
|
||||
public @Nullable MaterialColor getColor() {
|
||||
return color;
|
||||
}
|
||||
@@ -1720,4 +1823,14 @@ public class RecipientDatabase extends Database {
|
||||
super("Failed to find recipient with ID: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetOrInsertResult {
|
||||
final RecipientId recipientId;
|
||||
final boolean neededInsert;
|
||||
|
||||
private GetOrInsertResult(@NonNull RecipientId recipientId, boolean neededInsert) {
|
||||
this.recipientId = recipientId;
|
||||
this.neededInsert = neededInsert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import net.sqlcipher.database.SQLiteDatabase;
|
||||
import net.sqlcipher.database.SQLiteDatabaseHook;
|
||||
import net.sqlcipher.database.SQLiteOpenHelper;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.sync.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
@@ -111,8 +112,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int PROFILE_KEY_TO_DB = 47;
|
||||
private static final int PROFILE_KEY_CREDENTIALS = 48;
|
||||
private static final int ATTACHMENT_FILE_INDEX = 49;
|
||||
private static final int STORAGE_SERVICE_ACTIVE = 50;
|
||||
|
||||
private static final int DATABASE_VERSION = 49;
|
||||
private static final int DATABASE_VERSION = 50;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
@@ -673,20 +675,6 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
db.execSQL("CREATE UNIQUE INDEX recipient_storage_service_key ON recipient (storage_service_key)");
|
||||
db.execSQL("CREATE INDEX recipient_dirty_index ON recipient (dirty)");
|
||||
|
||||
// TODO [greyson] Do this in a future DB migration
|
||||
// db.execSQL("UPDATE recipient SET dirty = 2 WHERE registered = 1");
|
||||
//
|
||||
// try (Cursor cursor = db.rawQuery("SELECT _id FROM recipient WHERE registered = 1", null)) {
|
||||
// while (cursor != null && cursor.moveToNext()) {
|
||||
// String id = cursor.getString(cursor.getColumnIndexOrThrow("_id"));
|
||||
// ContentValues values = new ContentValues(1);
|
||||
//
|
||||
// values.put("storage_service_key", Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
//
|
||||
// db.update("recipient", values, "_id = ?", new String[] { id });
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
if (oldVersion < REACTIONS_UNREAD_INDEX) {
|
||||
@@ -753,6 +741,26 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS part_data_index ON part (_data)");
|
||||
}
|
||||
|
||||
if (oldVersion < STORAGE_SERVICE_ACTIVE) {
|
||||
db.execSQL("ALTER TABLE recipient ADD COLUMN group_type INTEGER DEFAULT 0");
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS recipient_group_type_index ON recipient (group_type)");
|
||||
|
||||
db.execSQL("UPDATE recipient set group_type = 1 WHERE group_id NOT NULL AND group_id LIKE '__signal_mms_group__%'");
|
||||
db.execSQL("UPDATE recipient set group_type = 2 WHERE group_id NOT NULL AND group_id LIKE '__textsecure_group__%'");
|
||||
|
||||
try (Cursor cursor = db.rawQuery("SELECT _id FROM recipient WHERE registered = 1 or group_type = 2", null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
String id = cursor.getString(cursor.getColumnIndexOrThrow("_id"));
|
||||
ContentValues values = new ContentValues(1);
|
||||
|
||||
values.put("dirty", 2);
|
||||
values.put("storage_service_key", Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||
|
||||
db.update("recipient", values, "_id = ?", new String[] { id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
||||
Reference in New Issue
Block a user