]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java
89306ecd18638e4dc9ee8a5bee632132fed1836f
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / storage / groups / GroupInfoV2.java
1 package org.asamk.signal.manager.storage.groups;
2
3 import org.asamk.signal.manager.api.GroupIdV2;
4 import org.asamk.signal.manager.api.GroupInviteLinkUrl;
5 import org.asamk.signal.manager.api.GroupPermission;
6 import org.asamk.signal.manager.storage.recipients.RecipientAddress;
7 import org.asamk.signal.manager.storage.recipients.RecipientId;
8 import org.asamk.signal.manager.storage.recipients.RecipientResolver;
9 import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
10 import org.signal.storageservice.protos.groups.AccessControl;
11 import org.signal.storageservice.protos.groups.Member;
12 import org.signal.storageservice.protos.groups.local.DecryptedGroup;
13 import org.signal.storageservice.protos.groups.local.EnabledState;
14 import org.whispersystems.signalservice.api.push.DistributionId;
15 import org.whispersystems.signalservice.api.push.ServiceId;
16
17 import java.util.Set;
18 import java.util.stream.Collectors;
19
20 public final class GroupInfoV2 extends GroupInfo {
21
22 private final GroupIdV2 groupId;
23 private final GroupMasterKey masterKey;
24 private final DistributionId distributionId;
25 private boolean blocked;
26 private boolean profileSharingEnabled;
27 private DecryptedGroup group;
28 private byte[] storageRecord;
29 private boolean permissionDenied;
30
31 private final RecipientResolver recipientResolver;
32
33 public GroupInfoV2(
34 final GroupIdV2 groupId, final GroupMasterKey masterKey, final RecipientResolver recipientResolver
35 ) {
36 this.groupId = groupId;
37 this.masterKey = masterKey;
38 this.distributionId = DistributionId.create();
39 this.recipientResolver = recipientResolver;
40 }
41
42 public GroupInfoV2(
43 final GroupIdV2 groupId,
44 final GroupMasterKey masterKey,
45 final DecryptedGroup group,
46 final DistributionId distributionId,
47 final boolean blocked,
48 final boolean profileSharingEnabled,
49 final boolean permissionDenied,
50 final byte[] storageRecord,
51 final RecipientResolver recipientResolver
52 ) {
53 this.groupId = groupId;
54 this.masterKey = masterKey;
55 this.group = group;
56 this.distributionId = distributionId;
57 this.blocked = blocked;
58 this.profileSharingEnabled = profileSharingEnabled;
59 this.permissionDenied = permissionDenied;
60 this.storageRecord = storageRecord;
61 this.recipientResolver = recipientResolver;
62 }
63
64 @Override
65 public GroupIdV2 getGroupId() {
66 return groupId;
67 }
68
69 public GroupMasterKey getMasterKey() {
70 return masterKey;
71 }
72
73 public byte[] getStorageRecord() {
74 return storageRecord;
75 }
76
77 public DistributionId getDistributionId() {
78 return distributionId;
79 }
80
81 public void setGroup(final DecryptedGroup group) {
82 if (group != null) {
83 this.permissionDenied = false;
84 }
85 this.group = group;
86 }
87
88 public DecryptedGroup getGroup() {
89 return group;
90 }
91
92 @Override
93 public String getTitle() {
94 if (this.group == null) {
95 return null;
96 }
97 return this.group.title;
98 }
99
100 @Override
101 public String getDescription() {
102 if (this.group == null) {
103 return null;
104 }
105 return this.group.description;
106 }
107
108 @Override
109 public GroupInviteLinkUrl getGroupInviteLink() {
110 if (this.group == null || this.group.inviteLinkPassword.toByteArray().length == 0 || (
111 this.group.accessControl != null
112 && this.group.accessControl.addFromInviteLink != AccessControl.AccessRequired.ANY
113 && this.group.accessControl.addFromInviteLink != AccessControl.AccessRequired.ADMINISTRATOR
114 )) {
115 return null;
116 }
117
118 return GroupInviteLinkUrl.forGroup(masterKey, group);
119 }
120
121 @Override
122 public Set<RecipientId> getMembers() {
123 if (this.group == null) {
124 return Set.of();
125 }
126 return group.members.stream()
127 .map(m -> ServiceId.parseOrThrow(m.aciBytes))
128 .map(recipientResolver::resolveRecipient)
129 .collect(Collectors.toSet());
130 }
131
132 @Override
133 public Set<RecipientId> getBannedMembers() {
134 if (this.group == null) {
135 return Set.of();
136 }
137 return group.bannedMembers.stream()
138 .map(m -> ServiceId.parseOrThrow(m.serviceIdBytes))
139 .map(recipientResolver::resolveRecipient)
140 .collect(Collectors.toSet());
141 }
142
143 @Override
144 public Set<RecipientId> getPendingMembers() {
145 if (this.group == null) {
146 return Set.of();
147 }
148 return group.pendingMembers.stream()
149 .map(m -> ServiceId.parseOrThrow(m.serviceIdBytes))
150 .map(recipientResolver::resolveRecipient)
151 .collect(Collectors.toSet());
152 }
153
154 @Override
155 public Set<RecipientId> getRequestingMembers() {
156 if (this.group == null) {
157 return Set.of();
158 }
159 return group.requestingMembers.stream()
160 .map(m -> ServiceId.parseOrThrow(m.aciBytes))
161 .map(recipientResolver::resolveRecipient)
162 .collect(Collectors.toSet());
163 }
164
165 @Override
166 public Set<RecipientId> getAdminMembers() {
167 if (this.group == null) {
168 return Set.of();
169 }
170 return group.members.stream()
171 .filter(m -> m.role == Member.Role.ADMINISTRATOR)
172 .map(m -> new RecipientAddress(ServiceId.ACI.parseOrNull(m.aciBytes),
173 ServiceId.PNI.parseOrNull(m.pniBytes),
174 null))
175 .map(recipientResolver::resolveRecipient)
176 .collect(Collectors.toSet());
177 }
178
179 @Override
180 public boolean isBlocked() {
181 return blocked;
182 }
183
184 @Override
185 public void setBlocked(final boolean blocked) {
186 this.blocked = blocked;
187 }
188
189 @Override
190 public boolean isProfileSharingEnabled() {
191 return profileSharingEnabled;
192 }
193
194 @Override
195 public void setProfileSharingEnabled(final boolean profileSharingEnabled) {
196 this.profileSharingEnabled = profileSharingEnabled;
197 }
198
199 @Override
200 public int getMessageExpirationTimer() {
201 return this.group != null && this.group.disappearingMessagesTimer != null
202 ? this.group.disappearingMessagesTimer.duration
203 : 0;
204 }
205
206 @Override
207 public boolean isAnnouncementGroup() {
208 return this.group != null && this.group.isAnnouncementGroup == EnabledState.ENABLED;
209 }
210
211 @Override
212 public GroupPermission getPermissionAddMember() {
213 final var accessControl = getAccessControl();
214 return accessControl == null ? GroupPermission.EVERY_MEMBER : toGroupPermission(accessControl.members);
215 }
216
217 @Override
218 public GroupPermission getPermissionEditDetails() {
219 final var accessControl = getAccessControl();
220 return accessControl == null ? GroupPermission.EVERY_MEMBER : toGroupPermission(accessControl.attributes);
221 }
222
223 @Override
224 public GroupPermission getPermissionSendMessage() {
225 return isAnnouncementGroup() ? GroupPermission.ONLY_ADMINS : GroupPermission.EVERY_MEMBER;
226 }
227
228 public void setPermissionDenied(final boolean permissionDenied) {
229 this.permissionDenied = permissionDenied;
230 }
231
232 public boolean isPermissionDenied() {
233 return permissionDenied;
234 }
235
236 private AccessControl getAccessControl() {
237 if (this.group == null || this.group.accessControl == null) {
238 return null;
239 }
240
241 return this.group.accessControl;
242 }
243
244 private static GroupPermission toGroupPermission(final AccessControl.AccessRequired permission) {
245 return switch (permission) {
246 case ADMINISTRATOR -> GroupPermission.ONLY_ADMINS;
247 default -> GroupPermission.EVERY_MEMBER;
248 };
249 }
250 }