Prevent last admin from leaving group

This commit is contained in:
AsamK 2021-05-15 18:05:07 +02:00
parent 78f22c7020
commit ea633efc9c
5 changed files with 56 additions and 8 deletions

View file

@ -27,6 +27,7 @@ import org.asamk.signal.manager.groups.GroupLinkState;
import org.asamk.signal.manager.groups.GroupNotFoundException;
import org.asamk.signal.manager.groups.GroupPermission;
import org.asamk.signal.manager.groups.GroupUtils;
import org.asamk.signal.manager.groups.LastGroupAdminException;
import org.asamk.signal.manager.groups.NotAGroupMemberException;
import org.asamk.signal.manager.helper.GroupV2Helper;
import org.asamk.signal.manager.helper.PinHelper;
@ -763,7 +764,9 @@ public class Manager implements Closeable {
return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfRecipientId()));
}
public Pair<Long, List<SendMessageResult>> sendQuitGroupMessage(GroupId groupId) throws GroupNotFoundException, IOException, NotAGroupMemberException {
public Pair<Long, List<SendMessageResult>> sendQuitGroupMessage(
GroupId groupId, Set<String> groupAdmins
) throws GroupNotFoundException, IOException, NotAGroupMemberException, InvalidNumberException, LastGroupAdminException {
SignalServiceDataMessage.Builder messageBuilder;
final var g = getGroupForUpdating(groupId);
@ -775,7 +778,18 @@ public class Manager implements Closeable {
account.getGroupStore().updateGroup(groupInfoV1);
} else {
final var groupInfoV2 = (GroupInfoV2) g;
final var groupGroupChangePair = groupV2Helper.leaveGroup(groupInfoV2);
final var currentAdmins = g.getAdminMembers();
final var newAdmins = getSignalServiceAddresses(groupAdmins);
newAdmins.removeAll(currentAdmins);
newAdmins.retainAll(g.getMembers());
if (currentAdmins.contains(getSelfRecipientId())
&& currentAdmins.size() == 1
&& g.getMembers().size() > 1
&& newAdmins.size() == 0) {
// Last admin can't leave the group, unless she's also the last member
throw new LastGroupAdminException(g.getGroupId(), g.getTitle());
}
final var groupGroupChangePair = groupV2Helper.leaveGroup(groupInfoV2, newAdmins);
groupInfoV2.setGroup(groupGroupChangePair.first(), this::resolveRecipient);
messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupGroupChangePair.second().toByteArray());
account.getGroupStore().updateGroup(groupInfoV2);

View file

@ -0,0 +1,8 @@
package org.asamk.signal.manager.groups;
public class LastGroupAdminException extends Exception {
public LastGroupAdminException(GroupId groupId, String groupName) {
super("User is last admin in group: " + groupName + " (" + groupId.toBase64() + ")");
}
}

View file

@ -250,7 +250,9 @@ public class GroupV2Helper {
return commitChange(groupInfoV2, change);
}
public Pair<DecryptedGroup, GroupChange> leaveGroup(GroupInfoV2 groupInfoV2) throws IOException {
public Pair<DecryptedGroup, GroupChange> leaveGroup(
GroupInfoV2 groupInfoV2, Set<RecipientId> membersToMakeAdmin
) throws IOException {
var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
final var selfUuid = addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
.getUuid()
@ -259,9 +261,15 @@ public class GroupV2Helper {
if (selfPendingMember.isPresent()) {
return revokeInvites(groupInfoV2, Set.of(selfPendingMember.get()));
} else {
return ejectMembers(groupInfoV2, Set.of(selfUuid));
}
final var adminUuids = membersToMakeAdmin.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(SignalServiceAddress::getUuid)
.map(Optional::get)
.collect(Collectors.toList());
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
return commitChange(groupInfoV2, groupOperations.createLeaveAndPromoteMembersToAdmin(selfUuid, adminUuids));
}
public Pair<DecryptedGroup, GroupChange> removeMembers(