Update the storage service.

This commit is contained in:
Greyson Parrelli
2020-02-10 13:42:43 -05:00
parent 133bd44b85
commit 6184e5f828
44 changed files with 1592 additions and 431 deletions

View File

@@ -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;
}
}
}

View File

@@ -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();