1 package org
.asamk
.signal
.manager
.helper
;
3 import com
.google
.protobuf
.InvalidProtocolBufferException
;
5 import org
.signal
.storageservice
.protos
.groups
.GroupChange
;
6 import org
.signal
.storageservice
.protos
.groups
.Member
;
7 import org
.signal
.storageservice
.protos
.groups
.local
.DecryptedGroup
;
8 import org
.signal
.storageservice
.protos
.groups
.local
.DecryptedGroupChange
;
9 import org
.signal
.zkgroup
.VerificationFailedException
;
10 import org
.signal
.zkgroup
.groups
.GroupMasterKey
;
11 import org
.signal
.zkgroup
.groups
.GroupSecretParams
;
12 import org
.signal
.zkgroup
.profiles
.ProfileKeyCredential
;
13 import org
.whispersystems
.libsignal
.util
.guava
.Optional
;
14 import org
.whispersystems
.signalservice
.api
.groupsv2
.DecryptedGroupUtil
;
15 import org
.whispersystems
.signalservice
.api
.groupsv2
.GroupCandidate
;
16 import org
.whispersystems
.signalservice
.api
.groupsv2
.GroupsV2Operations
;
17 import org
.whispersystems
.signalservice
.api
.groupsv2
.InvalidGroupStateException
;
18 import org
.whispersystems
.signalservice
.api
.groupsv2
.NotAbleToApplyGroupV2ChangeException
;
19 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
21 import java
.util
.Collection
;
23 import java
.util
.stream
.Collectors
;
25 public class GroupHelper
{
27 private final ProfileKeyCredentialProvider profileKeyCredentialProvider
;
29 private final ProfileProvider profileProvider
;
31 private final SelfAddressProvider selfAddressProvider
;
33 private final GroupsV2Operations groupsV2Operations
;
36 final ProfileKeyCredentialProvider profileKeyCredentialProvider
,
37 final ProfileProvider profileProvider
,
38 final SelfAddressProvider selfAddressProvider
,
39 final GroupsV2Operations groupsV2Operations
41 this.profileKeyCredentialProvider
= profileKeyCredentialProvider
;
42 this.profileProvider
= profileProvider
;
43 this.selfAddressProvider
= selfAddressProvider
;
44 this.groupsV2Operations
= groupsV2Operations
;
47 public GroupsV2Operations
.NewGroup
createGroupV2(
48 String name
, Collection
<SignalServiceAddress
> members
, byte[] avatar
50 final ProfileKeyCredential profileKeyCredential
= profileKeyCredentialProvider
.getProfileKeyCredential(
51 selfAddressProvider
.getSelfAddress());
52 if (profileKeyCredential
== null) {
53 System
.err
.println("Cannot create a V2 group as self does not have a versioned profile");
57 final int noUuidCapability
= members
.stream()
58 .filter(address
-> !address
.getUuid().isPresent())
59 .collect(Collectors
.toUnmodifiableSet())
61 if (noUuidCapability
> 0) {
62 System
.err
.println("Cannot create a V2 group as " + noUuidCapability
+ " members don't have a UUID.");
66 final int noGv2Capability
= members
.stream()
67 .map(profileProvider
::getProfile
)
68 .filter(profile
-> !profile
.getCapabilities().gv2
)
69 .collect(Collectors
.toUnmodifiableSet())
71 if (noGv2Capability
> 0) {
72 System
.err
.println("Cannot create a V2 group as " + noGv2Capability
+ " members don't support Groups V2.");
76 GroupCandidate self
= new GroupCandidate(selfAddressProvider
.getSelfAddress().getUuid().orNull(),
77 Optional
.fromNullable(profileKeyCredential
));
78 Set
<GroupCandidate
> candidates
= members
.stream()
79 .map(member
-> new GroupCandidate(member
.getUuid().get(),
80 Optional
.fromNullable(profileKeyCredentialProvider
.getProfileKeyCredential(member
))))
81 .collect(Collectors
.toSet());
83 final GroupSecretParams groupSecretParams
= GroupSecretParams
.generate();
84 return groupsV2Operations
.createNewGroup(groupSecretParams
,
86 Optional
.fromNullable(avatar
),
93 public DecryptedGroup
getUpdatedDecryptedGroup(
94 DecryptedGroup group
, byte[] signedGroupChange
, GroupMasterKey groupMasterKey
97 final DecryptedGroupChange decryptedGroupChange
= getDecryptedGroupChange(signedGroupChange
,
99 if (decryptedGroupChange
== null) {
102 return DecryptedGroupUtil
.apply(group
, decryptedGroupChange
);
103 } catch (NotAbleToApplyGroupV2ChangeException e
) {
108 private DecryptedGroupChange
getDecryptedGroupChange(byte[] signedGroupChange
, GroupMasterKey groupMasterKey
) {
109 if (signedGroupChange
!= null) {
110 GroupsV2Operations
.GroupOperations groupOperations
= groupsV2Operations
.forGroup(GroupSecretParams
.deriveFromMasterKey(
114 return groupOperations
.decryptChange(GroupChange
.parseFrom(signedGroupChange
), true).orNull();
115 } catch (VerificationFailedException
| InvalidGroupStateException
| InvalidProtocolBufferException e
) {