Convert SignalService, Database, Group, Payment, and other remaining protos to wire.

This commit is contained in:
Cody Henthorne
2023-09-18 15:32:43 -04:00
committed by Alex Hart
parent a6b7d0bcc5
commit efbd5cab85
267 changed files with 7100 additions and 7214 deletions

View File

@@ -35,15 +35,15 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 2
bodyRange.ranges.size assertIs 2
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 5
}
bodyRange.rangesList[1].apply {
bodyRange.ranges[1].apply {
style assertIs Style.ITALIC
start assertIs 10
length assertIs 5
@@ -57,15 +57,15 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 2
bodyRange.ranges.size assertIs 2
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 5
}
bodyRange.rangesList[1].apply {
bodyRange.ranges[1].apply {
style assertIs Style.ITALIC
start assertIs 3
length assertIs 7
@@ -79,9 +79,9 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 1
bodyRange.ranges.size assertIs 1
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 10
@@ -95,9 +95,9 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 1
bodyRange.ranges.size assertIs 1
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 10
@@ -111,15 +111,15 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 2
bodyRange.ranges.size assertIs 2
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 4
}
bodyRange.rangesList[1].apply {
bodyRange.ranges[1].apply {
style assertIs Style.BOLD
start assertIs 6
length assertIs 4
@@ -133,9 +133,9 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 1
bodyRange.ranges.size assertIs 1
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 10
@@ -160,9 +160,9 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 1
bodyRange.ranges.size assertIs 1
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 10
@@ -177,9 +177,9 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 1
bodyRange.ranges.size assertIs 1
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 8
@@ -193,15 +193,15 @@ class MessageStylerTest {
val bodyRange = MessageStyler.getStyling(text)!!
bodyRange.rangesCount assertIs 2
bodyRange.ranges.size assertIs 2
bodyRange.rangesList[0].apply {
bodyRange.ranges[0].apply {
style assertIs Style.BOLD
start assertIs 0
length assertIs 3
}
bodyRange.rangesList[1].apply {
bodyRange.ranges[1].apply {
style assertIs Style.BOLD
start assertIs 7
length assertIs 3

View File

@@ -8,111 +8,111 @@ class BodyRangeUtilTest {
@Test
fun testMentionBeforeBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(5).setLength(5).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(5).length(5).build())).build()
val adjustments = listOf(BodyAdjustment(0, 3, 1))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(3, updatedBodyRanges.getRanges(0).start)
assertEquals(5, updatedBodyRanges.getRanges(0).length)
assertEquals(3, updatedBodyRanges.ranges[0].start)
assertEquals(5, updatedBodyRanges.ranges[0].length)
}
@Test
fun textMentionAfterBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(5).setLength(5).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(5).length(5).build())).build()
val adjustments = listOf(BodyAdjustment(10, 3, 1))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(5, updatedBodyRanges.getRanges(0).start)
assertEquals(5, updatedBodyRanges.getRanges(0).length)
assertEquals(5, updatedBodyRanges.ranges[0].start)
assertEquals(5, updatedBodyRanges.ranges[0].length)
}
@Test
fun testMentionWithinBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(0).setLength(20).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(0).length(20).build())).build()
val adjustments = listOf(BodyAdjustment(5, 10, 1))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(0, updatedBodyRanges.getRanges(0).start)
assertEquals(11, updatedBodyRanges.getRanges(0).length)
assertEquals(0, updatedBodyRanges.ranges[0].start)
assertEquals(11, updatedBodyRanges.ranges[0].length)
}
@Test
fun testMentionWithinAndEndOfBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(0).setLength(5).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(0).length(5).build())).build()
val adjustments = listOf(BodyAdjustment(1, 4, 1))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(0, updatedBodyRanges.getRanges(0).start)
assertEquals(2, updatedBodyRanges.getRanges(0).length)
assertEquals(0, updatedBodyRanges.ranges[0].start)
assertEquals(2, updatedBodyRanges.ranges[0].length)
}
@Test
fun testDoubleMention() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(5).setLength(10).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(5).length(10).build())).build()
val adjustments = listOf(BodyAdjustment(0, 3, 1), BodyAdjustment(17, 10, 1))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(3, updatedBodyRanges.getRanges(0).start)
assertEquals(10, updatedBodyRanges.getRanges(0).length)
assertEquals(3, updatedBodyRanges.ranges[0].start)
assertEquals(10, updatedBodyRanges.ranges[0].length)
}
@Test
fun testResolvedMentionBeforeBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(10).setLength(20).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(10).length(20).build())).build()
val adjustments = listOf(BodyAdjustment(0, 1, 10))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(19, updatedBodyRanges.getRanges(0).start)
assertEquals(20, updatedBodyRanges.getRanges(0).length)
assertEquals(19, updatedBodyRanges.ranges[0].start)
assertEquals(20, updatedBodyRanges.ranges[0].length)
}
@Test
fun textResolvedMentionAfterBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(5).setLength(5).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(5).length(5).build())).build()
val adjustments = listOf(BodyAdjustment(10, 1, 10))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(5, updatedBodyRanges.getRanges(0).start)
assertEquals(5, updatedBodyRanges.getRanges(0).length)
assertEquals(5, updatedBodyRanges.ranges[0].start)
assertEquals(5, updatedBodyRanges.ranges[0].length)
}
@Test
fun testResolvedMentionWithinBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(0).setLength(20).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(0).length(20).build())).build()
val adjustments = listOf(BodyAdjustment(5, 1, 11))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(0, updatedBodyRanges.getRanges(0).start)
assertEquals(30, updatedBodyRanges.getRanges(0).length)
assertEquals(0, updatedBodyRanges.ranges[0].start)
assertEquals(30, updatedBodyRanges.ranges[0].length)
}
@Test
fun testResolvedMentionWithinAndEndOfBodyRange() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(0).setLength(2).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(0).length(2).build())).build()
val adjustments = listOf(BodyAdjustment(1, 1, 4))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(0, updatedBodyRanges.getRanges(0).start)
assertEquals(5, updatedBodyRanges.getRanges(0).length)
assertEquals(0, updatedBodyRanges.ranges[0].start)
assertEquals(5, updatedBodyRanges.ranges[0].length)
}
@Test
fun testDoubleResolvedMention() {
val bodyRangeList = BodyRangeList.newBuilder().addRanges(BodyRangeList.BodyRange.newBuilder().setStart(2).setLength(4).build()).build()
val bodyRangeList = BodyRangeList.Builder().ranges(listOf(BodyRangeList.BodyRange.Builder().start(2).length(4).build())).build()
val adjustments = listOf(BodyAdjustment(0, 1, 8), BodyAdjustment(7, 1, 11))
val updatedBodyRanges = bodyRangeList.adjustBodyRanges(adjustments)!!
assertEquals(9, updatedBodyRanges.getRanges(0).start)
assertEquals(4, updatedBodyRanges.getRanges(0).length)
assertEquals(9, updatedBodyRanges.ranges[0].start)
assertEquals(4, updatedBodyRanges.ranges[0].length)
}
}

View File

