mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-19 20:28:29 +00:00
Update group table schema to support GV1->GV2 migration.
Also puts in protections to make sure we don't insert bad recipients or groups.
This commit is contained in:
parent
985a220fca
commit
2d1bf33902
@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.groups.GroupId;
|
|||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
|
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||||
@ -62,6 +63,9 @@ public final class GroupDatabase extends Database {
|
|||||||
private static final String TIMESTAMP = "timestamp";
|
private static final String TIMESTAMP = "timestamp";
|
||||||
static final String ACTIVE = "active";
|
static final String ACTIVE = "active";
|
||||||
static final String MMS = "mms";
|
static final String MMS = "mms";
|
||||||
|
private static final String EXPECTED_V2_ID = "expected_v2_id";
|
||||||
|
private static final String FORMER_V1_MEMBERS = "former_v1_members";
|
||||||
|
|
||||||
|
|
||||||
/* V2 Group columns */
|
/* V2 Group columns */
|
||||||
/** 32 bytes serialized {@link GroupMasterKey} */
|
/** 32 bytes serialized {@link GroupMasterKey} */
|
||||||
@ -71,9 +75,7 @@ public final class GroupDatabase extends Database {
|
|||||||
/** Serialized {@link DecryptedGroup} protobuf */
|
/** Serialized {@link DecryptedGroup} protobuf */
|
||||||
private static final String V2_DECRYPTED_GROUP = "decrypted_group";
|
private static final String V2_DECRYPTED_GROUP = "decrypted_group";
|
||||||
|
|
||||||
public static final String CREATE_TABLE =
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||||
"CREATE TABLE " + TABLE_NAME +
|
|
||||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
|
||||||
GROUP_ID + " TEXT, " +
|
GROUP_ID + " TEXT, " +
|
||||||
RECIPIENT_ID + " INTEGER, " +
|
RECIPIENT_ID + " INTEGER, " +
|
||||||
TITLE + " TEXT, " +
|
TITLE + " TEXT, " +
|
||||||
@ -88,15 +90,18 @@ public final class GroupDatabase extends Database {
|
|||||||
MMS + " INTEGER DEFAULT 0, " +
|
MMS + " INTEGER DEFAULT 0, " +
|
||||||
V2_MASTER_KEY + " BLOB, " +
|
V2_MASTER_KEY + " BLOB, " +
|
||||||
V2_REVISION + " BLOB, " +
|
V2_REVISION + " BLOB, " +
|
||||||
V2_DECRYPTED_GROUP + " BLOB);";
|
V2_DECRYPTED_GROUP + " BLOB, " +
|
||||||
|
EXPECTED_V2_ID + " TEXT DEFAULT NULL, " +
|
||||||
|
FORMER_V1_MEMBERS + " TEXT DEFAULT NULL);";
|
||||||
|
|
||||||
public static final String[] CREATE_INDEXS = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");",
|
"CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");",
|
||||||
"CREATE UNIQUE INDEX IF NOT EXISTS group_recipient_id_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ");",
|
"CREATE UNIQUE INDEX IF NOT EXISTS group_recipient_id_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ");",
|
||||||
|
"CREATE UNIQUE INDEX IF NOT EXISTS expected_v2_id_index ON " + TABLE_NAME + " (" + EXPECTED_V2_ID + ");"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] GROUP_PROJECTION = {
|
private static final String[] GROUP_PROJECTION = {
|
||||||
GROUP_ID, RECIPIENT_ID, TITLE, MEMBERS, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
|
GROUP_ID, RECIPIENT_ID, TITLE, MEMBERS, FORMER_V1_MEMBERS, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
|
||||||
TIMESTAMP, ACTIVE, MMS, V2_MASTER_KEY, V2_REVISION, V2_DECRYPTED_GROUP
|
TIMESTAMP, ACTIVE, MMS, V2_MASTER_KEY, V2_REVISION, V2_DECRYPTED_GROUP
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,7 +134,7 @@ public final class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean findGroup(@NonNull GroupId groupId) {
|
public boolean groupExists(@NonNull GroupId groupId) {
|
||||||
try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
|
try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
|
||||||
new String[] {groupId.toString()},
|
new String[] {groupId.toString()},
|
||||||
null, null, null))
|
null, null, null))
|
||||||
@ -138,6 +143,27 @@ public final class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A gv1 group whose expected v2 ID matches the one provided.
|
||||||
|
*/
|
||||||
|
public Optional<GroupRecord> getGroupV1ByExpectedV2(@NonNull GroupId.V2 gv2Id) {
|
||||||
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
try (Cursor cursor = db.query(TABLE_NAME, GROUP_PROJECTION, EXPECTED_V2_ID + " = ?", SqlUtil.buildArgs(gv2Id), null, null, null)) {
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
return getGroup(cursor);
|
||||||
|
} else {
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearFormerV1Members(@NonNull GroupId.V2 id) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.putNull(FORMER_V1_MEMBERS);
|
||||||
|
|
||||||
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, values, GROUP_ID + " = ?", SqlUtil.buildArgs(id));
|
||||||
|
}
|
||||||
|
|
||||||
Optional<GroupRecord> getGroup(Cursor cursor) {
|
Optional<GroupRecord> getGroup(Cursor cursor) {
|
||||||
Reader reader = new Reader(cursor);
|
Reader reader = new Reader(cursor);
|
||||||
return Optional.fromNullable(reader.getCurrent());
|
return Optional.fromNullable(reader.getCurrent());
|
||||||
@ -320,6 +346,9 @@ public final class GroupDatabase extends Database {
|
|||||||
@Nullable SignalServiceAttachmentPointer avatar,
|
@Nullable SignalServiceAttachmentPointer avatar,
|
||||||
@Nullable String relay)
|
@Nullable String relay)
|
||||||
{
|
{
|
||||||
|
if (groupExists(groupId.deriveV2MigrationGroupId())) {
|
||||||
|
throw new LegacyGroupInsertException(groupId);
|
||||||
|
}
|
||||||
create(groupId, title, members, avatar, relay, null, null);
|
create(groupId, title, members, avatar, relay, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,6 +363,10 @@ public final class GroupDatabase extends Database {
|
|||||||
{
|
{
|
||||||
GroupId.V2 groupId = GroupId.v2(groupMasterKey);
|
GroupId.V2 groupId = GroupId.v2(groupMasterKey);
|
||||||
|
|
||||||
|
if (getGroupV1ByExpectedV2(groupId).isPresent()) {
|
||||||
|
throw new MissedGroupMigrationInsertException(groupId);
|
||||||
|
}
|
||||||
|
|
||||||
create(groupId, groupState.getTitle(), Collections.emptyList(), null, null, groupMasterKey, groupState);
|
create(groupId, groupState.getTitle(), Collections.emptyList(), null, null, groupMasterKey, groupState);
|
||||||
|
|
||||||
return groupId;
|
return groupId;
|
||||||
@ -378,6 +411,7 @@ public final class GroupDatabase extends Database {
|
|||||||
contentValues.put(ACTIVE, groupState != null && gv2GroupActive(groupState) ? 1 : 0);
|
contentValues.put(ACTIVE, groupState != null && gv2GroupActive(groupState) ? 1 : 0);
|
||||||
} else {
|
} else {
|
||||||
contentValues.put(ACTIVE, 1);
|
contentValues.put(ACTIVE, 1);
|
||||||
|
contentValues.put(EXPECTED_V2_ID, groupId.requireV1().deriveV2MigrationGroupId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
contentValues.put(MMS, groupId.isMms());
|
contentValues.put(MMS, groupId.isMms());
|
||||||
@ -630,20 +664,21 @@ public final class GroupDatabase extends Database {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GroupRecord(GroupId.parseOrThrow(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID))),
|
return new GroupRecord(GroupId.parseOrThrow(CursorUtil.requireString(cursor, GROUP_ID)),
|
||||||
RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
RecipientId.from(CursorUtil.requireString(cursor, RECIPIENT_ID)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(TITLE)),
|
CursorUtil.requireString(cursor, TITLE),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)),
|
CursorUtil.requireString(cursor, MEMBERS),
|
||||||
cursor.getLong(cursor.getColumnIndexOrThrow(AVATAR_ID)),
|
CursorUtil.requireString(cursor, FORMER_V1_MEMBERS),
|
||||||
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_KEY)),
|
CursorUtil.requireLong(cursor, AVATAR_ID),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_CONTENT_TYPE)),
|
CursorUtil.requireBlob(cursor, AVATAR_KEY),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_RELAY)),
|
CursorUtil.requireString(cursor, AVATAR_CONTENT_TYPE),
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(ACTIVE)) == 1,
|
CursorUtil.requireString(cursor, AVATAR_RELAY),
|
||||||
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)),
|
CursorUtil.requireBoolean(cursor, ACTIVE),
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(MMS)) == 1,
|
CursorUtil.requireBlob(cursor, AVATAR_DIGEST),
|
||||||
cursor.getBlob(cursor.getColumnIndexOrThrow(V2_MASTER_KEY)),
|
CursorUtil.requireBoolean(cursor, MMS),
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(V2_REVISION)),
|
CursorUtil.requireBlob(cursor, V2_MASTER_KEY),
|
||||||
cursor.getBlob(cursor.getColumnIndexOrThrow(V2_DECRYPTED_GROUP)));
|
CursorUtil.requireInt(cursor, V2_REVISION),
|
||||||
|
CursorUtil.requireBlob(cursor, V2_DECRYPTED_GROUP));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -659,6 +694,7 @@ public final class GroupDatabase extends Database {
|
|||||||
private final RecipientId recipientId;
|
private final RecipientId recipientId;
|
||||||
private final String title;
|
private final String title;
|
||||||
private final List<RecipientId> members;
|
private final List<RecipientId> members;
|
||||||
|
private final List<RecipientId> formerV1Members;
|
||||||
private final long avatarId;
|
private final long avatarId;
|
||||||
private final byte[] avatarKey;
|
private final byte[] avatarKey;
|
||||||
private final byte[] avatarDigest;
|
private final byte[] avatarDigest;
|
||||||
@ -668,10 +704,21 @@ public final class GroupDatabase extends Database {
|
|||||||
private final boolean mms;
|
private final boolean mms;
|
||||||
@Nullable private final V2GroupProperties v2GroupProperties;
|
@Nullable private final V2GroupProperties v2GroupProperties;
|
||||||
|
|
||||||
public GroupRecord(@NonNull GroupId id, @NonNull RecipientId recipientId, String title, String members,
|
public GroupRecord(@NonNull GroupId id,
|
||||||
long avatarId, byte[] avatarKey, String avatarContentType,
|
@NonNull RecipientId recipientId,
|
||||||
String relay, boolean active, byte[] avatarDigest, boolean mms,
|
String title,
|
||||||
@Nullable byte[] groupMasterKeyBytes, int groupRevision, @Nullable byte[] decryptedGroupBytes)
|
String members,
|
||||||
|
String formerV1Members,
|
||||||
|
long avatarId,
|
||||||
|
byte[] avatarKey,
|
||||||
|
String avatarContentType,
|
||||||
|
String relay,
|
||||||
|
boolean active,
|
||||||
|
byte[] avatarDigest,
|
||||||
|
boolean mms,
|
||||||
|
@Nullable byte[] groupMasterKeyBytes,
|
||||||
|
int groupRevision,
|
||||||
|
@Nullable byte[] decryptedGroupBytes)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.recipientId = recipientId;
|
this.recipientId = recipientId;
|
||||||
@ -696,8 +743,17 @@ public final class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
this.v2GroupProperties = v2GroupProperties;
|
this.v2GroupProperties = v2GroupProperties;
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(members)) this.members = RecipientId.fromSerializedList(members);
|
if (!TextUtils.isEmpty(members)) {
|
||||||
else this.members = new LinkedList<>();
|
this.members = RecipientId.fromSerializedList(members);
|
||||||
|
} else {
|
||||||
|
this.members = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(formerV1Members)) {
|
||||||
|
this.formerV1Members = RecipientId.fromSerializedList(formerV1Members);
|
||||||
|
} else {
|
||||||
|
this.formerV1Members = Collections.emptyList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupId getId() {
|
public GroupId getId() {
|
||||||
@ -712,10 +768,14 @@ public final class GroupDatabase extends Database {
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RecipientId> getMembers() {
|
public @NonNull List<RecipientId> getMembers() {
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NonNull List<RecipientId> getFormerV1Members() {
|
||||||
|
return formerV1Members;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasAvatar() {
|
public boolean hasAvatar() {
|
||||||
return avatarId != 0;
|
return avatarId != 0;
|
||||||
}
|
}
|
||||||
@ -952,4 +1012,16 @@ public final class GroupDatabase extends Database {
|
|||||||
return inGroup;
|
return inGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class LegacyGroupInsertException extends IllegalStateException {
|
||||||
|
public LegacyGroupInsertException(@Nullable GroupId id) {
|
||||||
|
super("Tried to create a new GV1 entry when we already had a migrated GV2! " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MissedGroupMigrationInsertException extends IllegalStateException {
|
||||||
|
public MissedGroupMigrationInsertException(@Nullable GroupId id) {
|
||||||
|
super("Tried to create a new GV2 entry when we already had a V1 group that mapped to the new ID! " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -554,27 +554,54 @@ public class RecipientDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull RecipientId getOrInsertFromGroupId(@NonNull GroupId groupId) {
|
public @NonNull RecipientId getOrInsertFromGroupId(@NonNull GroupId groupId) {
|
||||||
GetOrInsertResult result = getOrInsertByColumn(GROUP_ID, groupId.toString());
|
Optional<RecipientId> existing = getByColumn(GROUP_ID, groupId.toString());
|
||||||
|
|
||||||
if (result.neededInsert) {
|
if (existing.isPresent()) {
|
||||||
|
return existing.get();
|
||||||
|
} else if (groupId.isV1() && DatabaseFactory.getGroupDatabase(context).groupExists(groupId.requireV1().deriveV2MigrationGroupId())) {
|
||||||
|
throw new GroupDatabase.LegacyGroupInsertException(groupId);
|
||||||
|
} else if (groupId.isV2() && DatabaseFactory.getGroupDatabase(context).getGroupV1ByExpectedV2(groupId.requireV2()).isPresent()) {
|
||||||
|
throw new GroupDatabase.MissedGroupMigrationInsertException(groupId);
|
||||||
|
} else {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(GROUP_ID, groupId.toString());
|
||||||
|
|
||||||
|
long id = databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
existing = getByColumn(GROUP_ID, groupId.toString());
|
||||||
|
|
||||||
|
if (existing.isPresent()) {
|
||||||
|
return existing.get();
|
||||||
|
} else if (groupId.isV1() && DatabaseFactory.getGroupDatabase(context).groupExists(groupId.requireV1().deriveV2MigrationGroupId())) {
|
||||||
|
throw new GroupDatabase.LegacyGroupInsertException(groupId);
|
||||||
|
} else if (groupId.isV2() && DatabaseFactory.getGroupDatabase(context).getGroupV1ByExpectedV2(groupId.requireV2()).isPresent()) {
|
||||||
|
throw new GroupDatabase.MissedGroupMigrationInsertException(groupId);
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Failed to insert recipient!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ContentValues groupUpdates = new ContentValues();
|
||||||
|
|
||||||
if (groupId.isMms()) {
|
if (groupId.isMms()) {
|
||||||
values.put(GROUP_TYPE, GroupType.MMS.getId());
|
groupUpdates.put(GROUP_TYPE, GroupType.MMS.getId());
|
||||||
} else {
|
} else {
|
||||||
if (groupId.isV2()) {
|
if (groupId.isV2()) {
|
||||||
values.put(GROUP_TYPE, GroupType.SIGNAL_V2.getId());
|
groupUpdates.put(GROUP_TYPE, GroupType.SIGNAL_V2.getId());
|
||||||
} else {
|
} else {
|
||||||
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
groupUpdates.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
||||||
}
|
}
|
||||||
values.put(DIRTY, DirtyState.INSERT.getId());
|
groupUpdates.put(DIRTY, DirtyState.INSERT.getId());
|
||||||
values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
groupUpdates.put(STORAGE_SERVICE_ID, Base64.encodeBytes(StorageSyncHelper.generateKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
update(result.recipientId, values);
|
RecipientId recipientId = RecipientId.from(id);
|
||||||
}
|
|
||||||
|
|
||||||
return result.recipientId;
|
update(recipientId, groupUpdates);
|
||||||
|
|
||||||
|
return recipientId;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor getBlocked() {
|
public Cursor getBlocked() {
|
||||||
|
@ -158,8 +158,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int MENTION_CLEANUP_V2 = 77;
|
private static final int MENTION_CLEANUP_V2 = 77;
|
||||||
private static final int REACTION_CLEANUP = 78;
|
private static final int REACTION_CLEANUP = 78;
|
||||||
private static final int CAPABILITIES_REFACTOR = 79;
|
private static final int CAPABILITIES_REFACTOR = 79;
|
||||||
|
private static final int GV1_MIGRATION = 80;
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 79;
|
private static final int DATABASE_VERSION = 80;
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -1139,6 +1140,26 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL("UPDATE recipient SET capabilities = 2 WHERE gv2_capability = -1");
|
db.execSQL("UPDATE recipient SET capabilities = 2 WHERE gv2_capability = -1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < GV1_MIGRATION) {
|
||||||
|
db.execSQL("ALTER TABLE groups ADD COLUMN expected_v2_id TEXT DEFAULT NULL");
|
||||||
|
db.execSQL("ALTER TABLE groups ADD COLUMN former_v1_members TEXT DEFAULT NULL");
|
||||||
|
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS expected_v2_id_index ON groups (expected_v2_id)");
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
try (Cursor cursor = db.rawQuery("SELECT * FROM groups WHERE group_id LIKE '__textsecure_group__!%' AND LENGTH(group_id) = 53", null)) {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
String gv1 = CursorUtil.requireString(cursor, "group_id");
|
||||||
|
String gv2 = GroupId.parseOrThrow(gv1).requireV1().deriveV2MigrationGroupId().toString();
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put("expected_v2_id", gv2);
|
||||||
|
count += db.update("groups", values, "group_id = ?", SqlUtil.buildArgs(gv1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Updated " + count + " GV1 groups with expected GV2 IDs.");
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -202,7 +202,7 @@ public final class GroupManager {
|
|||||||
public static void updateSelfProfileKeyInGroup(@NonNull Context context, @NonNull GroupId.V2 groupId)
|
public static void updateSelfProfileKeyInGroup(@NonNull Context context, @NonNull GroupId.V2 groupId)
|
||||||
throws IOException, GroupChangeBusyException, GroupInsufficientRightsException, GroupNotAMemberException, GroupChangeFailedException
|
throws IOException, GroupChangeBusyException, GroupInsufficientRightsException, GroupNotAMemberException, GroupChangeFailedException
|
||||||
{
|
{
|
||||||
if (!DatabaseFactory.getGroupDatabase(context).findGroup(groupId)) {
|
if (!DatabaseFactory.getGroupDatabase(context).groupExists(groupId)) {
|
||||||
Log.i(TAG, "Group is not available locally " + groupId);
|
Log.i(TAG, "Group is not available locally " + groupId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user