mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Improve handling of membership changes during a GV1->GV2 migration.
This commit is contained in:
committed by
Alex Hart
parent
d4748efd42
commit
3804a89619
@@ -24,11 +24,13 @@ import org.signal.zkgroup.groups.GroupMasterKey;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.tracing.Trace;
|
||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.SetUtil;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@@ -486,11 +488,12 @@ public final class GroupDatabase extends Database {
|
||||
* Migrates a V1 group to a V2 group.
|
||||
*
|
||||
* @param decryptedGroup The state that represents the group on the server. This will be used to
|
||||
* determine if we need to save our old membership list and stuff. It will
|
||||
* *not* be stored as the definitive group state as-is. In order to ensure
|
||||
* proper diffing, we modify this model to have our V1 membership.
|
||||
* determine if we need to save our old membership list and stuff.
|
||||
*/
|
||||
public @NonNull GroupId.V2 migrateToV2(@NonNull GroupId.V1 groupIdV1, @NonNull DecryptedGroup decryptedGroup) {
|
||||
public @NonNull GroupId.V2 migrateToV2(long threadId,
|
||||
@NonNull GroupId.V1 groupIdV1,
|
||||
@NonNull DecryptedGroup decryptedGroup)
|
||||
{
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
GroupId.V2 groupIdV2 = groupIdV1.deriveV2MigrationGroupId();
|
||||
GroupMasterKey groupMasterKey = groupIdV1.deriveV2MigrationMasterKey();
|
||||
@@ -504,10 +507,13 @@ public final class GroupDatabase extends Database {
|
||||
contentValues.put(V2_MASTER_KEY, groupMasterKey.serialize());
|
||||
contentValues.putNull(EXPECTED_V2_ID);
|
||||
|
||||
List<RecipientId> newMembers = Stream.of(DecryptedGroupUtil.membersToUuidList(decryptedGroup.getMembersList())).map(u -> RecipientId.from(u, null)).toList();
|
||||
newMembers.addAll(Stream.of(DecryptedGroupUtil.pendingToUuidList(decryptedGroup.getPendingMembersList())).map(u -> RecipientId.from(u, null)).toList());
|
||||
List<RecipientId> newMembers = Stream.of(DecryptedGroupUtil.membersToUuidList(decryptedGroup.getMembersList())).map(u -> RecipientId.from(u, null)).toList();
|
||||
List<RecipientId> pendingMembers = Stream.of(DecryptedGroupUtil.pendingToUuidList(decryptedGroup.getPendingMembersList())).map(u -> RecipientId.from(u, null)).toList();
|
||||
List<RecipientId> droppedMembers = new ArrayList<>(SetUtil.difference(record.getMembers(), newMembers));
|
||||
|
||||
if (record.getMembers().size() > newMembers.size() || !newMembers.containsAll(record.getMembers())) {
|
||||
newMembers.addAll(pendingMembers);
|
||||
|
||||
if (droppedMembers.size() > 0) {
|
||||
contentValues.put(FORMER_V1_MEMBERS, RecipientId.toSerializedList(record.getMembers()));
|
||||
}
|
||||
|
||||
@@ -519,7 +525,11 @@ public final class GroupDatabase extends Database {
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).updateGroupId(groupIdV1, groupIdV2);
|
||||
|
||||
update(groupMasterKey, updateToHaveV1Membership(decryptedGroup, record.getMembers()));
|
||||
update(groupMasterKey, decryptedGroup);
|
||||
|
||||
DatabaseFactory.getSmsDatabase(context).insertGroupV1MigrationEvents(record.getRecipientId(),
|
||||
threadId,
|
||||
new GroupMigrationMembershipChange(pendingMembers, droppedMembers));
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
@@ -529,23 +539,6 @@ public final class GroupDatabase extends Database {
|
||||
return groupIdV2;
|
||||
}
|
||||
|
||||
private static DecryptedGroup updateToHaveV1Membership(@NonNull DecryptedGroup serverGroup, @NonNull List<RecipientId> v1Members) {
|
||||
DecryptedGroup.Builder builder = serverGroup.toBuilder();
|
||||
builder.clearMembers();
|
||||
|
||||
for (RecipientId v1MemberId : v1Members) {
|
||||
Recipient v1Member = Recipient.resolved(v1MemberId);
|
||||
if (v1Member.hasUuid()) {
|
||||
builder.addMembers(DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(v1Member.getUuid().get()))
|
||||
.setRole(Member.Role.ADMINISTRATOR)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void update(@NonNull GroupMasterKey groupMasterKey, @NonNull DecryptedGroup decryptedGroup) {
|
||||
update(GroupId.v2(groupMasterKey), decryptedGroup);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ReactionList;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.insights.InsightsConstants;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
@@ -148,7 +149,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||
public abstract long insertMessageOutbox(@NonNull OutgoingMediaMessage message, long threadId, boolean forceSms, @Nullable SmsDatabase.InsertListener insertListener) throws MmsException;
|
||||
public abstract long insertMessageOutbox(@NonNull OutgoingMediaMessage message, long threadId, boolean forceSms, int defaultReceiptStatus, @Nullable SmsDatabase.InsertListener insertListener) throws MmsException;
|
||||
public abstract void insertProfileNameChangeMessages(@NonNull Recipient recipient, @NonNull String newProfileName, @NonNull String previousProfileName);
|
||||
public abstract void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId, long threadId, List<RecipientId> pendingRecipients);
|
||||
public abstract void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId, long threadId, @NonNull GroupMigrationMembershipChange membershipChange);
|
||||
|
||||
public abstract boolean deleteMessage(long messageId);
|
||||
abstract void deleteThread(long threadId);
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
@@ -494,7 +495,10 @@ public class MmsDatabase extends MessageDatabase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId, long threadId, List<RecipientId> pendingRecipients) {
|
||||
public void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId,
|
||||
long threadId,
|
||||
@NonNull GroupMigrationMembershipChange membershipChange)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
@@ -72,7 +73,6 @@ import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -862,11 +862,14 @@ public class SmsDatabase extends MessageDatabase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId, long threadId, @NonNull List<RecipientId> pendingRecipients) {
|
||||
public void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId,
|
||||
long threadId,
|
||||
@NonNull GroupMigrationMembershipChange membershipChange)
|
||||
{
|
||||
insertGroupV1MigrationNotification(recipientId, threadId);
|
||||
|
||||
if (pendingRecipients.size() > 0) {
|
||||
insertGroupV1MigrationEvent(recipientId, threadId, pendingRecipients);
|
||||
if (!membershipChange.isEmpty()) {
|
||||
insertGroupV1MigrationMembershipChanges(recipientId, threadId, membershipChange);
|
||||
}
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
@@ -874,10 +877,13 @@ public class SmsDatabase extends MessageDatabase {
|
||||
}
|
||||
|
||||
private void insertGroupV1MigrationNotification(@NonNull RecipientId recipientId, long threadId) {
|
||||
insertGroupV1MigrationEvent(recipientId, threadId, Collections.emptyList());
|
||||
insertGroupV1MigrationMembershipChanges(recipientId, threadId, GroupMigrationMembershipChange.empty());
|
||||
}
|
||||
|
||||
private void insertGroupV1MigrationEvent(@NonNull RecipientId recipientId, long threadId, @NonNull List<RecipientId> pendingRecipients) {
|
||||
private void insertGroupV1MigrationMembershipChanges(@NonNull RecipientId recipientId,
|
||||
long threadId,
|
||||
@NonNull GroupMigrationMembershipChange membershipChange)
|
||||
{
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
@@ -887,8 +893,8 @@ public class SmsDatabase extends MessageDatabase {
|
||||
values.put(TYPE, Types.GV1_MIGRATION_TYPE);
|
||||
values.put(THREAD_ID, threadId);
|
||||
|
||||
if (pendingRecipients.size() > 0) {
|
||||
values.put(BODY, RecipientId.toSerializedList(pendingRecipients));
|
||||
if (!membershipChange.isEmpty()) {
|
||||
values.put(BODY, membershipChange.serialize());
|
||||
}
|
||||
|
||||
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -54,6 +55,7 @@ import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -186,12 +188,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
if (isOutgoing()) return staticUpdateDescription(context.getString(R.string.SmsMessageRecord_secure_session_reset), R.drawable.ic_update_info_16);
|
||||
else return fromRecipient(getIndividualRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
} else if (isGroupV1MigrationEvent()) {
|
||||
if (Util.isEmpty(getBody())) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_this_group_was_updated_to_a_new_group), R.drawable.ic_update_group_role_16);
|
||||
} else {
|
||||
int count = getGroupV1MigrationEventInvites().size();
|
||||
return staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, count, count), R.drawable.ic_update_group_add_16);
|
||||
}
|
||||
return getGroupMigrationEventDescription(context);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -288,6 +285,30 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return context.getString(R.string.MessageRecord_changed_their_profile, getIndividualRecipient().getDisplayName(context));
|
||||
}
|
||||
|
||||
private UpdateDescription getGroupMigrationEventDescription(@NonNull Context context) {
|
||||
if (Util.isEmpty(getBody())) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_this_group_was_updated_to_a_new_group), R.drawable.ic_update_group_role_16);
|
||||
} else {
|
||||
GroupMigrationMembershipChange change = getGroupV1MigrationMembershipChanges();
|
||||
List<UpdateDescription> updates = new ArrayList<>(2);
|
||||
|
||||
if (change.getPending().size() == 1 && change.getPending().get(0).equals(Recipient.self().getId())) {
|
||||
updates.add(staticUpdateDescription(context.getString(R.string.MessageRecord_you_couldnt_be_added_to_the_new_group_and_have_been_invited_to_join), R.drawable.ic_update_group_add_16));
|
||||
} else if (change.getPending().size() > 0) {
|
||||
int count = change.getPending().size();
|
||||
updates.add(staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, count, count), R.drawable.ic_update_group_add_16));
|
||||
}
|
||||
|
||||
if (change.getDropped().size() > 0) {
|
||||
int count = change.getDropped().size();
|
||||
updates.add(staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, count, count), R.drawable.ic_update_group_remove_16));
|
||||
}
|
||||
|
||||
return UpdateDescription.concatWithNewLines(updates);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body) {
|
||||
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body);
|
||||
|
||||
@@ -380,11 +401,11 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return SmsDatabase.Types.isGroupV1MigrationEvent(type);
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientId> getGroupV1MigrationEventInvites() {
|
||||
public @NonNull GroupMigrationMembershipChange getGroupV1MigrationMembershipChanges() {
|
||||
if (isGroupV1MigrationEvent()) {
|
||||
return RecipientId.fromSerializedList(getBody());
|
||||
return GroupMigrationMembershipChange.deserialize(getBody());
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
return GroupMigrationMembershipChange.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user