mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-25 19:29:54 +01:00
Convert SignalService, Database, Group, Payment, and other remaining protos to wire.
This commit is contained in:
committed by
Alex Hart
parent
a6b7d0bcc5
commit
efbd5cab85
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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" })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()))
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user