Convert all group code to be based on ServiceIds.

This commit is contained in:
Greyson Parrelli
2023-08-03 15:28:17 -04:00
committed by Alex Hart
parent d247e2c111
commit c5d9346370
50 changed files with 836 additions and 792 deletions

View File

@@ -85,7 +85,7 @@ class GroupChangeData(private val revision: Int, private val groupOperations: Gr
}
fun source(serviceId: ServiceId) {
actionsBuilder.sourceUuid = groupOperations.encryptServiceId(serviceId)
actionsBuilder.sourceServiceId = groupOperations.encryptServiceId(serviceId)
}
fun deleteMember(serviceId: ServiceId) {

View File

@@ -57,9 +57,9 @@ import static java.util.Collections.singletonList;
@Config(manifest = Config.NONE, application = Application.class)
public final class GroupsV2UpdateMessageProducerTest {
private UUID you;
private UUID alice;
private UUID bob;
private ACI you;
private ACI alice;
private ACI bob;
private GroupsV2UpdateMessageProducer producer;
@@ -74,9 +74,9 @@ public final class GroupsV2UpdateMessageProducerTest {
@Before
public void setup() {
you = UUID.randomUUID();
alice = UUID.randomUUID();
bob = UUID.randomUUID();
you = ACI.from(UUID.randomUUID());
alice = ACI.from(UUID.randomUUID());
bob = ACI.from(UUID.randomUUID());
recipientIdMockedStatic.when(() -> RecipientId.from(anyLong())).thenCallRealMethod();
@@ -86,10 +86,10 @@ public final class GroupsV2UpdateMessageProducerTest {
Recipient aliceRecipient = recipientWithName(aliceId, "Alice");
Recipient bobRecipient = recipientWithName(bobId, "Bob");
producer = new GroupsV2UpdateMessageProducer(ApplicationProvider.getApplicationContext(), new ServiceIds(ACI.from(you), PNI.from(UUID.randomUUID())), null);
producer = new GroupsV2UpdateMessageProducer(ApplicationProvider.getApplicationContext(), new ServiceIds(you, PNI.from(UUID.randomUUID())), null);
recipientIdMockedStatic.when(() -> RecipientId.from(ACI.from(alice))).thenReturn(aliceId);
recipientIdMockedStatic.when(() -> RecipientId.from(ACI.from(bob))).thenReturn(bobId);
recipientIdMockedStatic.when(() -> RecipientId.from(alice)).thenReturn(aliceId);
recipientIdMockedStatic.when(() -> RecipientId.from(bob)).thenReturn(bobId);
recipientMockedStatic.when(() -> Recipient.resolved(aliceId)).thenReturn(aliceRecipient);
recipientMockedStatic.when(() -> Recipient.resolved(bobId)).thenReturn(bobRecipient);
}
@@ -436,7 +436,7 @@ public final class GroupsV2UpdateMessageProducerTest {
public void member_invited_2_persons() {
DecryptedGroupChange change = changeBy(alice)
.invite(bob)
.invite(UUID.randomUUID())
.invite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(singletonList("Alice invited 2 people to the group.")));
@@ -447,8 +447,8 @@ public final class GroupsV2UpdateMessageProducerTest {
DecryptedGroupChange change = changeBy(bob)
.invite(alice)
.invite(you)
.invite(UUID.randomUUID())
.invite(UUID.randomUUID())
.invite(ACI.from(UUID.randomUUID()))
.invite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(Arrays.asList("Bob invited you to the group.", "Bob invited 3 people to the group.")));
@@ -496,8 +496,8 @@ public final class GroupsV2UpdateMessageProducerTest {
DecryptedGroupChange change = changeByUnknown()
.invite(alice)
.invite(you)
.invite(UUID.randomUUID())
.invite(UUID.randomUUID())
.invite(ACI.from(UUID.randomUUID()))
.invite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(Arrays.asList("You were invited to the group.", "3 people were invited to the group.")));
@@ -508,8 +508,8 @@ public final class GroupsV2UpdateMessageProducerTest {
DecryptedGroupChange change = changeByUnknown()
.invite(alice)
.inviteBy(you, bob)
.invite(UUID.randomUUID())
.invite(UUID.randomUUID())
.invite(ACI.from(UUID.randomUUID()))
.invite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(Arrays.asList("Bob invited you to the group.", "3 people were invited to the group.")));
@@ -520,8 +520,8 @@ public final class GroupsV2UpdateMessageProducerTest {
DecryptedGroupChange change = changeBy(bob)
.addMember(alice)
.invite(you)
.invite(UUID.randomUUID())
.invite(UUID.randomUUID())
.invite(ACI.from(UUID.randomUUID()))
.invite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(Arrays.asList("Bob invited you to the group.", "Bob added Alice.", "Bob invited 2 people to the group.")));
@@ -562,7 +562,7 @@ public final class GroupsV2UpdateMessageProducerTest {
public void member_uninvited_2_people() {
DecryptedGroupChange change = changeBy(alice)
.uninvite(bob)
.uninvite(UUID.randomUUID())
.uninvite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(singletonList("Alice revoked 2 invitations to the group.")));
@@ -581,7 +581,7 @@ public final class GroupsV2UpdateMessageProducerTest {
public void you_uninvited_2_people() {
DecryptedGroupChange change = changeBy(you)
.uninvite(bob)
.uninvite(UUID.randomUUID())
.uninvite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(singletonList("You revoked 2 invitations to the group.")));
@@ -627,7 +627,7 @@ public final class GroupsV2UpdateMessageProducerTest {
public void unknown_revokes_2_invites() {
DecryptedGroupChange change = changeByUnknown()
.uninvite(bob)
.uninvite(UUID.randomUUID())
.uninvite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(singletonList("2 invitations to the group were revoked.")));
@@ -638,8 +638,8 @@ public final class GroupsV2UpdateMessageProducerTest {
DecryptedGroupChange change = changeByUnknown()
.uninvite(bob)
.uninvite(you)
.uninvite(UUID.randomUUID())
.uninvite(UUID.randomUUID())
.uninvite(ACI.from(UUID.randomUUID()))
.uninvite(ACI.from(UUID.randomUUID()))
.build();
assertThat(describeChange(change), is(Arrays.asList("An admin revoked your invitation to the group.", "3 invitations to the group were revoked.")));
@@ -993,7 +993,7 @@ public final class GroupsV2UpdateMessageProducerTest {
assertEquals("The admin approval for the group link has been turned on.", describeGroupLinkChange(null, AccessControl.AccessRequired.ANY, AccessControl.AccessRequired.ADMINISTRATOR));
}
private String describeGroupLinkChange(@Nullable UUID editor, @NonNull AccessControl.AccessRequired fromAccess, AccessControl.AccessRequired toAccess){
private String describeGroupLinkChange(@Nullable ACI editor, @NonNull AccessControl.AccessRequired fromAccess, AccessControl.AccessRequired toAccess){
DecryptedGroup previousGroupState = DecryptedGroup.newBuilder()
.setAccessControl(AccessControl.newBuilder()
.setAddFromInviteLink(fromAccess))
@@ -1441,12 +1441,12 @@ public final class GroupsV2UpdateMessageProducerTest {
return producer.describeNewGroup(group, groupChange).getSpannable().toString();
}
private static GroupStateBuilder newGroupBy(UUID foundingMember, int revision) {
private static GroupStateBuilder newGroupBy(ACI foundingMember, int revision) {
return new GroupStateBuilder(foundingMember, revision);
}
private void assertSingleChangeMentioning(DecryptedGroupChange change, List<UUID> expectedMentions) {
List<ServiceId> expectedMentionSids = expectedMentions.stream().map(ACI::from).collect(Collectors.toList());
private void assertSingleChangeMentioning(DecryptedGroupChange change, List<ACI> expectedMentions) {
List<ServiceId> expectedMentionSids = expectedMentions.stream().collect(Collectors.toList());
List<UpdateDescription> changes = producer.describeChanges(null, change);
@@ -1466,23 +1466,23 @@ public final class GroupsV2UpdateMessageProducerTest {
private final DecryptedGroup.Builder builder;
GroupStateBuilder(@NonNull UUID foundingMember, int revision) {
GroupStateBuilder(@NonNull ACI foundingMember, int revision) {
builder = DecryptedGroup.newBuilder()
.setRevision(revision)
.addMembers(DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(foundingMember)));
.setAciBytes(foundingMember.toByteString()));
}
GroupStateBuilder invite(@NonNull UUID inviter, @NonNull UUID invitee) {
GroupStateBuilder invite(@NonNull ACI inviter, @NonNull ServiceId invitee) {
builder.addPendingMembers(DecryptedPendingMember.newBuilder()
.setServiceIdBinary(UuidUtil.toByteString(invitee))
.setAddedByUuid(UuidUtil.toByteString(inviter)));
.setServiceIdBytes(invitee.toByteString())
.setAddedByAci(inviter.toByteString()));
return this;
}
GroupStateBuilder member(@NonNull UUID member) {
GroupStateBuilder member(@NonNull ACI member) {
builder.addMembers(DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(member)));
.setAciBytes(member.toByteString()));
return this;
}

View File

@@ -9,7 +9,7 @@ import org.mockito.kotlin.mock
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context
import org.thoughtcrime.securesms.groups.v2.ChangeBuilder
import org.thoughtcrime.securesms.util.Base64
import org.whispersystems.signalservice.api.util.UuidUtil
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
import java.util.Random
import java.util.UUID
@@ -48,8 +48,8 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest {
*/
@Test
fun appendDeleteToExistingContext() {
val alice = UUID.randomUUID()
val aliceByteString = UuidUtil.toByteString(alice)
val alice = ACI.from(UUID.randomUUID())
val aliceByteString = alice.toByteString()
val change = ChangeBuilder.changeBy(alice)
.requestJoin(alice)
.build()
@@ -71,7 +71,7 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest {
val newContext = DecryptedGroupV2Context.parseFrom(Base64.decode(newEncodedBody))
assertThat("revision updated to 10", newContext.change.revision, `is`(10))
assertThat("change should retain join request", newContext.change.newRequestingMembersList[0].uuid, `is`(aliceByteString))
assertThat("change should retain join request", newContext.change.newRequestingMembersList[0].aciBytes, `is`(aliceByteString))
assertThat("change should add delete request", newContext.change.deleteRequestingMembersList[0], `is`(aliceByteString))
}

View File

@@ -151,8 +151,8 @@ class GroupManagerV2Test_edit {
then { patchedGroup ->
assertThat("Revision updated by one", patchedGroup.revision, `is`(6))
assertThat("Self is no longer in the group", patchedGroup.membersList.find { it.uuid == selfAci.toByteString() }, Matchers.nullValue())
assertThat("Other is now an admin in the group", patchedGroup.membersList.find { it.uuid == otherAci.toByteString() }?.role, `is`(Member.Role.ADMINISTRATOR))
assertThat("Self is no longer in the group", patchedGroup.membersList.find { it.aciBytes == selfAci.toByteString() }, Matchers.nullValue())
assertThat("Other is now an admin in the group", patchedGroup.membersList.find { it.aciBytes == otherAci.toByteString() }?.role, `is`(Member.Role.ADMINISTRATOR))
}
}
}

View File

@@ -19,16 +19,14 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
import org.signal.storageservice.protos.groups.local.DecryptedString;
import org.signal.storageservice.protos.groups.local.DecryptedTimer;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.UUID;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
public final class ChangeBuilder {
private final DecryptedGroupChange.Builder builder;
@Nullable private final UUID editor;
@Nullable private final ACI editor;
public static ChangeBuilder changeBy(@NonNull UUID editor) {
public static ChangeBuilder changeBy(@NonNull ACI editor) {
return new ChangeBuilder(editor);
}
@@ -36,10 +34,10 @@ public final class ChangeBuilder {
return new ChangeBuilder();
}
ChangeBuilder(@NonNull UUID editor) {
ChangeBuilder(@NonNull ACI editor) {
this.editor = editor;
this.builder = DecryptedGroupChange.newBuilder()
.setEditor(UuidUtil.toByteString(editor));
.setEditorServiceIdBytes(editor.toByteString());
}
ChangeBuilder() {
@@ -47,74 +45,74 @@ public final class ChangeBuilder {
this.builder = DecryptedGroupChange.newBuilder();
}
public ChangeBuilder addMember(@NonNull UUID newMember) {
public ChangeBuilder addMember(@NonNull ACI newMember) {
builder.addNewMembers(DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(newMember)));
.setAciBytes(newMember.toByteString()));
return this;
}
public ChangeBuilder addMember(@NonNull UUID newMember, @NonNull ProfileKey profileKey) {
public ChangeBuilder addMember(@NonNull ACI newMember, @NonNull ProfileKey profileKey) {
builder.addNewMembers(DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(newMember))
.setAciBytes(newMember.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
return this;
}
public ChangeBuilder deleteMember(@NonNull UUID removedMember) {
builder.addDeleteMembers(UuidUtil.toByteString(removedMember));
public ChangeBuilder deleteMember(@NonNull ACI removedMember) {
builder.addDeleteMembers(removedMember.toByteString());
return this;
}
public ChangeBuilder promoteToAdmin(@NonNull UUID member) {
public ChangeBuilder promoteToAdmin(@NonNull ACI member) {
builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
.setRole(Member.Role.ADMINISTRATOR)
.setUuid(UuidUtil.toByteString(member)));
.setAciBytes(member.toByteString()));
return this;
}
public ChangeBuilder demoteToMember(@NonNull UUID member) {
public ChangeBuilder demoteToMember(@NonNull ACI member) {
builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
.setRole(Member.Role.DEFAULT)
.setUuid(UuidUtil.toByteString(member)));
.setAciBytes(member.toByteString()));
return this;
}
public ChangeBuilder invite(@NonNull UUID potentialMember) {
return inviteBy(potentialMember, UuidUtil.UNKNOWN_UUID);
public ChangeBuilder invite(@NonNull ACI potentialMember) {
return inviteBy(potentialMember, ACI.UNKNOWN);
}
public ChangeBuilder inviteBy(@NonNull UUID potentialMember, @NonNull UUID inviter) {
public ChangeBuilder inviteBy(@NonNull ACI potentialMember, @NonNull ACI inviter) {
builder.addNewPendingMembers(DecryptedPendingMember.newBuilder()
.setServiceIdBinary(UuidUtil.toByteString(potentialMember))
.setAddedByUuid(UuidUtil.toByteString(inviter)));
.setServiceIdBytes(potentialMember.toByteString())
.setAddedByAci(inviter.toByteString()));
return this;
}
public ChangeBuilder uninvite(@NonNull UUID pendingMember) {
public ChangeBuilder uninvite(@NonNull ACI pendingMember) {
builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
.setServiceIdBinary(UuidUtil.toByteString(pendingMember)));
.setServiceIdBytes(pendingMember.toByteString()));
return this;
}
public ChangeBuilder promote(@NonNull UUID pendingMember) {
builder.addPromotePendingMembers(DecryptedMember.newBuilder().setUuid(UuidUtil.toByteString(pendingMember)));
public ChangeBuilder promote(@NonNull ACI pendingMember) {
builder.addPromotePendingMembers(DecryptedMember.newBuilder().setAciBytes(pendingMember.toByteString()));
return this;
}
public ChangeBuilder profileKeyUpdate(@NonNull UUID member, @NonNull ProfileKey profileKey) {
public ChangeBuilder profileKeyUpdate(@NonNull ACI member, @NonNull ProfileKey profileKey) {
return profileKeyUpdate(member, profileKey.serialize());
}
public ChangeBuilder profileKeyUpdate(@NonNull UUID member, @NonNull byte[] profileKey) {
public ChangeBuilder profileKeyUpdate(@NonNull ACI member, @NonNull byte[] profileKey) {
builder.addModifiedProfileKeys(DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(member))
.setAciBytes(member.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey)));
return this;
}
public ChangeBuilder promote(@NonNull UUID pendingMember, @NonNull ProfileKey profileKey) {
public ChangeBuilder promote(@NonNull ACI pendingMember, @NonNull ProfileKey profileKey) {
builder.addPromotePendingMembers(DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(pendingMember))
.setAciBytes(pendingMember.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
return this;
}
@@ -162,7 +160,7 @@ public final class ChangeBuilder {
return requestJoin(editor, newProfileKey());
}
public ChangeBuilder requestJoin(@NonNull UUID requester) {
public ChangeBuilder requestJoin(@NonNull ACI requester) {
return requestJoin(requester, newProfileKey());
}
@@ -171,22 +169,22 @@ public final class ChangeBuilder {
return requestJoin(editor, profileKey);
}
public ChangeBuilder requestJoin(@NonNull UUID requester, @NonNull ProfileKey profileKey) {
public ChangeBuilder requestJoin(@NonNull ACI requester, @NonNull ProfileKey profileKey) {
builder.addNewRequestingMembers(DecryptedRequestingMember.newBuilder()
.setUuid(UuidUtil.toByteString(requester))
.setAciBytes(requester.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
return this;
}
public ChangeBuilder approveRequest(@NonNull UUID approvedMember) {
public ChangeBuilder approveRequest(@NonNull ACI approvedMember) {
builder.addPromoteRequestingMembers(DecryptedApproveMember.newBuilder()
.setRole(Member.Role.DEFAULT)
.setUuid(UuidUtil.toByteString(approvedMember)));
.setAciBytes(approvedMember.toByteString()));
return this;
}
public ChangeBuilder denyRequest(@NonNull UUID approvedMember) {
builder.addDeleteRequestingMembers(UuidUtil.toByteString(approvedMember));
public ChangeBuilder denyRequest(@NonNull ACI approvedMember) {
builder.addDeleteRequestingMembers(approvedMember.toByteString());
return this;
}

View File

@@ -22,7 +22,7 @@ public final class ProfileKeySetTest {
@Test
public void empty_change() {
UUID editor = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(editor).build());
@@ -33,95 +33,95 @@ public final class ProfileKeySetTest {
@Test
public void new_member_is_not_authoritative() {
UUID editor = UUID.randomUUID();
UUID newMember = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI newMember = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(editor).addMember(newMember, profileKey).build());
assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty());
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey)));
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(newMember, profileKey)));
}
@Test
public void new_member_by_self_is_authoritative() {
UUID newMember = UUID.randomUUID();
ACI newMember = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(newMember).addMember(newMember, profileKey).build());
assertTrue(profileKeySet.getProfileKeys().isEmpty());
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey)));
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(newMember, profileKey)));
}
@Test
public void new_member_by_self_promote_is_authoritative() {
UUID newMember = UUID.randomUUID();
ACI newMember = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(newMember).promote(newMember, profileKey).build());
assertTrue(profileKeySet.getProfileKeys().isEmpty());
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey)));
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(newMember, profileKey)));
}
@Test
public void new_member_by_promote_by_other_editor_is_not_authoritative() {
UUID editor = UUID.randomUUID();
UUID newMember = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI newMember = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(editor).promote(newMember, profileKey).build());
assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty());
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey)));
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(newMember, profileKey)));
}
@Test
public void new_member_by_promote_by_unknown_editor_is_not_authoritative() {
UUID newMember = UUID.randomUUID();
ACI newMember = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeByUnknown().promote(newMember, profileKey).build());
assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty());
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey)));
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(newMember, profileKey)));
}
@Test
public void profile_key_update_by_self_is_authoritative() {
UUID member = UUID.randomUUID();
ACI member = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(member).profileKeyUpdate(member, profileKey).build());
assertTrue(profileKeySet.getProfileKeys().isEmpty());
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey)));
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(member, profileKey)));
}
@Test
public void profile_key_update_by_another_is_not_authoritative() {
UUID editor = UUID.randomUUID();
UUID member = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI member = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(editor).profileKeyUpdate(member, profileKey).build());
assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty());
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey)));
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(member, profileKey)));
}
@Test
public void multiple_updates_overwrite() {
UUID editor = UUID.randomUUID();
UUID member = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI member = ACI.from(UUID.randomUUID());
ProfileKey profileKey1 = ProfileKeyUtil.createNew();
ProfileKey profileKey2 = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
@@ -130,13 +130,13 @@ public final class ProfileKeySetTest {
profileKeySet.addKeysFromGroupChange(changeBy(editor).profileKeyUpdate(member, profileKey2).build());
assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty());
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey2)));
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(member, profileKey2)));
}
@Test
public void authoritative_takes_priority_when_seen_first() {
UUID editor = UUID.randomUUID();
UUID member = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI member = ACI.from(UUID.randomUUID());
ProfileKey profileKey1 = ProfileKeyUtil.createNew();
ProfileKey profileKey2 = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
@@ -145,13 +145,13 @@ public final class ProfileKeySetTest {
profileKeySet.addKeysFromGroupChange(changeBy(editor).profileKeyUpdate(member, profileKey2).build());
assertTrue(profileKeySet.getProfileKeys().isEmpty());
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey1)));
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(member, profileKey1)));
}
@Test
public void authoritative_takes_priority_when_seen_second() {
UUID editor = UUID.randomUUID();
UUID member = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI member = ACI.from(UUID.randomUUID());
ProfileKey profileKey1 = ProfileKeyUtil.createNew();
ProfileKey profileKey2 = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
@@ -160,14 +160,14 @@ public final class ProfileKeySetTest {
profileKeySet.addKeysFromGroupChange(changeBy(member).profileKeyUpdate(member, profileKey2).build());
assertTrue(profileKeySet.getProfileKeys().isEmpty());
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey2)));
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(member, profileKey2)));
}
@Test
public void bad_profile_key() {
LogRecorder logRecorder = new LogRecorder();
UUID editor = UUID.randomUUID();
UUID member = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI member = ACI.from(UUID.randomUUID());
byte[] badProfileKey = new byte[10];
ProfileKeySet profileKeySet = new ProfileKeySet();
@@ -181,26 +181,26 @@ public final class ProfileKeySetTest {
@Test
public void new_requesting_member_if_editor_is_authoritative() {
UUID editor = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(editor).requestJoin(profileKey).build());
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(editor), profileKey)));
assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(editor, profileKey)));
assertTrue(profileKeySet.getProfileKeys().isEmpty());
}
@Test
public void new_requesting_member_if_not_editor_is_not_authoritative() {
UUID editor = UUID.randomUUID();
UUID requesting = UUID.randomUUID();
ACI editor = ACI.from(UUID.randomUUID());
ACI requesting = ACI.from(UUID.randomUUID());
ProfileKey profileKey = ProfileKeyUtil.createNew();
ProfileKeySet profileKeySet = new ProfileKeySet();
profileKeySet.addKeysFromGroupChange(changeBy(editor).requestJoin(requesting, profileKey).build());
assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty());
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(requesting), profileKey)));
assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(requesting, profileKey)));
}
}

