diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java index d4228b2a1..e10bc2cc7 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import java.util.UUID; @@ -295,7 +296,20 @@ public final class DecryptedGroupUtil { } private static void applyAddMemberAction(DecryptedGroup.Builder builder, List newMembersList) { - builder.addAllMembers(newMembersList); + if (newMembersList.isEmpty()) return; + + LinkedHashMap members = new LinkedHashMap<>(); + + for (DecryptedMember member : builder.getMembersList()) { + members.put(member.getUuid(), member); + } + + for (DecryptedMember member : newMembersList) { + members.put(member.getUuid(), member); + } + + builder.clearMembers(); + builder.addAllMembers(members.values()); removePendingAndRequestingMembersNowInGroup(builder); } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java index 5ea3079ee..9cdfe3036 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java @@ -82,6 +82,54 @@ public final class DecryptedGroupUtil_apply_Test { newGroup); } + @Test + public void apply_new_member_already_in_the_group() throws NotAbleToApplyGroupV2ChangeException { + DecryptedMember member1 = member(UUID.randomUUID()); + DecryptedMember member2 = member(UUID.randomUUID()); + + DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() + .setRevision(10) + .addMembers(member1) + .addMembers(member2) + .build(), + DecryptedGroupChange.newBuilder() + .setRevision(11) + .addNewMembers(member2) + .build()); + + assertEquals(DecryptedGroup.newBuilder() + .setRevision(11) + .addMembers(member1) + .addMembers(member2) + .build(), + newGroup); + } + + @Test + public void apply_new_member_already_in_the_group_by_uuid() throws NotAbleToApplyGroupV2ChangeException { + DecryptedMember member1 = member(UUID.randomUUID()); + UUID member2Uuid = UUID.randomUUID(); + DecryptedMember member2a = member(member2Uuid, newProfileKey()); + DecryptedMember member2b = member(member2Uuid, newProfileKey()); + + DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() + .setRevision(10) + .addMembers(member1) + .addMembers(member2a) + .build(), + DecryptedGroupChange.newBuilder() + .setRevision(11) + .addNewMembers(member2b) + .build()); + + assertEquals(DecryptedGroup.newBuilder() + .setRevision(11) + .addMembers(member1) + .addMembers(member2b) + .build(), + newGroup); + } + @Test public void apply_remove_member() throws NotAbleToApplyGroupV2ChangeException { DecryptedMember member1 = member(UUID.randomUUID());