@@ -1,6 +1,6 @@
package org.thoughtcrime.securesms.database
import com.google.protobuf.ByteString
import okio.ByteString.Companion.toByteString
import org.signal.libsignal.zkgroup.groups.GroupMasterKey
import org.signal.storageservice.protos.groups.AccessControl
import org.signal.storageservice.protos.groups.GroupChange
@@ -24,11 +24,11 @@ import org.whispersystems.signalservice.api.push.ServiceId
import java.util.Optional
fun DecryptedGroupChange.Builder.setNewDescription(description: String) {
newDescription = DecryptedString.newBuilder().setValue(description).build()
newDescription = DecryptedString(value_ = description)
}
fun DecryptedGroupChange.Builder.setNewTitle(title: String) {
newTitle = DecryptedString.newBuilder().setValue(title).build()
newTitle = DecryptedString(value_ = title)
}
class ChangeLog(private val revision: Int) {
@@ -36,7 +36,7 @@ class ChangeLog(private val revision: Int) {
var groupChange: DecryptedGroupChange? = null
fun change(init: DecryptedGroupChange.Builder.() -> Unit) {
val builder = DecryptedGroupChange.newBuilder().setRevision(revision)
val builder = DecryptedGroupChange.Builder().revision(revision)
builder.init()
groupChange = builder.build()
}
@@ -46,12 +46,12 @@ class ChangeLog(private val revision: Int) {
title: String = extendGroup?.title ?: "",
avatar: String = extendGroup?.avatar ?: "",
description: String = extendGroup?.description ?: "",
accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl.getDefaultInstance(),
members: List<DecryptedMember> = extendGroup?.membersList ?: emptyList(),
pendingMembers: List<DecryptedPendingMember> = extendGroup?.pendingMembersList ?: emptyList(),
requestingMembers: List<DecryptedRequestingMember> = extendGroup?.requestingMembersList ?: emptyList(),
accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl(),
members: List<DecryptedMember> = extendGroup?.members ?: emptyList(),
pendingMembers: List<DecryptedPendingMember> = extendGroup?.pendingMembers ?: emptyList(),
requestingMembers: List<DecryptedRequestingMember> = extendGroup?.requestingMembers ?: emptyList(),
inviteLinkPassword: ByteArray = extendGroup?.inviteLinkPassword?.toByteArray() ?: ByteArray(0),
disappearingMessageTimer: DecryptedTimer = extendGroup?.disappearingMessagesTimer ?: DecryptedTimer.getDefaultInstance()
disappearingMessageTimer: DecryptedTimer = extendGroup?.disappearingMessagesTimer ?: DecryptedTimer()
) {
groupSnapshot = decryptedGroup(revision, title, avatar, description, accessControl, members, pendingMembers, requestingMembers, inviteLinkPassword, disappearingMessageTimer)
}
@@ -72,15 +72,15 @@ class ChangeSet {
}
class GroupChangeData(private val revision: Int, private val groupOperations: GroupsV2Operations.GroupOperations) {
private val groupChangeBuilder: GroupChange.Builder = GroupChange.newBuilder()
private val actionsBuilder: GroupChange.Actions.Builder = GroupChange.Actions.newBuilder()
private val groupChangeBuilder: GroupChange.Builder = GroupChange.Builder()
private val actionsBuilder: GroupChange.Actions.Builder = GroupChange.Actions.Builder()
var changeEpoch: Int = GroupsV2Operations.HIGHEST_KNOWN_EPOCH
val groupChange: GroupChange
get() {
return groupChangeBuilder
.setChangeEpoch(changeEpoch)
.setActions(actionsBuilder.setRevision(revision).build().toByteString())
.changeEpoch(changeEpoch)
.actions(actionsBuilder.revision(revision).build().encodeByteString())
.build()
}
@@ -89,11 +89,11 @@ class GroupChangeData(private val revision: Int, private val groupOperations: Gr
}
fun deleteMember(serviceId: ServiceId) {
actionsBuilder.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(groupOperations.encryptServiceId(serviceId)))
actionsBuilder.deleteMembers += GroupChange.Actions.DeleteMemberAction(deletedUserId = groupOperations.encryptServiceId(serviceId))
}
fun modifyRole(serviceId: ServiceId, role: Member.Role) {
actionsBuilder.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(groupOperations.encryptServiceId(serviceId)).setRole(role))
actionsBuilder.modifyMemberRoles += GroupChange.Actions.ModifyMemberRoleAction(userId = groupOperations.encryptServiceId(serviceId), role = role)
}
}
@@ -113,12 +113,12 @@ class GroupStateTestData(private val masterKey: GroupMasterKey, private val grou
title: String = "",
avatar: String = "",
description: String = "",
accessControl: AccessControl = AccessControl.getDefaultInstance(),
accessControl: AccessControl = AccessControl(),
members: List<DecryptedMember> = emptyList(),
pendingMembers: List<DecryptedPendingMember> = emptyList(),
requestingMembers: List<DecryptedRequestingMember> = emptyList(),
inviteLinkPassword: ByteArray = ByteArray(0),
disappearingMessageTimer: DecryptedTimer = DecryptedTimer.getDefaultInstance()
disappearingMessageTimer: DecryptedTimer = DecryptedTimer()
) {
localState = decryptedGroup(revision, title, avatar, description, accessControl, members, pendingMembers, requestingMembers, inviteLinkPassword, disappearingMessageTimer)
groupRecord = groupRecord(masterKey, localState!!, active = active)
@@ -130,12 +130,12 @@ class GroupStateTestData(private val masterKey: GroupMasterKey, private val grou
title: String = extendGroup?.title ?: "",
avatar: String = extendGroup?.avatar ?: "",
description: String = extendGroup?.description ?: "",
accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl.getDefaultInstance(),
members: List<DecryptedMember> = extendGroup?.membersList ?: emptyList(),
pendingMembers: List<DecryptedPendingMember> = extendGroup?.pendingMembersList ?: emptyList(),
requestingMembers: List<DecryptedRequestingMember> = extendGroup?.requestingMembersList ?: emptyList(),
accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl(),
members: List<DecryptedMember> = extendGroup?.members ?: emptyList(),
pendingMembers: List<DecryptedPendingMember> = extendGroup?.pendingMembers ?: emptyList(),
requestingMembers: List<DecryptedRequestingMember> = extendGroup?.requestingMembers ?: emptyList(),
inviteLinkPassword: ByteArray = extendGroup?.inviteLinkPassword?.toByteArray() ?: ByteArray(0),
disappearingMessageTimer: DecryptedTimer = extendGroup?.disappearingMessagesTimer ?: DecryptedTimer.getDefaultInstance()
disappearingMessageTimer: DecryptedTimer = extendGroup?.disappearingMessagesTimer ?: DecryptedTimer()
) {
serverState = decryptedGroup(revision, title, avatar, description, accessControl, members, pendingMembers, requestingMembers, inviteLinkPassword, disappearingMessageTimer)
}
@@ -188,7 +188,7 @@ fun groupRecord(
mms,
masterKey.serialize(),
decryptedGroup.revision,
decryptedGroup.toByteArray(),
decryptedGroup.encode(),
distributionId,
System.currentTimeMillis()
)
@@ -200,26 +200,24 @@ fun decryptedGroup(
title: String = "",
avatar: String = "",
description: String = "",
accessControl: AccessControl = AccessControl.getDefaultInstance(),
accessControl: AccessControl = AccessControl(),
members: List<DecryptedMember> = emptyList(),
pendingMembers: List<DecryptedPendingMember> = emptyList(),
requestingMembers: List<DecryptedRequestingMember> = emptyList(),
inviteLinkPassword: ByteArray = ByteArray(0),
disappearingMessageTimer: DecryptedTimer = DecryptedTimer.getDefaultInstance()
disappearingMessageTimer: DecryptedTimer = DecryptedTimer()
): DecryptedGroup {
val builder = DecryptedGroup.newBuilder()
.setAccessControl(accessControl)
.setAvatar(avatar)
.setAvatarBytes(ByteString.EMPTY)
.setDescription(description)
.setDisappearingMessagesTimer(disappearingMessageTimer)
.setInviteLinkPassword(ByteString.copyFrom(inviteLinkPassword))
.setIsAnnouncementGroup(EnabledState.DISABLED)
.setTitle(title)
.setRevision(revision)
.addAllMembers(members)
.addAllPendingMembers(pendingMembers)
.addAllRequestingMembers(requestingMembers)
return builder.build()
return DecryptedGroup(
accessControl = accessControl,
avatar = avatar,
description = description,
disappearingMessagesTimer = disappearingMessageTimer,
inviteLinkPassword = inviteLinkPassword.toByteString(),
isAnnouncementGroup = EnabledState.DISABLED,
title = title,
revision = revision,
members = members,
pendingMembers = pendingMembers,
requestingMembers = requestingMembers
)
}

View File

@@ -1,11 +1,13 @@
package org.thoughtcrime.securesms.database;
import com.google.protobuf.ByteString;
import org.junit.Test;
import org.thoughtcrime.securesms.payments.proto.PaymentMetaData;
import org.thoughtcrime.securesms.util.Util;
import java.util.Collections;
import okio.ByteString;
import static org.junit.Assert.assertArrayEquals;
public final class PaymentMetaDataUtilTest {
@@ -13,9 +15,8 @@ public final class PaymentMetaDataUtilTest {
@Test
public void extract_single_public_key() {
byte[] random = Util.getSecretBytes(32);
byte[] bytes = PaymentMetaDataUtil.receiptPublic(PaymentMetaData.newBuilder()
.setMobileCoinTxoIdentification(PaymentMetaData.MobileCoinTxoIdentification.newBuilder()
.addPublicKey(ByteString.copyFrom(random))).build());
byte[] bytes = PaymentMetaDataUtil.receiptPublic(new PaymentMetaData.Builder().mobileCoinTxoIdentification(new PaymentMetaData.MobileCoinTxoIdentification.Builder().publicKey(Collections.singletonList(ByteString.of(random))).build()).build());
assertArrayEquals(random, bytes);
}
}

View File

@@ -26,11 +26,10 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceIds;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Arrays;
import java.util.Collections;
@@ -38,6 +37,8 @@ import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import kotlin.collections.CollectionsKt;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -994,10 +995,11 @@ public final class GroupsV2UpdateMessageProducerTest {
}
private String describeGroupLinkChange(@Nullable ACI editor, @NonNull AccessControl.AccessRequired fromAccess, AccessControl.AccessRequired toAccess){
DecryptedGroup previousGroupState = DecryptedGroup.newBuilder()
.setAccessControl(AccessControl.newBuilder()
.setAddFromInviteLink(fromAccess))
.build();
DecryptedGroup previousGroupState = new DecryptedGroup.Builder()
.accessControl(new AccessControl.Builder()
.addFromInviteLink(fromAccess)
.build())
.build();
DecryptedGroupChange change = (editor != null ? changeBy(editor) : changeByUnknown()).inviteLinkAccess(toAccess)
.build();
@@ -1434,7 +1436,7 @@ public final class GroupsV2UpdateMessageProducerTest {
}
private @NonNull String describeNewGroup(@NonNull DecryptedGroup group) {
return describeNewGroup(group, DecryptedGroupChange.getDefaultInstance());
return describeNewGroup(group, new DecryptedGroupChange());
}
private @NonNull String describeNewGroup(@NonNull DecryptedGroup group, @NonNull DecryptedGroupChange groupChange) {
@@ -1467,23 +1469,19 @@ public final class GroupsV2UpdateMessageProducerTest {
private final DecryptedGroup.Builder builder;
GroupStateBuilder(@NonNull ACI foundingMember, int revision) {
builder = DecryptedGroup.newBuilder()
.setRevision(revision)
.addMembers(DecryptedMember.newBuilder()
.setAciBytes(foundingMember.toByteString()));
builder = new DecryptedGroup.Builder()
.revision(revision)
.members(Collections.singletonList(new DecryptedMember.Builder().aciBytes(foundingMember.toByteString()).build()));
}
GroupStateBuilder invite(@NonNull ACI inviter, @NonNull ServiceId invitee) {
builder.addPendingMembers(DecryptedPendingMember.newBuilder()
.setServiceIdBytes(invitee.toByteString())
.setAddedByAci(inviter.toByteString()));
return this;
builder.pendingMembers(CollectionsKt.plus(builder.pendingMembers, new DecryptedPendingMember.Builder().serviceIdBytes(invitee.toByteString()).addedByAci(inviter.toByteString()).build()));
return this;
}
GroupStateBuilder member(@NonNull ACI member) {
builder.addMembers(DecryptedMember.newBuilder()
.setAciBytes(member.toByteString()));
return this;
builder.members(CollectionsKt.plus(builder.members, new DecryptedMember.Builder().aciBytes(member.toByteString()).build()));
return this;
}
public DecryptedGroup build() {

View File

@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.database.model
import com.google.protobuf.ByteString
import okio.ByteString
import okio.ByteString.Companion.toByteString
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.junit.Test
@@ -10,7 +11,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2
import org.thoughtcrime.securesms.groups.v2.ChangeBuilder
import org.thoughtcrime.securesms.util.Base64
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
import org.whispersystems.signalservice.internal.push.GroupContextV2
import java.util.Random
import java.util.UUID
@@ -34,7 +35,7 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest {
*/
@Test(expected = AssertionError::class)
fun throwOnEmptyGv2Change() {
val groupContext = DecryptedGroupV2Context.getDefaultInstance()
val groupContext = DecryptedGroupV2Context()
val messageRecord = mock<MessageRecord> {
on { decryptedGroupV2Context } doReturn groupContext
@@ -53,13 +54,13 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest {
val change = ChangeBuilder.changeBy(alice)
.requestJoin(alice)
.build()
.toBuilder()
.setRevision(9)
.newBuilder()
.revision(9)
.build()
val context = DecryptedGroupV2Context.newBuilder()
.setContext(SignalServiceProtos.GroupContextV2.newBuilder().setMasterKey(ByteString.copyFrom(randomBytes())))
.setChange(change)
val context = DecryptedGroupV2Context.Builder()
.context(GroupContextV2.Builder().masterKey(randomBytes().toByteString()).build())
.change(change)
.build()
val messageRecord = mock<MessageRecord> {
@@ -68,11 +69,11 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest {
val newEncodedBody = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(messageRecord, 10, aliceByteString)
val newContext = DecryptedGroupV2Context.parseFrom(Base64.decode(newEncodedBody))
val newContext = DecryptedGroupV2Context.ADAPTER.decode(Base64.decode(newEncodedBody))
assertThat("revision updated to 10", newContext.change.revision, `is`(10))
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))
assertThat("revision updated to 10", newContext.change!!.revision, `is`(10))
assertThat("change should retain join request", newContext.change!!.newRequestingMembers[0].aciBytes, `is`(aliceByteString))
assertThat("change should add delete request", newContext.change!!.deleteRequestingMembers[0], `is`(aliceByteString))
}
private fun randomBytes(): ByteArray {

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.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))
assertThat("Self is no longer in the group", patchedGroup.members.find { it.aciBytes == selfAci.toByteString() }, Matchers.nullValue())
assertThat("Other is now an admin in the group", patchedGroup.members.find { it.aciBytes == otherAci.toByteString() }?.role, `is`(Member.Role.ADMINISTRATOR))
}
}
}

View File

@@ -3,8 +3,6 @@ package org.thoughtcrime.securesms.groups.v2;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.protobuf.ByteString;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.protos.groups.AccessControl;
@@ -21,6 +19,9 @@ import org.signal.storageservice.protos.groups.local.DecryptedTimer;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import kotlin.collections.CollectionsKt;
import okio.ByteString;
public final class ChangeBuilder {
private final DecryptedGroupChange.Builder builder;
@@ -36,44 +37,36 @@ public final class ChangeBuilder {
ChangeBuilder(@NonNull ACI editor) {
this.editor = editor;
this.builder = DecryptedGroupChange.newBuilder()
.setEditorServiceIdBytes(editor.toByteString());
this.builder = new DecryptedGroupChange.Builder().editorServiceIdBytes(editor.toByteString());
}
ChangeBuilder() {
this.editor = null;
this.builder = DecryptedGroupChange.newBuilder();
this.builder = new DecryptedGroupChange.Builder();
}
public ChangeBuilder addMember(@NonNull ACI newMember) {
builder.addNewMembers(DecryptedMember.newBuilder()
.setAciBytes(newMember.toByteString()));
builder.newMembers(CollectionsKt.plus(builder.newMembers, new DecryptedMember.Builder().aciBytes(newMember.toByteString()).build()));
return this;
}
public ChangeBuilder addMember(@NonNull ACI newMember, @NonNull ProfileKey profileKey) {
builder.addNewMembers(DecryptedMember.newBuilder()
.setAciBytes(newMember.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
builder.newMembers(CollectionsKt.plus(builder.newMembers, new DecryptedMember.Builder().aciBytes(newMember.toByteString()).profileKey(ByteString.of(profileKey.serialize())).build()));
return this;
}
public ChangeBuilder deleteMember(@NonNull ACI removedMember) {
builder.addDeleteMembers(removedMember.toByteString());
builder.deleteMembers(CollectionsKt.plus(builder.deleteMembers, removedMember.toByteString()));
return this;
}
public ChangeBuilder promoteToAdmin(@NonNull ACI member) {
builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
.setRole(Member.Role.ADMINISTRATOR)
.setAciBytes(member.toByteString()));
builder.modifyMemberRoles(CollectionsKt.plus(builder.modifyMemberRoles, new DecryptedModifyMemberRole.Builder().role(Member.Role.ADMINISTRATOR).aciBytes(member.toByteString()).build()));
return this;
}
public ChangeBuilder demoteToMember(@NonNull ACI member) {
builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
.setRole(Member.Role.DEFAULT)
.setAciBytes(member.toByteString()));
builder.modifyMemberRoles(CollectionsKt.plus(builder.modifyMemberRoles, new DecryptedModifyMemberRole.Builder().role(Member.Role.DEFAULT).aciBytes(member.toByteString()).build()));
return this;
}
@@ -82,20 +75,17 @@ public final class ChangeBuilder {
}
public ChangeBuilder inviteBy(@NonNull ACI potentialMember, @NonNull ACI inviter) {
builder.addNewPendingMembers(DecryptedPendingMember.newBuilder()
.setServiceIdBytes(potentialMember.toByteString())
.setAddedByAci(inviter.toByteString()));
builder.newPendingMembers(CollectionsKt.plus(builder.newPendingMembers, new DecryptedPendingMember.Builder().serviceIdBytes(potentialMember.toByteString()).addedByAci(inviter.toByteString()).build()));
return this;
}
public ChangeBuilder uninvite(@NonNull ACI pendingMember) {
builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
.setServiceIdBytes(pendingMember.toByteString()));
builder.deletePendingMembers(CollectionsKt.plus(builder.deletePendingMembers, new DecryptedPendingMemberRemoval.Builder().serviceIdBytes(pendingMember.toByteString()).build()));
return this;
}
public ChangeBuilder promote(@NonNull ACI pendingMember) {
builder.addPromotePendingMembers(DecryptedMember.newBuilder().setAciBytes(pendingMember.toByteString()));
builder.promotePendingMembers(CollectionsKt.plus(builder.promotePendingMembers, new DecryptedMember.Builder().aciBytes(pendingMember.toByteString()).build()));
return this;
}
@@ -104,54 +94,47 @@ public final class ChangeBuilder {
}
public ChangeBuilder profileKeyUpdate(@NonNull ACI member, @NonNull byte[] profileKey) {
builder.addModifiedProfileKeys(DecryptedMember.newBuilder()
.setAciBytes(member.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey)));
builder.modifiedProfileKeys(CollectionsKt.plus(builder.modifiedProfileKeys, new DecryptedMember.Builder().aciBytes(member.toByteString()).profileKey(ByteString.of(profileKey)).build()));
return this;
}
public ChangeBuilder promote(@NonNull ACI pendingMember, @NonNull ProfileKey profileKey) {
builder.addPromotePendingMembers(DecryptedMember.newBuilder()
.setAciBytes(pendingMember.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
builder.promotePendingMembers(CollectionsKt.plus(builder.promotePendingMembers, new DecryptedMember.Builder().aciBytes(pendingMember.toByteString()).profileKey(ByteString.of(profileKey.serialize())).build()));
return this;
}
public ChangeBuilder title(@NonNull String newTitle) {
builder.setNewTitle(DecryptedString.newBuilder()
.setValue(newTitle));
builder.newTitle(new DecryptedString.Builder().value_(newTitle).build());
return this;
}
public ChangeBuilder avatar(@NonNull String newAvatar) {
builder.setNewAvatar(DecryptedString.newBuilder()
.setValue(newAvatar));
builder.newAvatar(new DecryptedString.Builder().value_(newAvatar).build());
return this;
}
public ChangeBuilder timer(int duration) {
builder.setNewTimer(DecryptedTimer.newBuilder()
.setDuration(duration));
builder.newTimer(new DecryptedTimer.Builder().duration(duration).build());
return this;
}
public ChangeBuilder attributeAccess(@NonNull AccessControl.AccessRequired accessRequired) {
builder.setNewAttributeAccess(accessRequired);
builder.newAttributeAccess(accessRequired);
return this;
}
public ChangeBuilder membershipAccess(@NonNull AccessControl.AccessRequired accessRequired) {
builder.setNewMemberAccess(accessRequired);
builder.newMemberAccess(accessRequired);
return this;
}
public ChangeBuilder inviteLinkAccess(@NonNull AccessControl.AccessRequired accessRequired) {
builder.setNewInviteLinkAccess(accessRequired);
builder.newInviteLinkAccess(accessRequired);
return this;
}
public ChangeBuilder resetGroupLink() {
builder.setNewInviteLinkPassword(ByteString.copyFrom(GroupLinkPassword.createNew().serialize()));
builder.newInviteLinkPassword(ByteString.of(GroupLinkPassword.createNew().serialize()));
return this;
}
@@ -170,21 +153,17 @@ public final class ChangeBuilder {
}
public ChangeBuilder requestJoin(@NonNull ACI requester, @NonNull ProfileKey profileKey) {
builder.addNewRequestingMembers(DecryptedRequestingMember.newBuilder()
.setAciBytes(requester.toByteString())
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
builder.newRequestingMembers(CollectionsKt.plus(builder.newRequestingMembers, new DecryptedRequestingMember.Builder().aciBytes(requester.toByteString()).profileKey(ByteString.of(profileKey.serialize())).build()));
return this;
}
public ChangeBuilder approveRequest(@NonNull ACI approvedMember) {
builder.addPromoteRequestingMembers(DecryptedApproveMember.newBuilder()
.setRole(Member.Role.DEFAULT)
.setAciBytes(approvedMember.toByteString()));
builder.promoteRequestingMembers(CollectionsKt.plus(builder.promoteRequestingMembers, new DecryptedApproveMember.Builder().role(Member.Role.DEFAULT).aciBytes(approvedMember.toByteString()).build()));
return this;
}
public ChangeBuilder denyRequest(@NonNull ACI approvedMember) {
builder.addDeleteRequestingMembers(approvedMember.toByteString());
builder.deleteRequestingMembers(CollectionsKt.plus(builder.deleteRequestingMembers, approvedMember.toByteString()));
return this;
}

View File

@@ -2,9 +2,6 @@ package org.thoughtcrime.securesms.groups.v2;
import androidx.annotation.NonNull;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Test;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.storageservice.protos.groups.GroupInviteLink;
@@ -13,6 +10,8 @@ import org.whispersystems.util.Base64UrlSafe;
import java.io.IOException;
import okio.ByteString;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertNull;
@@ -70,7 +69,7 @@ public final class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
public void bad_protobuf() {
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(InvalidProtocolBufferException.class);
.hasCauseExactlyInstanceOf(IllegalStateException.class);
}
@Test
@@ -99,12 +98,13 @@ public final class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
private static String createEncodedProtobuf(@NonNull byte[] groupMasterKey,
@NonNull byte[] passwordBytes)
{
return Base64UrlSafe.encodeBytesWithoutPadding(GroupInviteLink.newBuilder()
.setV1Contents(GroupInviteLink.GroupInviteLinkContentsV1.newBuilder()
.setGroupMasterKey(ByteString.copyFrom(groupMasterKey))
.setInviteLinkPassword(ByteString.copyFrom(passwordBytes)))
.build()
.toByteArray());
return Base64UrlSafe.encodeBytesWithoutPadding(new GroupInviteLink.Builder()
.v1Contents(new GroupInviteLink.GroupInviteLinkContentsV1.Builder()
.groupMasterKey(ByteString.of(groupMasterKey))
.inviteLinkPassword(ByteString.of(passwordBytes))
.build())
.build()
.encode());
}
}

View File

@@ -36,10 +36,10 @@ public final class GlobalGroupStateTest {
}
private static DecryptedGroup state(int revision) {
return DecryptedGroup.newBuilder().setRevision(revision).build();
return new DecryptedGroup.Builder().revision(revision).build();
}
private static DecryptedGroupChange change(int revision) {
return DecryptedGroupChange.newBuilder().setRevision(revision).build();
return new DecryptedGroupChange.Builder().revision(revision).build();
}
}

View File

@@ -8,12 +8,14 @@ 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.Collections;
import java.util.UUID;
import kotlin.collections.CollectionsKt;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -199,31 +201,31 @@ public final class GroupStateMapperTest {
public void known_group_three_states_to_update_update_latest_handle_gap_with_changes() {
DecryptedGroup currentState = state(0);
ServerGroupLogEntry log1 = serverLogEntry(1);
DecryptedGroup state3a = DecryptedGroup.newBuilder()
.setRevision(3)
.setTitle("Group Revision " + 3)
.build();
DecryptedGroup state3 = DecryptedGroup.newBuilder()
.setRevision(3)
.setTitle("Group Revision " + 3)
.setAvatar("Lost Avatar Update")
.build();
ServerGroupLogEntry log3 = new ServerGroupLogEntry(state3, change(3));
DecryptedGroup state4 = DecryptedGroup.newBuilder()
.setRevision(4)
.setTitle("Group Revision " + 4)
.setAvatar("Lost Avatar Update")
.build();
ServerGroupLogEntry log4 = new ServerGroupLogEntry(state4, change(4));
DecryptedGroup state3a = new DecryptedGroup.Builder()
.revision(3)
.title("Group Revision " + 3)
.build();
DecryptedGroup state3 = new DecryptedGroup.Builder()
.revision(3)
.title("Group Revision " + 3)
.avatar("Lost Avatar Update")
.build();
ServerGroupLogEntry log3 = new ServerGroupLogEntry(state3, change(3));
DecryptedGroup state4 = new DecryptedGroup.Builder()
.revision(4)
.title("Group Revision " + 4)
.avatar("Lost Avatar Update")
.build();
ServerGroupLogEntry log4 = new ServerGroupLogEntry(state4, change(4));
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log3, log4)), LATEST);
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1),
new LocalGroupLogEntry(state3a, log3.getChange()),
new LocalGroupLogEntry(state3, DecryptedGroupChange.newBuilder()
.setRevision(3)
.setNewAvatar(DecryptedString.newBuilder().setValue("Lost Avatar Update"))
.build()),
new LocalGroupLogEntry(state3, new DecryptedGroupChange.Builder()
.revision(3)
.newAvatar(new DecryptedString.Builder().value_("Lost Avatar Update").build())
.build()),
asLocal(log4))));
assertNewState(new GlobalGroupState(log4.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
@@ -262,35 +264,35 @@ public final class GroupStateMapperTest {
public void updates_with_a_server_mismatch_inserts_additional_update() {
DecryptedGroup currentState = state(6);
ServerGroupLogEntry log7 = serverLogEntry(7);
DecryptedMember newMember = DecryptedMember.newBuilder()
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup state7b = DecryptedGroup.newBuilder()
.setRevision(8)
.setTitle("Group Revision " + 8)
.build();
DecryptedGroup state8 = DecryptedGroup.newBuilder()
.setRevision(8)
.setTitle("Group Revision " + 8)
.addMembers(newMember)
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(state8,
change(8) );
ServerGroupLogEntry log9 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
.setRevision(9)
.addMembers(newMember)
.setTitle("Group Revision " + 9)
.build(),
change(9) );
DecryptedMember newMember = new DecryptedMember.Builder()
.aciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup state7b = new DecryptedGroup.Builder()
.revision(8)
.title("Group Revision " + 8)
.build();
DecryptedGroup state8 = new DecryptedGroup.Builder()
.revision(8)
.title("Group Revision " + 8)
.members(Collections.singletonList(newMember))
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(state8,
change(8));
ServerGroupLogEntry log9 = new ServerGroupLogEntry(new DecryptedGroup.Builder()
.revision(9)
.members(Collections.singletonList(newMember))
.title("Group Revision " + 9)
.build(),
change(9));
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log7, log8, log9)), LATEST);
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log7),
new LocalGroupLogEntry(state7b, log8.getChange()),
new LocalGroupLogEntry(state8, DecryptedGroupChange.newBuilder()
.setRevision(8)
.addNewMembers(newMember)
.build()),
new LocalGroupLogEntry(state8, new DecryptedGroupChange.Builder()
.revision(8)
.newMembers(Collections.singletonList(newMember))
.build()),
asLocal(log9))));
assertNewState(new GlobalGroupState(log9.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
assertEquals(log9.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
@@ -310,11 +312,11 @@ public final class GroupStateMapperTest {
@Test
public void no_repair_change_is_posted_if_the_local_state_is_a_placeholder() {
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
.setTitle("Incorrect group title, Revision " + 6)
.build();
ServerGroupLogEntry log6 = serverLogEntry(6);
DecryptedGroup currentState = new DecryptedGroup.Builder()
.revision(GroupStateMapper.PLACEHOLDER_REVISION)
.title("Incorrect group title, Revision " + 6)
.build();
ServerGroupLogEntry log6 = serverLogEntry(6);
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log6)), LATEST);
@@ -325,29 +327,28 @@ public final class GroupStateMapperTest {
@Test
public void clears_changes_duplicated_in_the_placeholder() {
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = DecryptedMember.newBuilder()
.setAciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = DecryptedMember.newBuilder()
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
.setTitle("Group Revision " + 8)
.addMembers(newMember)
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
.setRevision(8)
.addMembers(newMember)
.addMembers(existingMember)
.setTitle("Group Revision " + 8)
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditorServiceIdBytes(newMemberAci.toByteString())
.addNewMembers(newMember)
.build());
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = new DecryptedMember.Builder()
.aciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = new DecryptedMember.Builder()
.aciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = new DecryptedGroup.Builder()
.revision(GroupStateMapper.PLACEHOLDER_REVISION)
.title("Group Revision " + 8)
.members(Collections.singletonList(newMember))
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(new DecryptedGroup.Builder()
.revision(8)
.members(CollectionsKt.plus(Collections.singletonList(existingMember), newMember))
.title("Group Revision " + 8)
.build(),
new DecryptedGroupChange.Builder()
.revision(8)
.editorServiceIdBytes(newMemberAci.toByteString())
.newMembers(Collections.singletonList(newMember))
.build());
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log8)), LATEST);
@@ -359,37 +360,35 @@ public final class GroupStateMapperTest {
@Test
public void clears_changes_duplicated_in_a_non_placeholder() {
ACI editorAci = ACI.from(UUID.randomUUID());
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = DecryptedMember.newBuilder()
.setAciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = DecryptedMember.newBuilder()
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(8)
.setTitle("Group Revision " + 8)
.addMembers(existingMember)
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
.setRevision(8)
.addMembers(existingMember)
.addMembers(newMember)
.setTitle("Group Revision " + 8)
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditorServiceIdBytes(editorAci.toByteString())
.addNewMembers(existingMember)
.addNewMembers(newMember)
.build());
ACI editorAci = ACI.from(UUID.randomUUID());
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = new DecryptedMember.Builder()
.aciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = new DecryptedMember.Builder()
.aciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = new DecryptedGroup.Builder()
.revision(8)
.title("Group Revision " + 8)
.members(Collections.singletonList(existingMember))
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(new DecryptedGroup.Builder()
.revision(8)
.members(CollectionsKt.plus(Collections.singletonList(existingMember), newMember))
.title("Group Revision " + 8)
.build(),
new DecryptedGroupChange.Builder()
.revision(8)
.editorServiceIdBytes(editorAci.toByteString())
.newMembers(CollectionsKt.plus(Collections.singletonList(existingMember), newMember))
.build());
DecryptedGroupChange expectedChange = DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditorServiceIdBytes(editorAci.toByteString())
.addNewMembers(newMember)
.build();
DecryptedGroupChange expectedChange = new DecryptedGroupChange.Builder()
.revision(8)
.editorServiceIdBytes(editorAci.toByteString())
.newMembers(Collections.singletonList(newMember))
.build();
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log8)), LATEST);
@@ -401,37 +400,36 @@ public final class GroupStateMapperTest {
@Test
public void notices_changes_in_avatar_and_title_but_not_members_in_placeholder() {
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = DecryptedMember.newBuilder()
.setAciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = DecryptedMember.newBuilder()
.setAciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
.setTitle("Incorrect group title")
.setAvatar("Incorrect group avatar")
.addMembers(newMember)
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
.setRevision(8)
.addMembers(newMember)
.addMembers(existingMember)
.setTitle("Group Revision " + 8)
.setAvatar("Group Avatar " + 8)
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(8)
.setEditorServiceIdBytes(newMemberAci.toByteString())
.addNewMembers(newMember)
.build());
ACI newMemberAci = ACI.from(UUID.randomUUID());
DecryptedMember newMember = new DecryptedMember.Builder()
.aciBytes(newMemberAci.toByteString())
.build();
DecryptedMember existingMember = new DecryptedMember.Builder()
.aciBytes(ACI.from(UUID.randomUUID()).toByteString())
.build();
DecryptedGroup currentState = new DecryptedGroup.Builder()
.revision(GroupStateMapper.PLACEHOLDER_REVISION)
.title("Incorrect group title")
.avatar("Incorrect group avatar")
.members(Collections.singletonList(newMember))
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(new DecryptedGroup.Builder()
.revision(8)
.members(CollectionsKt.plus(Collections.singletonList(existingMember), newMember))
.title("Group Revision " + 8)
.avatar("Group Avatar " + 8)
.build(),
new DecryptedGroupChange.Builder()
.revision(8)
.editorServiceIdBytes(newMemberAci.toByteString())
.newMembers(Collections.singletonList(newMember))
.build());
DecryptedGroupChange expectedChange = DecryptedGroupChange.newBuilder()
.setRevision(8)
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + 8))
.setNewAvatar(DecryptedString.newBuilder().setValue("Group Avatar " + 8))
.build();
DecryptedGroupChange expectedChange = new DecryptedGroupChange.Builder()
.revision(8)
.newTitle(new DecryptedString.Builder().value_("Group Revision " + 8).build())
.newAvatar(new DecryptedString.Builder().value_("Group Avatar " + 8).build())
.build();
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log8)), LATEST);
@@ -445,22 +443,22 @@ public final class GroupStateMapperTest {
public void no_actual_change() {
DecryptedGroup currentState = state(0);
ServerGroupLogEntry log1 = serverLogEntry(1);
ServerGroupLogEntry log2 = new ServerGroupLogEntry(DecryptedGroup.newBuilder(log1.getGroup())
.setRevision(2)
.build(),
DecryptedGroupChange.newBuilder()
.setRevision(2)
.setEditorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.setNewTitle(DecryptedString.newBuilder().setValue(log1.getGroup().getTitle()))
.build());
ServerGroupLogEntry log2 = new ServerGroupLogEntry(log1.getGroup().newBuilder()
.revision(2)
.build(),
new DecryptedGroupChange.Builder()
.revision(2)
.editorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.newTitle(new DecryptedString.Builder().value_(log1.getGroup().title).build())
.build());
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2)), 2);
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1),
new LocalGroupLogEntry(log2.getGroup(), DecryptedGroupChange.newBuilder()
.setRevision(2)
.setEditorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.build()))));
new LocalGroupLogEntry(log2.getGroup(), new DecryptedGroupChange.Builder()
.revision(2)
.editorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.build()))));
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
}
@@ -487,25 +485,25 @@ public final class GroupStateMapperTest {
}
private static DecryptedGroup state(int revision) {
return DecryptedGroup.newBuilder()
.setRevision(revision)
.setTitle("Group Revision " + revision)
.build();
return new DecryptedGroup.Builder()
.revision(revision)
.title("Group Revision " + revision)
.build();
}
private static DecryptedGroupChange change(int revision) {
return DecryptedGroupChange.newBuilder()
.setRevision(revision)
.setEditorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + revision))
.build();
return new DecryptedGroupChange.Builder()
.revision(revision)
.editorServiceIdBytes(UuidUtil.toByteString(KNOWN_EDITOR))
.newTitle(new DecryptedString.Builder().value_("Group Revision " + revision).build())
.build();
}
private static DecryptedGroupChange changeNoEditor(int revision) {
return DecryptedGroupChange.newBuilder()
.setRevision(revision)
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + revision))
.build();
return new DecryptedGroupChange.Builder()
.revision(revision)
.newTitle(new DecryptedString.Builder().value_("Group Revision " + revision).build())
.build();
}
private static LocalGroupLogEntry asLocal(ServerGroupLogEntry logEntry) {

View File

@@ -1,17 +1,13 @@
package org.thoughtcrime.securesms.groups.v2.processing
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.both
import org.hamcrest.Matchers.hasItem
import org.hamcrest.Matchers.hasProperty
import org.hamcrest.Matchers.`is`
import org.hamcrest.Matchers.notNullValue
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -26,7 +22,6 @@ import org.signal.libsignal.zkgroup.groups.GroupMasterKey
import org.signal.storageservice.protos.groups.local.DecryptedGroup
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.signal.storageservice.protos.groups.local.DecryptedTimer
import org.thoughtcrime.securesms.SignalStoreRule
import org.thoughtcrime.securesms.database.GroupStateTestData
@@ -91,7 +86,7 @@ class GroupsV2StateProcessorTest {
mockkStatic(ApplicationDependencies::class)
every { ApplicationDependencies.getJobManager() } returns jobManager
processor = GroupsV2StateProcessor.StateProcessorForGroup(serviceIds, ApplicationProvider.getApplicationContext(), groupTable, groupsV2API, groupsV2Authorization, masterKey, profileAndMessageHelper)
processor = GroupsV2StateProcessor.StateProcessorForGroup(serviceIds, groupTable, groupsV2API, groupsV2Authorization, masterKey, profileAndMessageHelper)
}
@After
@@ -246,18 +241,18 @@ class GroupsV2StateProcessorTest {
given {
localState(
revision = 5,
disappearingMessageTimer = DecryptedTimer.newBuilder().setDuration(1000).build()
disappearingMessageTimer = DecryptedTimer.Builder().duration(1000).build()
)
}
val signedChange = DecryptedGroupChange.newBuilder().apply {
val signedChange = DecryptedGroupChange.Builder().apply {
revision = 6
setNewTimer(DecryptedTimer.newBuilder().setDuration(5000))
newTimer(DecryptedTimer.Builder().duration(5000).build())
}
val result = processor.updateLocalGroupToRevision(6, 0, signedChange.build())
assertThat("revision matches peer change", result.latestServer!!.revision, `is`(6))
assertThat("timer changed by peer change", result.latestServer!!.disappearingMessagesTimer.duration, `is`(5000))
assertThat("timer changed by peer change", result.latestServer!!.disappearingMessagesTimer!!.duration, `is`(5000))
}
@Test
@@ -277,7 +272,7 @@ class GroupsV2StateProcessorTest {
apiCallParameters(2, true)
}
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange.getDefaultInstance())
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange())
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
assertThat("revision matches server", result.latestServer!!.revision, `is`(2))
}
@@ -306,7 +301,7 @@ class GroupsV2StateProcessorTest {
every { groupTable.isUnknownGroup(any<GroupId>()) } returns true
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange.getDefaultInstance())
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange())
assertThat("local should update to revision added", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
assertThat("revision matches peer revision added", result.latestServer!!.revision, `is`(2))
@@ -351,7 +346,7 @@ class GroupsV2StateProcessorTest {
changeLog(3) {
fullSnapshot(serverState)
change {
addNewMembers(member(selfAci, joinedAt = 3))
newMembers += member(selfAci, joinedAt = 3)
}
}
}
@@ -381,7 +376,7 @@ class GroupsV2StateProcessorTest {
changeLog(3) {
fullSnapshot(extendGroup = serverState, title = "Beam me up")
change {
addNewMembers(member(selfAci, joinedAt = 3))
newMembers += member(selfAci, joinedAt = 3)
}
}
changeLog(4) {
@@ -423,13 +418,13 @@ class GroupsV2StateProcessorTest {
changeSet {
changeLog(100) {
change {
addNewMembers(member(selfAci, joinedAt = 100))
newMembers += member(selfAci, joinedAt = 100)
}
}
changeLog(101) {
change {
addDeleteMembers(randomMembers[1].aciBytes)
addModifiedProfileKeys(randomMembers[0])
deleteMembers += randomMembers[1].aciBytes
modifiedProfileKeys += randomMembers[0]
}
}
}
@@ -444,13 +439,13 @@ class GroupsV2StateProcessorTest {
members = selfAndOthers + randomMembers[0] + randomMembers[1]
)
change {
addNewMembers(member(selfAci, joinedAt = 100))
newMembers += member(selfAci, joinedAt = 100)
}
}
changeLog(101) {
change {
addDeleteMembers(randomMembers[1].aciBytes)
addModifiedProfileKeys(randomMembers[0])
deleteMembers += randomMembers[1].aciBytes
modifiedProfileKeys += randomMembers[0]
}
}
}
@@ -509,9 +504,9 @@ class GroupsV2StateProcessorTest {
val result = processor.updateLocalGroupToRevision(GroupsV2StateProcessor.LATEST, 0, null)
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
assertThat("members contains second other", result.latestServer!!.members, hasItem(secondOther))
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change!!.newMembers }, hasItem(hasItem(secondOther)))
}
/**
@@ -543,16 +538,10 @@ class GroupsV2StateProcessorTest {
val result = processor.forceSanityUpdateFromServer(0)
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
assertThat("members contains second other", result.latestServer!!.members, hasItem(secondOther))
assertThat("title should be updated", result.latestServer!!.title, `is`("Changed"))
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
assertThat(
"group update messages contains title change",
updateMessageContextArgs.map { it.change.newTitle },
hasItem(both<DecryptedString>(notNullValue()).and(hasProperty("value", `is`("Changed"))))
)
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change!!.newMembers }, hasItem(hasItem(secondOther)))
assertThat("group update messages contains title change", updateMessageContextArgs.mapNotNull { it.change!!.newTitle }.any { it.value_ == "Changed" })
}
/**

View File

@@ -1,14 +1,14 @@
package org.thoughtcrime.securesms.payments;
import com.google.protobuf.ByteString;
import org.junit.Before;
import org.junit.Test;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.internal.push.PaymentAddress;
import okio.ByteString;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertArrayEquals;
@@ -23,9 +23,9 @@ public final class MobileCoinPublicAddressProfileUtilTest {
@Test
public void can_verify_an_address() throws PaymentsAddressException {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
SignalServiceProtos.PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
byte[] paymentsAddress = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(signedPaymentAddress, identityKeyPair.getPublicKey());
@@ -34,85 +34,89 @@ public final class MobileCoinPublicAddressProfileUtilTest {
@Test
public void can_not_verify_an_address_with_the_wrong_key() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
IdentityKey wrongPublicKey = IdentityKeyUtil.generateIdentityKeyPair().getPublicKey();
byte[] address = Util.getSecretBytes(100);
SignalServiceProtos.PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
IdentityKey wrongPublicKey = IdentityKeyUtil.generateIdentityKeyPair().getPublicKey();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(signedPaymentAddress, wrongPublicKey))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_tampered_signature() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
SignalServiceProtos.PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
byte[] signature = signedPaymentAddress.getMobileCoinAddress().getSignature().toByteArray();
byte[] signature = signedPaymentAddress.mobileCoinAddress.signature.toByteArray();
signature[0] = (byte) (signature[0] ^ 0x01);
SignalServiceProtos.PaymentAddress tamperedSignature = signedPaymentAddress.toBuilder()
.setMobileCoinAddress(signedPaymentAddress.getMobileCoinAddress()
.toBuilder()
.setSignature(ByteString.copyFrom(signature)))
.build();
PaymentAddress tamperedSignature = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.signature(ByteString.of(signature))
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(tamperedSignature, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_tampered_address() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] addressBytes = Util.getSecretBytes(100);
SignalServiceProtos.PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(addressBytes, identityKeyPair);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] addressBytes = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(addressBytes, identityKeyPair);
byte[] address = signedPaymentAddress.getMobileCoinAddress().getAddress().toByteArray();
byte[] address = signedPaymentAddress.mobileCoinAddress.address.toByteArray();
address[0] = (byte) (address[0] ^ 0x01);
SignalServiceProtos.PaymentAddress tamperedAddress = signedPaymentAddress.toBuilder()
.setMobileCoinAddress(signedPaymentAddress.getMobileCoinAddress()
.toBuilder()
.setAddress(ByteString.copyFrom(address)))
.build();
PaymentAddress tamperedAddress = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.address(ByteString.of(address))
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(tamperedAddress, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_missing_signature() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
SignalServiceProtos.PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
SignalServiceProtos.PaymentAddress removedSignature = signedPaymentAddress.toBuilder()
.setMobileCoinAddress(signedPaymentAddress.getMobileCoinAddress()
.toBuilder()
.clearSignature())
.build();
PaymentAddress removedSignature = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.signature(null)
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(removedSignature, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_missing_address() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
SignalServiceProtos.PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
SignalServiceProtos.PaymentAddress removedAddress = signedPaymentAddress.toBuilder()
.setMobileCoinAddress(signedPaymentAddress.getMobileCoinAddress()
.toBuilder()
.clearAddress())
.build();
PaymentAddress removedAddress = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.address(null)
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(removedAddress, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
}

View File

@@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import com.google.protobuf.ByteString;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -26,6 +25,7 @@ import org.whispersystems.signalservice.api.util.Uint64Util;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -34,6 +34,8 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
import okio.ByteString;
import static org.junit.Assert.assertEquals;
public final class LedgerReconcileTest {
@@ -45,7 +47,7 @@ public final class LedgerReconcileTest {
@Test
public void empty_lists() {
List<Payment> payments = reconcile(Collections.emptyList(), new MobileCoinLedgerWrapper(MobileCoinLedger.getDefaultInstance()));
List<Payment> payments = reconcile(Collections.emptyList(), new MobileCoinLedgerWrapper(new MobileCoinLedger()));
assertEquals(Collections.emptyList(), payments);
}
@@ -232,16 +234,14 @@ public final class LedgerReconcileTest {
}
private MobileCoinLedger.Block block(long blockIndex) {
return MobileCoinLedger.Block.newBuilder()
.setBlockNumber(blockIndex)
.build();
return new MobileCoinLedger.Block.Builder()
.blockNumber(blockIndex)
.build();
}
private MobileCoinLedger ledger(MobileCoinLedger.OwnedTXO... txos) {
MobileCoinLedger.Builder builder = MobileCoinLedger.newBuilder();
for (MobileCoinLedger.OwnedTXO txo : txos) {
builder.addUnspentTxos(txo);
}
MobileCoinLedger.Builder builder = new MobileCoinLedger.Builder();
builder.unspentTxos(Arrays.asList(txos));
return builder.build();
}
@@ -250,19 +250,19 @@ public final class LedgerReconcileTest {
}
private MobileCoinLedger.OwnedTXO spentTxo(Money.MobileCoin mob, ByteString keyImage, ByteString publicKey, MobileCoinLedger.Block receivedBlock, MobileCoinLedger.Block spentBlock) {
return txo(mob, keyImage, publicKey, receivedBlock).setSpentInBlock(spentBlock).build();
return txo(mob, keyImage, publicKey, receivedBlock).spentInBlock(spentBlock).build();
}
private MobileCoinLedger.OwnedTXO.Builder txo(Money.MobileCoin mob, ByteString keyImage, ByteString publicKey, MobileCoinLedger.Block receivedBlock) {
if (mob.isNegative()) {
throw new AssertionError();
}
MobileCoinLedger.OwnedTXO.Builder builder = MobileCoinLedger.OwnedTXO.newBuilder()
.setReceivedInBlock(receivedBlock)
.setKeyImage(keyImage)
.setPublicKey(publicKey);
MobileCoinLedger.OwnedTXO.Builder builder = new MobileCoinLedger.OwnedTXO.Builder()
.receivedInBlock(receivedBlock)
.keyImage(keyImage)
.publicKey(publicKey);
try {
builder.setAmount(Uint64Util.bigIntegerToUInt64(mob.toPicoMobBigInteger()));
builder.amount(Uint64Util.bigIntegerToUInt64(mob.toPicoMobBigInteger()));
} catch (Uint64RangeException e) {
throw new AssertionError(e);
}
@@ -272,14 +272,14 @@ public final class LedgerReconcileTest {
private static Payment payment(String note, Money.MobileCoin valueAndDirection, Set<ByteString> keyImages, Set<ByteString> publicKeys) {
UUID uuid = UUID.randomUUID();
PaymentMetaData.MobileCoinTxoIdentification.Builder builderForValue = PaymentMetaData.MobileCoinTxoIdentification.newBuilder();
PaymentMetaData.MobileCoinTxoIdentification.Builder builderForValue = new PaymentMetaData.MobileCoinTxoIdentification.Builder();
builderForValue.addAllKeyImages(keyImages);
builderForValue.addAllPublicKey(publicKeys);
builderForValue.keyImages(new ArrayList<>(keyImages));
builderForValue.publicKey(new ArrayList<>(publicKeys));
PaymentMetaData paymentMetaData = PaymentMetaData.newBuilder()
.setMobileCoinTxoIdentification(builderForValue)
.build();
PaymentMetaData paymentMetaData = new PaymentMetaData.Builder()
.mobileCoinTxoIdentification(builderForValue.build())
.build();
return new Payment() {
@Override
@@ -375,7 +375,7 @@ public final class LedgerReconcileTest {
private static ByteString id(long id) {
byte[] bytes = ByteUtil.longToByteArray(id);
return ByteString.copyFrom(bytes);
return ByteString.of(bytes);
}
private static Money.MobileCoin mob(double value) {

View File

@@ -2,20 +2,19 @@ package org.thoughtcrime.securesms.sms;
import androidx.annotation.NonNull;
import com.google.protobuf.ByteString;
import org.junit.Test;
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 org.whispersystems.signalservice.internal.push.GroupContextV2;
import java.util.Random;
import java.util.UUID;
import okio.ByteString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -29,11 +28,10 @@ public class GroupV2UpdateMessageUtilTest {
.deleteMember(alice)
.build();
DecryptedGroupV2Context context = DecryptedGroupV2Context.newBuilder()
.setContext(SignalServiceProtos.GroupContextV2.newBuilder()
.setMasterKey(ByteString.copyFrom(randomBytes())))
.setChange(change)
.build();
DecryptedGroupV2Context context = new DecryptedGroupV2Context.Builder()
.context(new GroupContextV2.Builder().masterKey(ByteString.of(randomBytes())).build())
.change(change)
.build();
MessageGroupContext messageGroupContext = new MessageGroupContext(context);
@@ -53,11 +51,10 @@ public class GroupV2UpdateMessageUtilTest {
.deleteMember(bob)
.build();
DecryptedGroupV2Context context = DecryptedGroupV2Context.newBuilder()
.setContext(SignalServiceProtos.GroupContextV2.newBuilder()
.setMasterKey(ByteString.copyFrom(randomBytes())))
.setChange(change)
.build();
DecryptedGroupV2Context context = new DecryptedGroupV2Context.Builder()
.context(new GroupContextV2.Builder().masterKey(ByteString.of(randomBytes())).build())
.change(change)
.build();
MessageGroupContext messageGroupContext = new MessageGroupContext(context);
@@ -78,11 +75,10 @@ public class GroupV2UpdateMessageUtilTest {
.addMember(bob)
.build();
DecryptedGroupV2Context context = DecryptedGroupV2Context.newBuilder()
.setContext(SignalServiceProtos.GroupContextV2.newBuilder()
.setMasterKey(ByteString.copyFrom(randomBytes())))
.setChange(change)
.build();
DecryptedGroupV2Context context = new DecryptedGroupV2Context.Builder()
.context(new GroupContextV2.Builder().masterKey(ByteString.of(randomBytes())).build())
.change(change)
.build();
MessageGroupContext messageGroupContext = new MessageGroupContext(context);
@@ -101,11 +97,10 @@ public class GroupV2UpdateMessageUtilTest {
.denyRequest(alice)
.build();
DecryptedGroupV2Context context = DecryptedGroupV2Context.newBuilder()
.setContext(SignalServiceProtos.GroupContextV2.newBuilder()
.setMasterKey(ByteString.copyFrom(randomBytes())))
.setChange(change)
.build();
DecryptedGroupV2Context context = new DecryptedGroupV2Context.Builder()
.context(new GroupContextV2.Builder().masterKey(ByteString.of(randomBytes())).build())
.change(change)
.build();
MessageGroupContext messageGroupContext = new MessageGroupContext(context);
@@ -126,11 +121,10 @@ public class GroupV2UpdateMessageUtilTest {
.addMember(bob)
.build();
DecryptedGroupV2Context context = DecryptedGroupV2Context.newBuilder()
.setContext(SignalServiceProtos.GroupContextV2.newBuilder()
.setMasterKey(ByteString.copyFrom(randomBytes())))
.setChange(change)
.build();
DecryptedGroupV2Context context = new DecryptedGroupV2Context.Builder()
.context(new GroupContextV2.Builder().masterKey(ByteString.of(randomBytes())).build())
.change(change)
.build();
MessageGroupContext messageGroupContext = new MessageGroupContext(context);

View File

@@ -74,7 +74,7 @@ class StoryContextMenuTest {
val expected = "Hello"
val storyRecord = FakeMessageRecords.buildMediaMmsMessageRecord(
storyType = StoryType.TEXT_STORY_WITH_REPLIES,
body = Base64.encodeBytes(StoryTextPost.newBuilder().setBody(expected).build().toByteArray())
body = Base64.encodeBytes(StoryTextPost.Builder().body(expected).build().encode())
)
// WHEN
@@ -93,7 +93,7 @@ class StoryContextMenuTest {
val expected = "https://www.signal.org"
val storyRecord = FakeMessageRecords.buildMediaMmsMessageRecord(
storyType = StoryType.TEXT_STORY_WITH_REPLIES,
body = Base64.encodeBytes(StoryTextPost.newBuilder().build().toByteArray()),
body = Base64.encodeBytes(StoryTextPost.Builder().build().encode()),
linkPreviews = listOf(LinkPreview(expected, "", "", 0L, Optional.empty()))
)
@@ -115,7 +115,7 @@ class StoryContextMenuTest {
val expected = "$text $url"
val storyRecord = FakeMessageRecords.buildMediaMmsMessageRecord(
storyType = StoryType.TEXT_STORY_WITH_REPLIES,
body = Base64.encodeBytes(StoryTextPost.newBuilder().setBody(text).build().toByteArray()),
body = Base64.encodeBytes(StoryTextPost.Builder().body(text).build().encode()),
linkPreviews = listOf(LinkPreview(url, "", "", 0L, Optional.empty()))
)