View File

@@ -8,6 +8,8 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedString;
import org.thoughtcrime.securesms.testutil.LogRecorder;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.UUID;
@@ -261,7 +263,7 @@ public final class GroupStateMapperTest {
DecryptedGroup currentState = state(6);
ServerGroupLogEntry log7 = serverLogEntry(7);
DecryptedMember newMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup state7b = DecryptedGroup.newBuilder()
.setRevision(8)
@@ -323,12 +325,12 @@ public final class GroupStateMapperTest {
@Test
public void clears_changes_duplicated_in_the_placeholder() {
UUID newMemberUuid = UUID.randomUUID();
DecryptedMember newMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(newMemberUuid))
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = DecryptedMember.newBuilder()
.setAciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
@@ -343,7 +345,7 @@ public final class GroupStateMapperTest {
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditor(UuidUtil.toByteString(newMemberUuid))
.setEditorServiceIdBytes(newMemberAci.toByteString())
.addNewMembers(newMember)
.build());
@@ -357,13 +359,13 @@ public final class GroupStateMapperTest {
@Test
public void clears_changes_duplicated_in_a_non_placeholder() {
UUID editorUuid = UUID.randomUUID();
UUID newMemberUuid = UUID.randomUUID();
ACI editorAci = ACI.from(UUID.randomUUID());
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(newMemberUuid))
.setAciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(8)
@@ -378,14 +380,14 @@ public final class GroupStateMapperTest {
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditor(UuidUtil.toByteString(editorUuid))
.setEditorServiceIdBytes(editorAci.toByteString())
.addNewMembers(existingMember)
.addNewMembers(newMember)
.build());
DecryptedGroupChange expectedChange = DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditor(UuidUtil.toByteString(editorUuid))
.setEditorServiceIdBytes(editorAci.toByteString())
.addNewMembers(newMember)
.build();
@@ -399,12 +401,12 @@ public final class GroupStateMapperTest {
@Test
public void notices_changes_in_avatar_and_title_but_not_members_in_placeholder() {
UUID newMemberUuid = UUID.randomUUID();
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(newMemberUuid))
.setAciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
@@ -421,7 +423,7 @@ public final class GroupStateMapperTest {
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditor(UuidUtil.toByteString(newMemberUuid))
.setEditorServiceIdBytes(newMemberAci.toByteString())
.addNewMembers(newMember)
.build());
@@ -448,7 +450,7 @@ public final class GroupStateMapperTest {
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(2)
.setEditor(UuidUtil.toByteString(KNOWN_EDITOR))
.setEditorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.setNewTitle(DecryptedString.newBuilder().setValue(log1.getGroup().getTitle()))
.build());
@@ -457,7 +459,7 @@ public final class GroupStateMapperTest {
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1),
new LocalGroupLogEntry(log2.getGroup(), DecryptedGroupChange.newBuilder()
.setRevision(2)
.setEditor(UuidUtil.toByteString(KNOWN_EDITOR))
.setEditorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.build()))));
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
@@ -494,7 +496,7 @@ public final class GroupStateMapperTest {
private static DecryptedGroupChange change(int revision) {
return DecryptedGroupChange.newBuilder()
.setRevision(revision)
.setEditor(UuidUtil.toByteString(KNOWN_EDITOR))
.setEditorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + revision))
.build();
}

