mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-30 11:00:38 +00:00
Refactor to use GroupId class to wrap the byte array
Helps distinguish between group v1 and v2 ids
This commit is contained in:
parent
67f62947c6
commit
9942d967a4
31 changed files with 358 additions and 228 deletions
63
src/main/java/org/asamk/signal/manager/GroupId.java
Normal file
63
src/main/java/org/asamk/signal/manager/GroupId.java
Normal file
|
@ -0,0 +1,63 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class GroupId {
|
||||
|
||||
private final byte[] id;
|
||||
|
||||
public static GroupIdV1 v1(byte[] id) {
|
||||
return new GroupIdV1(id);
|
||||
}
|
||||
|
||||
public static GroupIdV2 v2(byte[] id) {
|
||||
return new GroupIdV2(id);
|
||||
}
|
||||
|
||||
public static GroupId unknownVersion(byte[] id) {
|
||||
if (id.length == 16) {
|
||||
return new GroupIdV1(id);
|
||||
} else if (id.length == 32) {
|
||||
return new GroupIdV2(id);
|
||||
}
|
||||
|
||||
throw new AssertionError("Invalid group id of size " + id.length);
|
||||
}
|
||||
|
||||
public static GroupId fromBase64(String id) throws GroupIdFormatException {
|
||||
try {
|
||||
return unknownVersion(java.util.Base64.getDecoder().decode(id));
|
||||
} catch (Throwable e) {
|
||||
throw new GroupIdFormatException(id, e);
|
||||
}
|
||||
}
|
||||
|
||||
public GroupId(final byte[] id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte[] serialize() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String toBase64() {
|
||||
return Base64.encodeBytes(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final GroupId groupId = (GroupId) o;
|
||||
|
||||
return Arrays.equals(id, groupId.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
public class GroupIdFormatException extends Exception {
|
||||
|
||||
public GroupIdFormatException(String groupId, Throwable e) {
|
||||
super("Failed to decode groupId (must be base64) \"" + groupId + "\": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
14
src/main/java/org/asamk/signal/manager/GroupIdV1.java
Normal file
14
src/main/java/org/asamk/signal/manager/GroupIdV1.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import static org.asamk.signal.manager.KeyUtils.getSecretBytes;
|
||||
|
||||
public class GroupIdV1 extends GroupId {
|
||||
|
||||
public static GroupIdV1 createRandom() {
|
||||
return new GroupIdV1(getSecretBytes(16));
|
||||
}
|
||||
|
||||
public GroupIdV1(final byte[] id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
14
src/main/java/org/asamk/signal/manager/GroupIdV2.java
Normal file
14
src/main/java/org/asamk/signal/manager/GroupIdV2.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class GroupIdV2 extends GroupId {
|
||||
|
||||
public static GroupIdV2 fromBase64(String groupId) {
|
||||
return new GroupIdV2(Base64.getDecoder().decode(groupId));
|
||||
}
|
||||
|
||||
public GroupIdV2(final byte[] id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
public class GroupNotFoundException extends Exception {
|
||||
|
||||
public GroupNotFoundException(byte[] groupId) {
|
||||
super("Group not found: " + Base64.encodeBytes(groupId));
|
||||
public GroupNotFoundException(GroupId groupId) {
|
||||
super("Group not found: " + groupId.toBase64());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.signal.zkgroup.groups.GroupSecretParams;
|
|||
import org.whispersystems.libsignal.kdf.HKDFv3;
|
||||
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;
|
||||
|
||||
public class GroupUtils {
|
||||
|
@ -18,7 +19,7 @@ public class GroupUtils {
|
|||
) {
|
||||
if (groupInfo instanceof GroupInfoV1) {
|
||||
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.DELIVER)
|
||||
.withId(groupInfo.groupId)
|
||||
.withId(groupInfo.getGroupId().serialize())
|
||||
.build();
|
||||
messageBuilder.asGroupMessage(group);
|
||||
} else {
|
||||
|
@ -30,14 +31,34 @@ public class GroupUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static byte[] getGroupId(GroupMasterKey groupMasterKey) {
|
||||
final GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
|
||||
return groupSecretParams.getPublicParams().getGroupIdentifier().serialize();
|
||||
public static GroupId getGroupId(SignalServiceGroupContext context) {
|
||||
if (context.getGroupV1().isPresent()) {
|
||||
return GroupId.v1(context.getGroupV1().get().getGroupId());
|
||||
} else if (context.getGroupV2().isPresent()) {
|
||||
return getGroupIdV2(context.getGroupV2().get().getMasterKey());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static GroupMasterKey deriveV2MigrationMasterKey(byte[] groupIdV1) {
|
||||
public static GroupIdV2 getGroupIdV2(GroupSecretParams groupSecretParams) {
|
||||
return GroupId.v2(groupSecretParams.getPublicParams().getGroupIdentifier().serialize());
|
||||
}
|
||||
|
||||
public static GroupIdV2 getGroupIdV2(GroupMasterKey groupMasterKey) {
|
||||
final GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
|
||||
return getGroupIdV2(groupSecretParams);
|
||||
}
|
||||
|
||||
public static GroupIdV2 getGroupIdV2(GroupIdV1 groupIdV1) {
|
||||
final GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(deriveV2MigrationMasterKey(
|
||||
groupIdV1));
|
||||
return getGroupIdV2(groupSecretParams);
|
||||
}
|
||||
|
||||
private static GroupMasterKey deriveV2MigrationMasterKey(GroupIdV1 groupIdV1) {
|
||||
try {
|
||||
return new GroupMasterKey(new HKDFv3().deriveSecrets(groupIdV1,
|
||||
return new GroupMasterKey(new HKDFv3().deriveSecrets(groupIdV1.serialize(),
|
||||
"GV2 Migration".getBytes(),
|
||||
GroupMasterKey.SIZE));
|
||||
} catch (InvalidInputException e) {
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.asamk.signal.manager;
|
|||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
interface HandleAction {
|
||||
|
@ -93,9 +92,9 @@ class SendSyncBlockedListAction implements HandleAction {
|
|||
class SendGroupInfoRequestAction implements HandleAction {
|
||||
|
||||
private final SignalServiceAddress address;
|
||||
private final byte[] groupId;
|
||||
private final GroupIdV1 groupId;
|
||||
|
||||
public SendGroupInfoRequestAction(final SignalServiceAddress address, final byte[] groupId) {
|
||||
public SendGroupInfoRequestAction(final SignalServiceAddress address, final GroupIdV1 groupId) {
|
||||
this.address = address;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
@ -109,14 +108,17 @@ class SendGroupInfoRequestAction implements HandleAction {
|
|||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final SendGroupInfoRequestAction that = (SendGroupInfoRequestAction) o;
|
||||
return address.equals(that.address) && Arrays.equals(groupId, that.groupId);
|
||||
|
||||
if (!address.equals(that.address)) return false;
|
||||
return groupId.equals(that.groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(address);
|
||||
result = 31 * result + Arrays.hashCode(groupId);
|
||||
int result = address.hashCode();
|
||||
result = 31 * result + groupId.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -124,9 +126,9 @@ class SendGroupInfoRequestAction implements HandleAction {
|
|||
class SendGroupUpdateAction implements HandleAction {
|
||||
|
||||
private final SignalServiceAddress address;
|
||||
private final byte[] groupId;
|
||||
private final GroupIdV1 groupId;
|
||||
|
||||
public SendGroupUpdateAction(final SignalServiceAddress address, final byte[] groupId) {
|
||||
public SendGroupUpdateAction(final SignalServiceAddress address, final GroupIdV1 groupId) {
|
||||
this.address = address;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
@ -140,14 +142,17 @@ class SendGroupUpdateAction implements HandleAction {
|
|||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final SendGroupUpdateAction that = (SendGroupUpdateAction) o;
|
||||
return address.equals(that.address) && Arrays.equals(groupId, that.groupId);
|
||||
|
||||
if (!address.equals(that.address)) return false;
|
||||
return groupId.equals(that.groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(address);
|
||||
result = 31 * result + Arrays.hashCode(groupId);
|
||||
int result = address.hashCode();
|
||||
result = 31 * result + groupId.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,6 @@ class KeyUtils {
|
|||
return getSecret(18);
|
||||
}
|
||||
|
||||
static byte[] createGroupId() {
|
||||
return getSecretBytes(16);
|
||||
}
|
||||
|
||||
static byte[] createStickerUploadKey() {
|
||||
return getSecretBytes(32);
|
||||
}
|
||||
|
|
|
@ -679,7 +679,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
private Optional<SignalServiceAttachmentStream> createGroupAvatarAttachment(byte[] groupId) throws IOException {
|
||||
private Optional<SignalServiceAttachmentStream> createGroupAvatarAttachment(GroupId groupId) throws IOException {
|
||||
File file = getGroupAvatarFile(groupId);
|
||||
if (!file.exists()) {
|
||||
return Optional.absent();
|
||||
|
@ -697,7 +697,7 @@ public class Manager implements Closeable {
|
|||
return Optional.of(Utils.createAttachment(file));
|
||||
}
|
||||
|
||||
private GroupInfo getGroupForSending(byte[] groupId) throws GroupNotFoundException, NotAGroupMemberException {
|
||||
private GroupInfo getGroupForSending(GroupId groupId) throws GroupNotFoundException, NotAGroupMemberException {
|
||||
GroupInfo g = account.getGroupStore().getGroup(groupId);
|
||||
if (g == null) {
|
||||
throw new GroupNotFoundException(groupId);
|
||||
|
@ -708,7 +708,7 @@ public class Manager implements Closeable {
|
|||
return g;
|
||||
}
|
||||
|
||||
private GroupInfo getGroupForUpdating(byte[] groupId) throws GroupNotFoundException, NotAGroupMemberException {
|
||||
private GroupInfo getGroupForUpdating(GroupId groupId) throws GroupNotFoundException, NotAGroupMemberException {
|
||||
GroupInfo g = account.getGroupStore().getGroup(groupId);
|
||||
if (g == null) {
|
||||
throw new GroupNotFoundException(groupId);
|
||||
|
@ -724,7 +724,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
public Pair<Long, List<SendMessageResult>> sendGroupMessage(
|
||||
SignalServiceDataMessage.Builder messageBuilder, byte[] groupId
|
||||
SignalServiceDataMessage.Builder messageBuilder, GroupId groupId
|
||||
) throws IOException, GroupNotFoundException, NotAGroupMemberException {
|
||||
final GroupInfo g = getGroupForSending(groupId);
|
||||
|
||||
|
@ -735,7 +735,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
public Pair<Long, List<SendMessageResult>> sendGroupMessage(
|
||||
String messageText, List<String> attachments, byte[] groupId
|
||||
String messageText, List<String> attachments, GroupId groupId
|
||||
) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
|
||||
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
|
||||
.withBody(messageText);
|
||||
|
@ -747,7 +747,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
public Pair<Long, List<SendMessageResult>> sendGroupMessageReaction(
|
||||
String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, byte[] groupId
|
||||
String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, GroupId groupId
|
||||
) throws IOException, InvalidNumberException, NotAGroupMemberException, GroupNotFoundException {
|
||||
SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji,
|
||||
remove,
|
||||
|
@ -759,7 +759,7 @@ public class Manager implements Closeable {
|
|||
return sendGroupMessage(messageBuilder, groupId);
|
||||
}
|
||||
|
||||
public Pair<Long, List<SendMessageResult>> sendQuitGroupMessage(byte[] groupId) throws GroupNotFoundException, IOException, NotAGroupMemberException {
|
||||
public Pair<Long, List<SendMessageResult>> sendQuitGroupMessage(GroupId groupId) throws GroupNotFoundException, IOException, NotAGroupMemberException {
|
||||
|
||||
SignalServiceDataMessage.Builder messageBuilder;
|
||||
|
||||
|
@ -767,7 +767,7 @@ public class Manager implements Closeable {
|
|||
if (g instanceof GroupInfoV1) {
|
||||
GroupInfoV1 groupInfoV1 = (GroupInfoV1) g;
|
||||
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.QUIT)
|
||||
.withId(groupId)
|
||||
.withId(groupId.serialize())
|
||||
.build();
|
||||
messageBuilder = SignalServiceDataMessage.newBuilder().asGroupMessage(group);
|
||||
groupInfoV1.removeMember(account.getSelfAddress());
|
||||
|
@ -783,8 +783,8 @@ public class Manager implements Closeable {
|
|||
return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfAddress()));
|
||||
}
|
||||
|
||||
private Pair<byte[], List<SendMessageResult>> sendUpdateGroupMessage(
|
||||
byte[] groupId, String name, Collection<SignalServiceAddress> members, String avatarFile
|
||||
private Pair<GroupId, List<SendMessageResult>> sendUpdateGroupMessage(
|
||||
GroupId groupId, String name, Collection<SignalServiceAddress> members, String avatarFile
|
||||
) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
|
||||
GroupInfo g;
|
||||
SignalServiceDataMessage.Builder messageBuilder;
|
||||
|
@ -792,7 +792,7 @@ public class Manager implements Closeable {
|
|||
// Create new group
|
||||
GroupInfoV2 gv2 = groupHelper.createGroupV2(name, members, avatarFile);
|
||||
if (gv2 == null) {
|
||||
GroupInfoV1 gv1 = new GroupInfoV1(KeyUtils.createGroupId());
|
||||
GroupInfoV1 gv1 = new GroupInfoV1(GroupIdV1.createRandom());
|
||||
gv1.addMembers(Collections.singleton(account.getSelfAddress()));
|
||||
updateGroupV1(gv1, name, members, avatarFile);
|
||||
messageBuilder = getGroupUpdateMessageBuilder(gv1);
|
||||
|
@ -834,7 +834,7 @@ public class Manager implements Closeable {
|
|||
groupGroupChangePair.second());
|
||||
}
|
||||
|
||||
return new Pair<>(group.groupId, result.second());
|
||||
return new Pair<>(group.getGroupId(), result.second());
|
||||
} else {
|
||||
GroupInfoV1 gv1 = (GroupInfoV1) group;
|
||||
updateGroupV1(gv1, name, members, avatarFile);
|
||||
|
@ -847,16 +847,16 @@ public class Manager implements Closeable {
|
|||
|
||||
final Pair<Long, List<SendMessageResult>> result = sendMessage(messageBuilder,
|
||||
g.getMembersIncludingPendingWithout(account.getSelfAddress()));
|
||||
return new Pair<>(g.groupId, result.second());
|
||||
return new Pair<>(g.getGroupId(), result.second());
|
||||
}
|
||||
|
||||
public Pair<byte[], List<SendMessageResult>> joinGroup(
|
||||
public Pair<GroupId, List<SendMessageResult>> joinGroup(
|
||||
GroupInviteLinkUrl inviteLinkUrl
|
||||
) throws IOException, GroupLinkNotActiveException {
|
||||
return sendJoinGroupMessage(inviteLinkUrl);
|
||||
}
|
||||
|
||||
private Pair<byte[], List<SendMessageResult>> sendJoinGroupMessage(
|
||||
private Pair<GroupId, List<SendMessageResult>> sendJoinGroupMessage(
|
||||
GroupInviteLinkUrl inviteLinkUrl
|
||||
) throws IOException, GroupLinkNotActiveException {
|
||||
final DecryptedGroupJoinInfo groupJoinInfo = groupHelper.getDecryptedGroupJoinInfo(inviteLinkUrl.getGroupMasterKey(),
|
||||
|
@ -870,12 +870,12 @@ public class Manager implements Closeable {
|
|||
|
||||
if (group.getGroup() == null) {
|
||||
// Only requested member, can't send update to group members
|
||||
return new Pair<>(group.groupId, List.of());
|
||||
return new Pair<>(group.getGroupId(), List.of());
|
||||
}
|
||||
|
||||
final Pair<Long, List<SendMessageResult>> result = sendUpdateGroupMessage(group, group.getGroup(), groupChange);
|
||||
|
||||
return new Pair<>(group.groupId, result.second());
|
||||
return new Pair<>(group.getGroupId(), result.second());
|
||||
}
|
||||
|
||||
private Pair<Long, List<SendMessageResult>> sendUpdateGroupMessage(
|
||||
|
@ -923,13 +923,13 @@ public class Manager implements Closeable {
|
|||
|
||||
if (avatarFile != null) {
|
||||
IOUtils.createPrivateDirectories(pathConfig.getAvatarsPath());
|
||||
File aFile = getGroupAvatarFile(g.groupId);
|
||||
File aFile = getGroupAvatarFile(g.getGroupId());
|
||||
Files.copy(Paths.get(avatarFile), aFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
Pair<Long, List<SendMessageResult>> sendUpdateGroupMessage(
|
||||
byte[] groupId, SignalServiceAddress recipient
|
||||
GroupIdV1 groupId, SignalServiceAddress recipient
|
||||
) throws IOException, NotAGroupMemberException, GroupNotFoundException, AttachmentInvalidException {
|
||||
GroupInfoV1 g;
|
||||
GroupInfo group = getGroupForSending(groupId);
|
||||
|
@ -950,11 +950,11 @@ public class Manager implements Closeable {
|
|||
|
||||
private SignalServiceDataMessage.Builder getGroupUpdateMessageBuilder(GroupInfoV1 g) throws AttachmentInvalidException {
|
||||
SignalServiceGroup.Builder group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.UPDATE)
|
||||
.withId(g.groupId)
|
||||
.withId(g.getGroupId().serialize())
|
||||
.withName(g.name)
|
||||
.withMembers(new ArrayList<>(g.getMembers()));
|
||||
|
||||
File aFile = getGroupAvatarFile(g.groupId);
|
||||
File aFile = getGroupAvatarFile(g.getGroupId());
|
||||
if (aFile.exists()) {
|
||||
try {
|
||||
group.withAvatar(Utils.createAttachment(aFile));
|
||||
|
@ -978,10 +978,10 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
Pair<Long, List<SendMessageResult>> sendGroupInfoRequest(
|
||||
byte[] groupId, SignalServiceAddress recipient
|
||||
GroupIdV1 groupId, SignalServiceAddress recipient
|
||||
) throws IOException {
|
||||
SignalServiceGroup.Builder group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.REQUEST_INFO)
|
||||
.withId(groupId);
|
||||
.withId(groupId.serialize());
|
||||
|
||||
SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
|
||||
.asGroupMessage(group.build());
|
||||
|
@ -1087,7 +1087,7 @@ public class Manager implements Closeable {
|
|||
account.save();
|
||||
}
|
||||
|
||||
public void setGroupBlocked(final byte[] groupId, final boolean blocked) throws GroupNotFoundException {
|
||||
public void setGroupBlocked(final GroupId groupId, final boolean blocked) throws GroupNotFoundException {
|
||||
GroupInfo group = getGroup(groupId);
|
||||
if (group == null) {
|
||||
throw new GroupNotFoundException(groupId);
|
||||
|
@ -1098,8 +1098,8 @@ public class Manager implements Closeable {
|
|||
account.save();
|
||||
}
|
||||
|
||||
public Pair<byte[], List<SendMessageResult>> updateGroup(
|
||||
byte[] groupId, String name, List<String> members, String avatar
|
||||
public Pair<GroupId, List<SendMessageResult>> updateGroup(
|
||||
GroupId groupId, String name, List<String> members, String avatar
|
||||
) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
|
||||
return sendUpdateGroupMessage(groupId,
|
||||
name,
|
||||
|
@ -1137,7 +1137,7 @@ public class Manager implements Closeable {
|
|||
/**
|
||||
* Change the expiration timer for a group
|
||||
*/
|
||||
public void setExpirationTimer(byte[] groupId, int messageExpirationTimer) {
|
||||
public void setExpirationTimer(GroupId groupId, int messageExpirationTimer) {
|
||||
GroupInfo g = account.getGroupStore().getGroup(groupId);
|
||||
if (g instanceof GroupInfoV1) {
|
||||
GroupInfoV1 groupInfoV1 = (GroupInfoV1) g;
|
||||
|
@ -1551,20 +1551,21 @@ public class Manager implements Closeable {
|
|||
if (message.getGroupContext().isPresent()) {
|
||||
if (message.getGroupContext().get().getGroupV1().isPresent()) {
|
||||
SignalServiceGroup groupInfo = message.getGroupContext().get().getGroupV1().get();
|
||||
GroupInfo group = account.getGroupStore().getGroupByV1Id(groupInfo.getGroupId());
|
||||
GroupIdV1 groupId = GroupId.v1(groupInfo.getGroupId());
|
||||
GroupInfo group = account.getGroupStore().getGroup(groupId);
|
||||
if (group == null || group instanceof GroupInfoV1) {
|
||||
GroupInfoV1 groupV1 = (GroupInfoV1) group;
|
||||
switch (groupInfo.getType()) {
|
||||
case UPDATE: {
|
||||
if (groupV1 == null) {
|
||||
groupV1 = new GroupInfoV1(groupInfo.getGroupId());
|
||||
groupV1 = new GroupInfoV1(groupId);
|
||||
}
|
||||
|
||||
if (groupInfo.getAvatar().isPresent()) {
|
||||
SignalServiceAttachment avatar = groupInfo.getAvatar().get();
|
||||
if (avatar.isPointer()) {
|
||||
try {
|
||||
retrieveGroupAvatarAttachment(avatar.asPointer(), groupV1.groupId);
|
||||
retrieveGroupAvatarAttachment(avatar.asPointer(), groupV1.getGroupId());
|
||||
} catch (IOException | InvalidMessageException | MissingConfigurationException e) {
|
||||
System.err.println("Failed to retrieve group avatar (" + avatar.asPointer()
|
||||
.getRemoteId() + "): " + e.getMessage());
|
||||
|
@ -1589,7 +1590,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
case DELIVER:
|
||||
if (groupV1 == null && !isSync) {
|
||||
actions.add(new SendGroupInfoRequestAction(source, groupInfo.getGroupId()));
|
||||
actions.add(new SendGroupInfoRequestAction(source, groupV1.getGroupId()));
|
||||
}
|
||||
break;
|
||||
case QUIT: {
|
||||
|
@ -1601,7 +1602,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
case REQUEST_INFO:
|
||||
if (groupV1 != null && !isSync) {
|
||||
actions.add(new SendGroupUpdateAction(source, groupV1.groupId));
|
||||
actions.add(new SendGroupUpdateAction(source, groupV1.getGroupId()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1627,7 +1628,7 @@ public class Manager implements Closeable {
|
|||
if (message.getGroupContext().isPresent()) {
|
||||
if (message.getGroupContext().get().getGroupV1().isPresent()) {
|
||||
SignalServiceGroup groupInfo = message.getGroupContext().get().getGroupV1().get();
|
||||
GroupInfoV1 group = account.getGroupStore().getOrCreateGroupV1(groupInfo.getGroupId());
|
||||
GroupInfoV1 group = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(groupInfo.getGroupId()));
|
||||
if (group != null) {
|
||||
if (group.messageExpirationTime != message.getExpiresInSeconds()) {
|
||||
group.messageExpirationTime = message.getExpiresInSeconds();
|
||||
|
@ -1723,17 +1724,17 @@ public class Manager implements Closeable {
|
|||
) {
|
||||
final GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
|
||||
|
||||
byte[] groupId = groupSecretParams.getPublicParams().getGroupIdentifier().serialize();
|
||||
GroupInfo groupInfo = account.getGroupStore().getGroupByV2Id(groupId);
|
||||
GroupIdV2 groupId = GroupUtils.getGroupIdV2(groupSecretParams);
|
||||
GroupInfo groupInfo = account.getGroupStore().getGroup(groupId);
|
||||
final GroupInfoV2 groupInfoV2;
|
||||
if (groupInfo instanceof GroupInfoV1) {
|
||||
// Received a v2 group message for a v1 group, we need to locally migrate the group
|
||||
account.getGroupStore().deleteGroup(groupInfo.groupId);
|
||||
account.getGroupStore().deleteGroup(groupInfo.getGroupId());
|
||||
groupInfoV2 = new GroupInfoV2(groupId, groupMasterKey);
|
||||
System.err.println("Locally migrated group "
|
||||
+ Base64.encodeBytes(groupInfo.groupId)
|
||||
+ groupInfo.getGroupId().toBase64()
|
||||
+ " to group v2, id: "
|
||||
+ Base64.encodeBytes(groupInfoV2.groupId)
|
||||
+ groupInfoV2.getGroupId().toBase64()
|
||||
+ " !!!");
|
||||
} else if (groupInfo instanceof GroupInfoV2) {
|
||||
groupInfoV2 = (GroupInfoV2) groupInfo;
|
||||
|
@ -1970,19 +1971,14 @@ public class Manager implements Closeable {
|
|||
if (content != null && content.getDataMessage().isPresent()) {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
if (message.getGroupContext().isPresent()) {
|
||||
GroupInfo group = null;
|
||||
if (message.getGroupContext().get().getGroupV1().isPresent()) {
|
||||
SignalServiceGroup groupInfo = message.getGroupContext().get().getGroupV1().get();
|
||||
if (groupInfo.getType() == SignalServiceGroup.Type.DELIVER) {
|
||||
group = getGroup(groupInfo.getGroupId());
|
||||
if (groupInfo.getType() != SignalServiceGroup.Type.DELIVER) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (message.getGroupContext().get().getGroupV2().isPresent()) {
|
||||
SignalServiceGroupV2 groupContext = message.getGroupContext().get().getGroupV2().get();
|
||||
final GroupMasterKey groupMasterKey = groupContext.getMasterKey();
|
||||
byte[] groupId = GroupUtils.getGroupId(groupMasterKey);
|
||||
group = account.getGroupStore().getGroupByV2Id(groupId);
|
||||
}
|
||||
GroupId groupId = GroupUtils.getGroupId(message.getGroupContext().get());
|
||||
GroupInfo group = account.getGroupStore().getGroup(groupId);
|
||||
if (group != null && group.isBlocked()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -2055,7 +2051,8 @@ public class Manager implements Closeable {
|
|||
DeviceGroupsInputStream s = new DeviceGroupsInputStream(attachmentAsStream);
|
||||
DeviceGroup g;
|
||||
while ((g = s.read()) != null) {
|
||||
GroupInfoV1 syncGroup = account.getGroupStore().getOrCreateGroupV1(g.getId());
|
||||
GroupInfoV1 syncGroup = account.getGroupStore()
|
||||
.getOrCreateGroupV1(GroupId.v1(g.getId()));
|
||||
if (syncGroup != null) {
|
||||
if (g.getName().isPresent()) {
|
||||
syncGroup.name = g.getName().get();
|
||||
|
@ -2076,7 +2073,7 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
if (g.getAvatar().isPresent()) {
|
||||
retrieveGroupAvatarAttachment(g.getAvatar().get(), syncGroup.groupId);
|
||||
retrieveGroupAvatarAttachment(g.getAvatar().get(), syncGroup.getGroupId());
|
||||
}
|
||||
syncGroup.inboxPosition = g.getInboxPosition().orNull();
|
||||
syncGroup.archived = g.isArchived();
|
||||
|
@ -2104,12 +2101,15 @@ public class Manager implements Closeable {
|
|||
for (SignalServiceAddress address : blockedListMessage.getAddresses()) {
|
||||
setContactBlocked(resolveSignalServiceAddress(address), true);
|
||||
}
|
||||
for (byte[] groupId : blockedListMessage.getGroupIds()) {
|
||||
for (GroupId groupId : blockedListMessage.getGroupIds()
|
||||
.stream()
|
||||
.map(GroupId::unknownVersion)
|
||||
.collect(Collectors.toSet())) {
|
||||
try {
|
||||
setGroupBlocked(groupId, true);
|
||||
} catch (GroupNotFoundException e) {
|
||||
System.err.println("BlockedListMessage contained groupID that was not found in GroupStore: "
|
||||
+ Base64.encodeBytes(groupId));
|
||||
+ groupId.toBase64());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2229,12 +2229,12 @@ public class Manager implements Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
private File getGroupAvatarFile(byte[] groupId) {
|
||||
return new File(pathConfig.getAvatarsPath(), "group-" + Base64.encodeBytes(groupId).replace("/", "_"));
|
||||
private File getGroupAvatarFile(GroupId groupId) {
|
||||
return new File(pathConfig.getAvatarsPath(), "group-" + groupId.toBase64().replace("/", "_"));
|
||||
}
|
||||
|
||||
private File retrieveGroupAvatarAttachment(
|
||||
SignalServiceAttachment attachment, byte[] groupId
|
||||
SignalServiceAttachment attachment, GroupId groupId
|
||||
) throws IOException, InvalidMessageException, MissingConfigurationException {
|
||||
IOUtils.createPrivateDirectories(pathConfig.getAvatarsPath());
|
||||
if (attachment.isPointer()) {
|
||||
|
@ -2333,10 +2333,10 @@ public class Manager implements Closeable {
|
|||
for (GroupInfo record : account.getGroupStore().getGroups()) {
|
||||
if (record instanceof GroupInfoV1) {
|
||||
GroupInfoV1 groupInfo = (GroupInfoV1) record;
|
||||
out.write(new DeviceGroup(groupInfo.groupId,
|
||||
out.write(new DeviceGroup(groupInfo.getGroupId().serialize(),
|
||||
Optional.fromNullable(groupInfo.name),
|
||||
new ArrayList<>(groupInfo.getMembers()),
|
||||
createGroupAvatarAttachment(groupInfo.groupId),
|
||||
createGroupAvatarAttachment(groupInfo.getGroupId()),
|
||||
groupInfo.isMember(account.getSelfAddress()),
|
||||
Optional.of(groupInfo.messageExpirationTime),
|
||||
Optional.fromNullable(groupInfo.color),
|
||||
|
@ -2442,7 +2442,7 @@ public class Manager implements Closeable {
|
|||
List<byte[]> groupIds = new ArrayList<>();
|
||||
for (GroupInfo record : account.getGroupStore().getGroups()) {
|
||||
if (record.isBlocked()) {
|
||||
groupIds.add(record.groupId);
|
||||
groupIds.add(record.getGroupId().serialize());
|
||||
}
|
||||
}
|
||||
sendSyncMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groupIds)));
|
||||
|
@ -2466,7 +2466,7 @@ public class Manager implements Closeable {
|
|||
return account.getContactStore().getContact(Util.getSignalServiceAddressFromIdentifier(number));
|
||||
}
|
||||
|
||||
public GroupInfo getGroup(byte[] groupId) {
|
||||
public GroupInfo getGroup(GroupId groupId) {
|
||||
return account.getGroupStore().getGroup(groupId);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
public class NotAGroupMemberException extends Exception {
|
||||
|
||||
public NotAGroupMemberException(byte[] groupId, String groupName) {
|
||||
super("User is not a member in group: " + groupName + " (" + Base64.encodeBytes(groupId) + ")");
|
||||
public NotAGroupMemberException(GroupId groupId, String groupName) {
|
||||
super("User is not a member in group: " + groupName + " (" + groupId.toBase64() + ")");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ package org.asamk.signal.manager.helper;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.asamk.signal.manager.GroupIdV2;
|
||||
import org.asamk.signal.manager.GroupLinkPassword;
|
||||
import org.asamk.signal.manager.GroupUtils;
|
||||
import org.asamk.signal.storage.groups.GroupInfoV2;
|
||||
import org.asamk.signal.util.IOUtils;
|
||||
import org.signal.storageservice.protos.groups.AccessControl;
|
||||
|
@ -117,7 +119,7 @@ public class GroupHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
final byte[] groupId = groupSecretParams.getPublicParams().getGroupIdentifier().serialize();
|
||||
final GroupIdV2 groupId = GroupUtils.getGroupIdV2(groupSecretParams);
|
||||
final GroupMasterKey masterKey = groupSecretParams.getMasterKey();
|
||||
GroupInfoV2 g = new GroupInfoV2(groupId, masterKey);
|
||||
g.setGroup(decryptedGroup);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue