]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/manager/helper/GroupHelper.java
Implement creating V2 Groups
[signal-cli] / src / main / java / org / asamk / signal / manager / helper / GroupHelper.java
1 package org.asamk.signal.manager.helper;
2
3 import org.asamk.signal.storage.groups.GroupInfo;
4 import org.asamk.signal.storage.groups.GroupInfoV1;
5 import org.asamk.signal.storage.groups.GroupInfoV2;
6 import org.signal.storageservice.protos.groups.Member;
7 import org.signal.zkgroup.groups.GroupSecretParams;
8 import org.signal.zkgroup.profiles.ProfileKeyCredential;
9 import org.whispersystems.libsignal.util.guava.Optional;
10 import org.whispersystems.signalservice.api.groupsv2.GroupCandidate;
11 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
12 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
13 import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
14 import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
15 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
16
17 import java.util.Collection;
18 import java.util.Set;
19 import java.util.stream.Collectors;
20
21 public class GroupHelper {
22
23 private final ProfileKeyCredentialProvider profileKeyCredentialProvider;
24
25 private final ProfileProvider profileProvider;
26
27 private final SelfAddressProvider selfAddressProvider;
28
29 private final GroupsV2Operations groupsV2Operations;
30
31 public GroupHelper(
32 final ProfileKeyCredentialProvider profileKeyCredentialProvider,
33 final ProfileProvider profileProvider,
34 final SelfAddressProvider selfAddressProvider,
35 final GroupsV2Operations groupsV2Operations
36 ) {
37 this.profileKeyCredentialProvider = profileKeyCredentialProvider;
38 this.profileProvider = profileProvider;
39 this.selfAddressProvider = selfAddressProvider;
40 this.groupsV2Operations = groupsV2Operations;
41 }
42
43 public static void setGroupContext(
44 final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo groupInfo
45 ) {
46 if (groupInfo instanceof GroupInfoV1) {
47 SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.DELIVER)
48 .withId(groupInfo.groupId)
49 .build();
50 messageBuilder.asGroupMessage(group);
51 } else {
52 final GroupInfoV2 groupInfoV2 = (GroupInfoV2) groupInfo;
53 SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(groupInfoV2.getMasterKey())
54 .withRevision(groupInfoV2.getGroup() == null ? 0 : groupInfoV2.getGroup().getRevision())
55 .build();
56 messageBuilder.asGroupMessage(group);
57 }
58 }
59
60 public GroupsV2Operations.NewGroup createGroupV2(
61 String name, Collection<SignalServiceAddress> members, byte[] avatar
62 ) {
63 final ProfileKeyCredential profileKeyCredential = profileKeyCredentialProvider.getProfileKeyCredential(
64 selfAddressProvider.getSelfAddress());
65 if (profileKeyCredential == null) {
66 System.err.println("Cannot create a V2 group as self does not have a versioned profile");
67 return null;
68 }
69
70 final int noUuidCapability = members.stream()
71 .filter(address -> !address.getUuid().isPresent())
72 .collect(Collectors.toUnmodifiableSet())
73 .size();
74 if (noUuidCapability > 0) {
75 System.err.println("Cannot create a V2 group as " + noUuidCapability + " members don't have a UUID.");
76 return null;
77 }
78
79 final int noGv2Capability = members.stream()
80 .map(profileProvider::getProfile)
81 .filter(profile -> !profile.getCapabilities().gv2)
82 .collect(Collectors.toUnmodifiableSet())
83 .size();
84 if (noGv2Capability > 0) {
85 System.err.println("Cannot create a V2 group as " + noGv2Capability + " members don't support Groups V2.");
86 return null;
87 }
88
89 GroupCandidate self = new GroupCandidate(selfAddressProvider.getSelfAddress().getUuid().orNull(),
90 Optional.fromNullable(profileKeyCredential));
91 Set<GroupCandidate> candidates = members.stream()
92 .map(member -> new GroupCandidate(member.getUuid().get(),
93 Optional.fromNullable(profileKeyCredentialProvider.getProfileKeyCredential(member))))
94 .collect(Collectors.toSet());
95
96 final GroupSecretParams groupSecretParams = GroupSecretParams.generate();
97 return groupsV2Operations.createNewGroup(groupSecretParams,
98 name,
99 Optional.fromNullable(avatar),
100 self,
101 candidates,
102 Member.Role.DEFAULT,
103 0);
104 }
105
106 }