View File

@@ -428,7 +428,7 @@ class GroupsV2StateProcessorTest {
}
changeLog(101) {
change {
addDeleteMembers(randomMembers[1].uuid)
addDeleteMembers(randomMembers[1].aciBytes)
addModifiedProfileKeys(randomMembers[0])
}
}
@@ -449,7 +449,7 @@ class GroupsV2StateProcessorTest {
}
changeLog(101) {
change {
addDeleteMembers(randomMembers[1].uuid)
addDeleteMembers(randomMembers[1].aciBytes)
addModifiedProfileKeys(randomMembers[0])
}
}

View File

@@ -9,6 +9,8 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
import org.thoughtcrime.securesms.groups.v2.ChangeBuilder;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import java.util.Random;
@@ -22,7 +24,7 @@ public class GroupV2UpdateMessageUtilTest {
@Test
public void isJustAGroupLeave_whenEditorIsRemoved_shouldReturnTrue() {
// GIVEN
UUID alice = UUID.randomUUID();
ACI alice = ACI.from(UUID.randomUUID());
DecryptedGroupChange change = ChangeBuilder.changeBy(alice)
.deleteMember(alice)
.build();
@@ -45,8 +47,8 @@ public class GroupV2UpdateMessageUtilTest {
@Test
public void isJustAGroupLeave_whenOtherIsRemoved_shouldReturnFalse() {
// GIVEN
UUID alice = UUID.randomUUID();
UUID bob = UUID.randomUUID();
ACI alice = ACI.from(UUID.randomUUID());
ACI bob = ACI.from(UUID.randomUUID());
DecryptedGroupChange change = ChangeBuilder.changeBy(alice)
.deleteMember(bob)
.build();
@@ -69,8 +71,8 @@ public class GroupV2UpdateMessageUtilTest {
@Test
public void isJustAGroupLeave_whenEditorIsRemovedAndOtherChanges_shouldReturnFalse() {
// GIVEN
UUID alice = UUID.randomUUID();
UUID bob = UUID.randomUUID();
ACI alice = ACI.from(UUID.randomUUID());
ACI bob = ACI.from(UUID.randomUUID());
DecryptedGroupChange change = ChangeBuilder.changeBy(alice)
.deleteMember(alice)
.addMember(bob)
@@ -94,7 +96,7 @@ public class GroupV2UpdateMessageUtilTest {
@Test
public void isJoinRequestCancel_whenChangeRemovesRequestingMembers_shouldReturnTrue() {
// GIVEN
UUID alice = UUID.randomUUID();
ACI alice = ACI.from(UUID.randomUUID());
DecryptedGroupChange change = ChangeBuilder.changeBy(alice)
.denyRequest(alice)
.build();
@@ -117,8 +119,8 @@ public class GroupV2UpdateMessageUtilTest {
@Test
public void isJoinRequestCancel_whenChangeContainsNoRemoveRequestingMembers_shouldReturnFalse() {
// GIVEN
UUID alice = UUID.randomUUID();
UUID bob = UUID.randomUUID();
ACI alice = ACI.from(UUID.randomUUID());
ACI bob = ACI.from(UUID.randomUUID());
DecryptedGroupChange change = ChangeBuilder.changeBy(alice)
.deleteMember(alice)
.addMember(bob)