GroupId for GV2.

This commit is contained in:
Alan Evans
2020-03-27 11:28:48 -03:00
committed by GitHub
parent d8fa46c558
commit 66c7f8bcb2
10 changed files with 358 additions and 62 deletions

View File

@@ -26,7 +26,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin
import java.io.Closeable;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -233,7 +232,7 @@ public class GroupDatabase extends Database {
contentValues.put(AVATAR_RELAY, relay);
contentValues.put(TIMESTAMP, System.currentTimeMillis());
contentValues.put(ACTIVE, 1);
contentValues.put(MMS, groupId.isMmsGroup());
contentValues.put(MMS, groupId.isMms());
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);

View File

@@ -356,7 +356,7 @@ public class RecipientDatabase extends Database {
if (result.neededInsert) {
ContentValues values = new ContentValues();
if (groupId.isMmsGroup()) {
if (groupId.isMms()) {
values.put(GROUP_TYPE, GroupType.MMS.getId());
} else {
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
@@ -1406,9 +1406,9 @@ public class RecipientDatabase extends Database {
db.update(TABLE_NAME, setBlocked, UUID + " = ?", new String[] { uuid });
}
List<GroupId> groupIdStrings = Stream.of(groupIds).map(GroupId::v1).toList();
List<GroupId.V1> groupIdStrings = Stream.of(groupIds).map(GroupId::v1).toList();
for (GroupId groupId : groupIdStrings) {
for (GroupId.V1 groupId : groupIdStrings) {
db.update(TABLE_NAME, setBlocked, GROUP_ID + " = ?", new String[] { groupId.toString() });
}

View File

@@ -3,27 +3,52 @@ package org.thoughtcrime.securesms.groups;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.zkgroup.groups.GroupIdentifier;
import org.signal.zkgroup.groups.GroupMasterKey;
import org.signal.zkgroup.groups.GroupSecretParams;
import org.thoughtcrime.securesms.util.Hex;
import java.io.IOException;
public final class GroupId {
public abstract class GroupId {
private static final String ENCODED_SIGNAL_GROUP_PREFIX = "__textsecure_group__!";
private static final String ENCODED_MMS_GROUP_PREFIX = "__signal_mms_group__!";
private static final int V2_BYTE_LENGTH = GroupIdentifier.SIZE;
private static final int V2_ENCODED_LENGTH = ENCODED_SIGNAL_GROUP_PREFIX.length() + V2_BYTE_LENGTH * 2;
private final String encodedId;
private GroupId(@NonNull String encodedId) {
this.encodedId = encodedId;
private GroupId(@NonNull String prefix, @NonNull byte[] bytes) {
this.encodedId = prefix + Hex.toStringCondensed(bytes);
}
public static @NonNull GroupId v1(byte[] gv1GroupIdBytes) {
return new GroupId(ENCODED_SIGNAL_GROUP_PREFIX + Hex.toStringCondensed(gv1GroupIdBytes));
public static @NonNull GroupId.Mms mms(byte[] mmsGroupIdBytes) {
return new GroupId.Mms(mmsGroupIdBytes);
}
public static @NonNull GroupId mms(byte[] mmsGroupIdBytes) {
return new GroupId(ENCODED_MMS_GROUP_PREFIX + Hex.toStringCondensed(mmsGroupIdBytes));
public static @NonNull GroupId.V1 v1(byte[] gv1GroupIdBytes) {
if (gv1GroupIdBytes.length == V2_BYTE_LENGTH) {
throw new AssertionError();
}
return new GroupId.V1(gv1GroupIdBytes);
}
public static GroupId.V2 v2(@NonNull byte[] bytes) {
if (bytes.length != V2_BYTE_LENGTH) {
throw new AssertionError();
}
return new GroupId.V2(bytes);
}
public static GroupId.V2 v2(@NonNull GroupIdentifier groupIdentifier) {
return v2(groupIdentifier.serialize());
}
public static GroupId.V2 v2(@NonNull GroupMasterKey masterKey) {
return v2(GroupSecretParams.deriveFromMasterKey(masterKey)
.getPublicParams()
.getGroupIdentifier());
}
public static @NonNull GroupId parse(@NonNull String encodedGroupId) {
@@ -33,7 +58,11 @@ public final class GroupId {
}
byte[] bytes = extractDecodedId(encodedGroupId);
return isMmsGroup(encodedGroupId) ? mms(bytes) : v1(bytes);
if (encodedGroupId.startsWith(ENCODED_MMS_GROUP_PREFIX)) return mms(bytes);
else if (encodedGroupId.length() == V2_ENCODED_LENGTH) return v2(bytes);
else return v1(bytes);
} catch (IOException e) {
throw new AssertionError(e);
}
@@ -55,10 +84,6 @@ public final class GroupId {
return Hex.fromStringCondensed(encodedGroupId.split("!", 2)[1]);
}
private static boolean isMmsGroup(@NonNull String groupId) {
return groupId.startsWith(ENCODED_MMS_GROUP_PREFIX);
}
public byte[] getDecodedId() {
try {
return extractDecodedId(encodedId);
@@ -67,10 +92,6 @@ public final class GroupId {
}
}
public boolean isMmsGroup() {
return isMmsGroup(encodedId);
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj instanceof GroupId) {
@@ -90,4 +111,109 @@ public final class GroupId {
public String toString() {
return encodedId;
}
public abstract boolean isMms();
public abstract boolean isV1();
public abstract boolean isV2();
public abstract boolean isPush();
public GroupId.Mms requireMms() {
if (this instanceof GroupId.Mms) return (GroupId.Mms) this;
throw new AssertionError();
}
public GroupId.V1 requireV1() {
if (this instanceof GroupId.V1) return (GroupId.V1) this;
throw new AssertionError();
}
public GroupId.V2 requireV2() {
if (this instanceof GroupId.V2) return (GroupId.V2) this;
throw new AssertionError();
}
public GroupId.Push requirePush() {
if (this instanceof GroupId.Push) return (GroupId.Push) this;
throw new AssertionError();
}
public static final class Mms extends GroupId {
private Mms(@NonNull byte[] bytes) {
super(ENCODED_MMS_GROUP_PREFIX, bytes);
}
@Override
public boolean isMms() {
return true;
}
@Override
public boolean isV1() {
return false;
}
@Override
public boolean isV2() {
return false;
}
@Override
public boolean isPush() {
return false;
}
}
public static abstract class Push extends GroupId {
private Push(@NonNull byte[] bytes) {
super(ENCODED_SIGNAL_GROUP_PREFIX, bytes);
}
@Override
public boolean isMms() {
return false;
}
@Override
public boolean isPush() {
return true;
}
}
public static final class V1 extends GroupId.Push {
private V1(@NonNull byte[] bytes) {
super(bytes);
}
@Override
public boolean isV1() {
return true;
}
@Override
public boolean isV2() {
return false;
}
}
public static final class V2 extends GroupId.Push {
private V2(@NonNull byte[] bytes) {
super(bytes);
}
@Override
public boolean isV1() {
return false;
}
@Override
public boolean isV2() {
return true;
}
}
}

View File

@@ -53,7 +53,7 @@ public final class GroupManager {
public static boolean leaveGroup(@NonNull Context context, @NonNull Recipient groupRecipient) {
GroupId groupId = groupRecipient.requireGroupId();
return V1GroupManager.leaveGroup(context, groupId, groupRecipient);
return V1GroupManager.leaveGroup(context, groupId.requireV1(), groupRecipient);
}
public static class GroupActionResult {

View File

@@ -68,7 +68,7 @@ final class V1GroupManager {
}
groupDatabase.onAvatarUpdated(groupId, avatarBytes != null);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
return sendGroupUpdate(context, groupId, memberIds, name, avatarBytes);
return sendGroupUpdate(context, groupId.requireV1(), memberIds, name, avatarBytes);
} else {
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
return new GroupActionResult(groupRecipient, threadId);
@@ -91,13 +91,13 @@ final class V1GroupManager {
groupDatabase.updateTitle(groupId, name);
groupDatabase.onAvatarUpdated(groupId, avatarBytes != null);
if (!groupId.isMmsGroup()) {
if (groupId.isPush()) {
try {
AvatarHelper.setAvatar(context, groupRecipientId, avatarBytes != null ? new ByteArrayInputStream(avatarBytes) : null);
} catch (IOException e) {
Log.w(TAG, "Failed to save avatar!", e);
}
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes);
return sendGroupUpdate(context, groupId.requireV1(), memberAddresses, name, avatarBytes);
} else {
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
@@ -106,7 +106,7 @@ final class V1GroupManager {
}
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
@NonNull GroupId groupId,
@NonNull GroupId.V1 groupId,
@NonNull Set<RecipientId> members,
@Nullable String groupName,
@Nullable byte[] avatar)
@@ -143,7 +143,7 @@ final class V1GroupManager {
}
@WorkerThread
static boolean leaveGroup(@NonNull Context context, @NonNull GroupId groupId, @NonNull Recipient groupRecipient) {
static boolean leaveGroup(@NonNull Context context, @NonNull GroupId.V1 groupId, @NonNull Recipient groupRecipient) {
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);

View File

@@ -51,7 +51,7 @@ public class LeaveGroupJob extends BaseJob {
private static final String KEY_MEMBERS = "members";
private static final String KEY_RECIPIENTS = "recipients";
private final GroupId groupId;
private final GroupId.Push groupId;
private final String name;
private final List<RecipientId> members;
private final List<RecipientId> recipients;
@@ -60,7 +60,7 @@ public class LeaveGroupJob extends BaseJob {
List<RecipientId> members = Stream.of(group.resolve().getParticipants()).map(Recipient::getId).toList();
members.remove(Recipient.self().getId());
return new LeaveGroupJob(group.getGroupId().get(),
return new LeaveGroupJob(group.getGroupId().get().requirePush(),
group.resolve().getDisplayName(ApplicationDependencies.getApplication()),
members,
members,
@@ -72,7 +72,7 @@ public class LeaveGroupJob extends BaseJob {
.build());
}
private LeaveGroupJob(@NonNull GroupId groupId,
private LeaveGroupJob(@NonNull GroupId.Push groupId,
@NonNull String name,
@NonNull List<RecipientId> members,
@NonNull List<RecipientId> recipients,

View File

@@ -197,7 +197,7 @@ public final class LiveRecipient {
List<Recipient> members = Stream.of(groupRecord.get().getMembers()).filterNot(RecipientId::isUnknown).map(this::fetchRecipientFromDisk).toList();
Optional<Long> avatarId = Optional.absent();
if (settings.getGroupId() != null && !settings.getGroupId().isMmsGroup() && title == null) {
if (settings.getGroupId() != null && settings.getGroupId().isPush() && title == null) {
title = unnamedGroupName;
}

View File

@@ -381,7 +381,7 @@ public class Recipient {
}
public @Nullable String getName(@NonNull Context context) {
if (this.name == null && groupId != null && groupId.isMmsGroup()) {
if (this.name == null && groupId != null && groupId.isMms()) {
List<String> names = new LinkedList<>();
for (Recipient recipient : participants) {
@@ -567,12 +567,12 @@ public class Recipient {
public boolean isMmsGroup() {
GroupId groupId = resolve().groupId;
return groupId != null && groupId.isMmsGroup();
return groupId != null && groupId.isMms();
}
public boolean isPushGroup() {
GroupId groupId = resolve().groupId;
return groupId != null && !groupId.isMmsGroup();
return groupId != null && groupId.isPush();
}
public @NonNull List<Recipient> getParticipants() {