Add the ability to migrate GV1 groups to GV2.

Co-authored-by: Alan Evans <alan@signal.org>
This commit is contained in:
Greyson Parrelli
2020-10-15 15:49:09 -04:00
committed by Alan Evans
parent 2d1bf33902
commit 6bb9d27d4e
34 changed files with 818 additions and 132 deletions

View File

@@ -13,6 +13,7 @@ import org.json.JSONObject;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.SelectionLimits;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.Log;
@@ -61,6 +62,8 @@ public final class FeatureFlags {
public static final String MODERN_PROFILE_SHARING = "android.modernProfileSharing";
private static final String VIEWED_RECEIPTS = "android.viewed.receipts";
private static final String MAX_ENVELOPE_SIZE = "android.maxEnvelopeSize";
private static final String GV1_AUTO_MIGRATE_VERSION = "android.groupsv2.autoMigrateVersion";
private static final String GV1_MANUAL_MIGRATE_VERSION = "android.groupsv2.manualMigrateVersion";
/**
* We will only store remote values for flags in this set. If you want a flag to be controllable
@@ -79,7 +82,9 @@ public final class FeatureFlags {
RESEARCH_MEGAPHONE_1,
MODERN_PROFILE_SHARING,
VIEWED_RECEIPTS,
MAX_ENVELOPE_SIZE
MAX_ENVELOPE_SIZE,
GV1_AUTO_MIGRATE_VERSION,
GV1_MANUAL_MIGRATE_VERSION
);
/**
@@ -124,6 +129,7 @@ public final class FeatureFlags {
* desired test state.
*/
private static final Map<String, OnFlagChange> FLAG_CHANGE_LISTENERS = new HashMap<String, OnFlagChange>() {{
put(GV1_AUTO_MIGRATE_VERSION, change -> ApplicationDependencies.getJobManager().add(new RefreshAttributesJob()));
}};
private static final Map<String, Object> REMOTE_VALUES = new TreeMap<>();
@@ -257,6 +263,16 @@ public final class FeatureFlags {
return getInteger(MAX_ENVELOPE_SIZE, 0);
}
/** Whether or not auto-migration from GV1->GV2 is enabled. */
public static boolean groupsV1AutoMigration() {
return getVersionFlag(GV1_AUTO_MIGRATE_VERSION) == VersionFlag.ON;
}
/** Whether or not manual migration from GV1->GV2 is enabled. */
public static boolean groupsV1ManualMigration() {
return groupsV1AutoMigration() && getVersionFlag(GV1_MANUAL_MIGRATE_VERSION) == VersionFlag.ON;
}
/** Only for rendering debug info. */
public static synchronized @NonNull Map<String, Object> getMemoryValues() {
return new TreeMap<>(REMOTE_VALUES);

View File

@@ -6,6 +6,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.google.protobuf.ByteString;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.groups.GroupMasterKey;
import org.thoughtcrime.securesms.R;
@@ -15,6 +17,7 @@ import org.thoughtcrime.securesms.groups.BadGroupIdException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -22,8 +25,11 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
public final class GroupUtil {
@@ -108,6 +114,26 @@ public final class GroupUtil {
}
}
public static OutgoingGroupUpdateMessage createGroupV1LeaveMessage(@NonNull GroupId.V1 groupId,
@NonNull Recipient groupRecipient)
{
GroupContext groupContext = GroupContext.newBuilder()
.setId(ByteString.copyFrom(groupId.getDecodedId()))
.setType(GroupContext.Type.QUIT)
.build();
return new OutgoingGroupUpdateMessage(groupRecipient,
groupContext,
null,
System.currentTimeMillis(),
0,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList());
}
public static class GroupDescription {
@NonNull private final Context context;